//! Functions for parsing DWARF debugging abbreviations. use alloc::collections::btree_map; use alloc::vec::Vec; use core::convert::TryFrom; use core::fmt::{self, Debug}; use core::iter::FromIterator; use core::ops::Deref; use crate::common::{DebugAbbrevOffset, Encoding, SectionId}; use crate::constants; use crate::endianity::Endianity; use crate::read::{EndianSlice, Error, Reader, Result, Section, UnitHeader}; /// The `DebugAbbrev` struct represents the abbreviations describing /// `DebuggingInformationEntry`s' attribute names and forms found in the /// `.debug_abbrev` section. #[derive(Debug, Default, Clone, Copy)] pub struct DebugAbbrev { debug_abbrev_section: R, } impl<'input, Endian> DebugAbbrev> where Endian: Endianity, { /// Construct a new `DebugAbbrev` instance from the data in the `.debug_abbrev` /// section. /// /// It is the caller's responsibility to read the `.debug_abbrev` section and /// present it as a `&[u8]` slice. That means using some ELF loader on /// Linux, a Mach-O loader on macOS, etc. /// /// ``` /// use gimli::{DebugAbbrev, LittleEndian}; /// /// # let buf = [0x00, 0x01, 0x02, 0x03]; /// # let read_debug_abbrev_section_somehow = || &buf; /// let debug_abbrev = DebugAbbrev::new(read_debug_abbrev_section_somehow(), LittleEndian); /// ``` pub fn new(debug_abbrev_section: &'input [u8], endian: Endian) -> Self { Self::from(EndianSlice::new(debug_abbrev_section, endian)) } } impl DebugAbbrev { /// Parse the abbreviations at the given `offset` within this /// `.debug_abbrev` section. /// /// The `offset` should generally be retrieved from a unit header. pub fn abbreviations( &self, debug_abbrev_offset: DebugAbbrevOffset, ) -> Result { let input = &mut self.debug_abbrev_section.clone(); input.skip(debug_abbrev_offset.0)?; Abbreviations::parse(input) } } impl DebugAbbrev { /// Create a `DebugAbbrev` section that references the data in `self`. /// /// This is useful when `R` implements `Reader` but `T` does not. /// /// ## Example Usage /// /// ```rust,no_run /// # let load_section = || unimplemented!(); /// // Read the DWARF section into a `Vec` with whatever object loader you're using. /// let owned_section: gimli::DebugAbbrev> = load_section(); /// // Create a reference to the DWARF section. /// let section = owned_section.borrow(|section| { /// gimli::EndianSlice::new(§ion, gimli::LittleEndian) /// }); /// ``` pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugAbbrev where F: FnMut(&'a T) -> R, { borrow(&self.debug_abbrev_section).into() } } impl Section for DebugAbbrev { fn id() -> SectionId { SectionId::DebugAbbrev } fn reader(&self) -> &R { &self.debug_abbrev_section } } impl From for DebugAbbrev { fn from(debug_abbrev_section: R) -> Self { DebugAbbrev { debug_abbrev_section, } } } /// A set of type abbreviations. /// /// Construct an `Abbreviations` instance with the /// [`abbreviations()`](struct.UnitHeader.html#method.abbreviations) /// method. #[derive(Debug, Default, Clone)] pub struct Abbreviations { vec: Vec, map: btree_map::BTreeMap, } impl Abbreviations { /// Construct a new, empty set of abbreviations. fn empty() -> Abbreviations { Abbreviations { vec: Vec::new(), map: btree_map::BTreeMap::new(), } } /// Insert an abbreviation into the set. /// /// Returns `Ok` if it is the first abbreviation in the set with its code, /// `Err` if the code is a duplicate and there already exists an /// abbreviation in the set with the given abbreviation's code. fn insert(&mut self, abbrev: Abbreviation) -> ::core::result::Result<(), ()> { let code_usize = abbrev.code as usize; if code_usize as u64 == abbrev.code { // Optimize for sequential abbreviation codes by storing them // in a Vec, as long as the map doesn't already contain them. // A potential further optimization would be to allow some // holes in the Vec, but there's no need for that yet. if code_usize - 1 < self.vec.len() { return Err(()); } else if code_usize - 1 == self.vec.len() { if !self.map.is_empty() && self.map.contains_key(&abbrev.code) { return Err(()); } else { self.vec.push(abbrev); return Ok(()); } } } match self.map.entry(abbrev.code) { btree_map::Entry::Occupied(_) => Err(()), btree_map::Entry::Vacant(entry) => { entry.insert(abbrev); Ok(()) } } } /// Get the abbreviation associated with the given code. #[inline] pub fn get(&self, code: u64) -> Option<&Abbreviation> { if let Ok(code) = usize::try_from(code) { let index = code.checked_sub(1)?; if index < self.vec.len() { return Some(&self.vec[index]); } } self.map.get(&code) } /// Parse a series of abbreviations, terminated by a null abbreviation. fn parse(input: &mut R) -> Result { let mut abbrevs = Abbreviations::empty(); while let Some(abbrev) = Abbreviation::parse(input)? { if abbrevs.insert(abbrev).is_err() { return Err(Error::DuplicateAbbreviationCode); } } Ok(abbrevs) } } /// An abbreviation describes the shape of a `DebuggingInformationEntry`'s type: /// its code, tag type, whether it has children, and its set of attributes. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Abbreviation { code: u64, tag: constants::DwTag, has_children: constants::DwChildren, attributes: Attributes, } impl Abbreviation { /// Construct a new `Abbreviation`. /// /// ### Panics /// /// Panics if `code` is `0`. pub(crate) fn new( code: u64, tag: constants::DwTag, has_children: constants::DwChildren, attributes: Attributes, ) -> Abbreviation { assert_ne!(code, 0); Abbreviation { code, tag, has_children, attributes, } } /// Get this abbreviation's code. #[inline] pub fn code(&self) -> u64 { self.code } /// Get this abbreviation's tag. #[inline] pub fn tag(&self) -> constants::DwTag { self.tag } /// Return true if this abbreviation's type has children, false otherwise. #[inline] pub fn has_children(&self) -> bool { self.has_children == constants::DW_CHILDREN_yes } /// Get this abbreviation's attributes. #[inline] pub fn attributes(&self) -> &[AttributeSpecification] { &self.attributes[..] } /// Parse an abbreviation's tag. fn parse_tag(input: &mut R) -> Result { let val = input.read_uleb128_u16()?; if val == 0 { Err(Error::AbbreviationTagZero) } else { Ok(constants::DwTag(val)) } } /// Parse an abbreviation's "does the type have children?" byte. fn parse_has_children(input: &mut R) -> Result { let val = input.read_u8()?; let val = constants::DwChildren(val); if val == constants::DW_CHILDREN_no || val == constants::DW_CHILDREN_yes { Ok(val) } else { Err(Error::BadHasChildren) } } /// Parse a series of attribute specifications, terminated by a null attribute /// specification. fn parse_attributes(input: &mut R) -> Result { let mut attrs = Attributes::new(); while let Some(attr) = AttributeSpecification::parse(input)? { attrs.push(attr); } Ok(attrs) } /// Parse an abbreviation. Return `None` for the null abbreviation, `Some` /// for an actual abbreviation. fn parse(input: &mut R) -> Result> { let code = input.read_uleb128()?; if code == 0 { return Ok(None); } let tag = Self::parse_tag(input)?; let has_children = Self::parse_has_children(input)?; let attributes = Self::parse_attributes(input)?; let abbrev = Abbreviation::new(code, tag, has_children, attributes); Ok(Some(abbrev)) } } /// A list of attributes found in an `Abbreviation` #[derive(Clone)] pub(crate) enum Attributes { Inline { buf: [AttributeSpecification; MAX_ATTRIBUTES_INLINE], len: usize, }, Heap(Vec), } // Length of 5 based on benchmark results for both x86-64 and i686. const MAX_ATTRIBUTES_INLINE: usize = 5; impl Attributes { /// Returns a new empty list of attributes fn new() -> Attributes { let default = AttributeSpecification::new(constants::DW_AT_null, constants::DW_FORM_null, None); Attributes::Inline { buf: [default; 5], len: 0, } } /// Pushes a new value onto this list of attributes. fn push(&mut self, attr: AttributeSpecification) { match self { Attributes::Heap(list) => return list.push(attr), Attributes::Inline { buf, len: MAX_ATTRIBUTES_INLINE, } => { let mut list = buf.to_vec(); list.push(attr); *self = Attributes::Heap(list); } Attributes::Inline { buf, len } => { buf[*len] = attr; *len += 1; } } } } impl Debug for Attributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (&**self).fmt(f) } } impl PartialEq for Attributes { fn eq(&self, other: &Attributes) -> bool { &**self == &**other } } impl Eq for Attributes {} impl Deref for Attributes { type Target = [AttributeSpecification]; fn deref(&self) -> &[AttributeSpecification] { match self { Attributes::Inline { buf, len } => &buf[..*len], Attributes::Heap(list) => list, } } } impl FromIterator for Attributes { fn from_iter(iter: I) -> Attributes where I: IntoIterator, { let mut list = Attributes::new(); for item in iter { list.push(item); } return list; } } impl From> for Attributes { fn from(list: Vec) -> Attributes { Attributes::Heap(list) } } /// The description of an attribute in an abbreviated type. It is a pair of name /// and form. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct AttributeSpecification { name: constants::DwAt, form: constants::DwForm, implicit_const_value: i64, } impl AttributeSpecification { /// Construct a new `AttributeSpecification` from the given name and form /// and implicit const value. #[inline] pub fn new( name: constants::DwAt, form: constants::DwForm, implicit_const_value: Option, ) -> AttributeSpecification { debug_assert!( (form == constants::DW_FORM_implicit_const && implicit_const_value.is_some()) || (form != constants::DW_FORM_implicit_const && implicit_const_value.is_none()) ); AttributeSpecification { name, form, implicit_const_value: implicit_const_value.unwrap_or(0), } } /// Get the attribute's name. #[inline] pub fn name(&self) -> constants::DwAt { self.name } /// Get the attribute's form. #[inline] pub fn form(&self) -> constants::DwForm { self.form } /// Get the attribute's implicit const value. #[inline] pub fn implicit_const_value(&self) -> Option { if self.form == constants::DW_FORM_implicit_const { Some(self.implicit_const_value) } else { None } } /// Return the size of the attribute, in bytes. /// /// Note that because some attributes are variably sized, the size cannot /// always be known without parsing, in which case we return `None`. pub fn size(&self, header: &UnitHeader) -> Option { get_attribute_size(self.form, header.encoding()).map(usize::from) } /// Parse an attribute's form. fn parse_form(input: &mut R) -> Result { let val = input.read_uleb128_u16()?; if val == 0 { Err(Error::AttributeFormZero) } else { Ok(constants::DwForm(val)) } } /// Parse an attribute specification. Returns `None` for the null attribute /// specification, `Some` for an actual attribute specification. fn parse(input: &mut R) -> Result> { let name = input.read_uleb128_u16()?; if name == 0 { // Parse the null attribute specification. let form = input.read_uleb128_u16()?; return if form == 0 { Ok(None) } else { Err(Error::ExpectedZero) }; } let name = constants::DwAt(name); let form = Self::parse_form(input)?; let implicit_const_value = if form == constants::DW_FORM_implicit_const { Some(input.read_sleb128()?) } else { None }; let spec = AttributeSpecification::new(name, form, implicit_const_value); Ok(Some(spec)) } } #[inline] pub(crate) fn get_attribute_size(form: constants::DwForm, encoding: Encoding) -> Option { match form { constants::DW_FORM_addr => Some(encoding.address_size), constants::DW_FORM_implicit_const | constants::DW_FORM_flag_present => Some(0), constants::DW_FORM_data1 | constants::DW_FORM_flag | constants::DW_FORM_strx1 | constants::DW_FORM_ref1 | constants::DW_FORM_addrx1 => Some(1), constants::DW_FORM_data2 | constants::DW_FORM_ref2 | constants::DW_FORM_addrx2 | constants::DW_FORM_strx2 => Some(2), constants::DW_FORM_addrx3 | constants::DW_FORM_strx3 => Some(3), constants::DW_FORM_data4 | constants::DW_FORM_ref_sup4 | constants::DW_FORM_ref4 | constants::DW_FORM_strx4 | constants::DW_FORM_addrx4 => Some(4), constants::DW_FORM_data8 | constants::DW_FORM_ref8 | constants::DW_FORM_ref_sig8 | constants::DW_FORM_ref_sup8 => Some(8), constants::DW_FORM_data16 => Some(16), constants::DW_FORM_sec_offset | constants::DW_FORM_GNU_ref_alt | constants::DW_FORM_strp | constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt | constants::DW_FORM_line_strp => Some(encoding.format.word_size()), constants::DW_FORM_ref_addr => { // This is an offset, but DWARF version 2 specifies that DW_FORM_ref_addr // has the same size as an address on the target system. This was changed // in DWARF version 3. Some(if encoding.version == 2 { encoding.address_size } else { encoding.format.word_size() }) } // Variably sized forms. constants::DW_FORM_block | constants::DW_FORM_block1 | constants::DW_FORM_block2 | constants::DW_FORM_block4 | constants::DW_FORM_exprloc | constants::DW_FORM_ref_udata | constants::DW_FORM_string | constants::DW_FORM_sdata | constants::DW_FORM_udata | constants::DW_FORM_indirect | // We don't know the size of unknown forms. _ => None, } } #[cfg(test)] pub mod tests { use super::*; use crate::constants; use crate::endianity::LittleEndian; use crate::read::{EndianSlice, Error}; use crate::test_util::GimliSectionMethods; #[cfg(target_pointer_width = "32")] use core::u32; use test_assembler::Section; pub trait AbbrevSectionMethods { fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self; fn abbrev_null(self) -> Self; fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self; fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self; fn abbrev_attr_null(self) -> Self; } impl AbbrevSectionMethods for Section { fn abbrev(self, code: u64, tag: constants::DwTag, children: constants::DwChildren) -> Self { self.uleb(code).uleb(tag.0.into()).D8(children.0) } fn abbrev_null(self) -> Self { self.D8(0) } fn abbrev_attr(self, name: constants::DwAt, form: constants::DwForm) -> Self { self.uleb(name.0.into()).uleb(form.0.into()) } fn abbrev_attr_implicit_const(self, name: constants::DwAt, value: i64) -> Self { self.uleb(name.0.into()) .uleb(constants::DW_FORM_implicit_const.0.into()) .sleb(value) } fn abbrev_attr_null(self) -> Self { self.D8(0).D8(0) } } #[test] fn test_debug_abbrev_ok() { let extra_start = [1, 2, 3, 4]; let expected_rest = [5, 6, 7, 8]; #[rustfmt::skip] let buf = Section::new() .append_bytes(&extra_start) .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let abbrev1 = Abbreviation::new( 1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new( constants::DW_AT_producer, constants::DW_FORM_strp, None, ), AttributeSpecification::new( constants::DW_AT_language, constants::DW_FORM_data2, None, ), ] .into(), ); let abbrev2 = Abbreviation::new( 2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )] .into(), ); let debug_abbrev = DebugAbbrev::new(&buf, LittleEndian); let debug_abbrev_offset = DebugAbbrevOffset(extra_start.len()); let abbrevs = debug_abbrev .abbreviations(debug_abbrev_offset) .expect("Should parse abbreviations"); assert_eq!(abbrevs.get(1), Some(&abbrev1)); assert_eq!(abbrevs.get(2), Some(&abbrev2)); } #[test] fn test_abbreviations_insert() { fn abbrev(code: u16) -> Abbreviation { Abbreviation::new( code.into(), constants::DwTag(code), constants::DW_CHILDREN_no, vec![].into(), ) } fn assert_abbrev(abbrevs: &Abbreviations, code: u16) { let abbrev = abbrevs.get(code.into()).unwrap(); assert_eq!(abbrev.tag(), constants::DwTag(code)); } // Sequential insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.vec.len(), 2); assert!(abbrevs.map.is_empty()); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, 2); // Out of order insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); abbrevs.insert(abbrev(3)).unwrap(); assert!(abbrevs.vec.is_empty()); assert_abbrev(&abbrevs, 2); assert_abbrev(&abbrevs, 3); // Mixed order insert. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(3)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.vec.len(), 2); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, 2); assert_abbrev(&abbrevs, 3); // Duplicate code in vec. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.insert(abbrev(1)), Err(())); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // Duplicate code in map when adding to map. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // Duplicate code in map when adding to vec. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); abbrevs.insert(abbrev(1)).unwrap(); assert_eq!(abbrevs.insert(abbrev(2)), Err(())); // 32-bit usize conversions. let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(2)).unwrap(); } #[test] #[cfg(target_pointer_width = "32")] fn test_abbreviations_insert_32() { fn abbrev(code: u64) -> Abbreviation { Abbreviation::new( code, constants::DwTag(code as u16), constants::DW_CHILDREN_no, vec![].into(), ) } fn assert_abbrev(abbrevs: &Abbreviations, code: u64) { let abbrev = abbrevs.get(code).unwrap(); assert_eq!(abbrev.tag(), constants::DwTag(code as u16)); } let mut abbrevs = Abbreviations::empty(); abbrevs.insert(abbrev(1)).unwrap(); let wrap_code = (u32::MAX as u64 + 1) + 1; // `get` should not treat the wrapped code as `1`. assert_eq!(abbrevs.get(wrap_code), None); // `insert` should not treat the wrapped code as `1`. abbrevs.insert(abbrev(wrap_code)).unwrap(); assert_abbrev(&abbrevs, 1); assert_abbrev(&abbrevs, wrap_code); } #[test] fn test_parse_abbreviations_ok() { let expected_rest = [1, 2, 3, 4]; #[rustfmt::skip] let buf = Section::new() .abbrev(2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let abbrev1 = Abbreviation::new( 1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes, vec![ AttributeSpecification::new( constants::DW_AT_producer, constants::DW_FORM_strp, None, ), AttributeSpecification::new( constants::DW_AT_language, constants::DW_FORM_data2, None, ), ] .into(), ); let abbrev2 = Abbreviation::new( 2, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )] .into(), ); let abbrevs = Abbreviations::parse(rest).expect("Should parse abbreviations"); assert_eq!(abbrevs.get(1), Some(&abbrev1)); assert_eq!(abbrevs.get(2), Some(&abbrev2)); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviations_duplicate() { let expected_rest = [1, 2, 3, 4]; #[rustfmt::skip] let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .abbrev(1, constants::DW_TAG_compile_unit, constants::DW_CHILDREN_yes) .abbrev_attr(constants::DW_AT_producer, constants::DW_FORM_strp) .abbrev_attr(constants::DW_AT_language, constants::DW_FORM_data2) .abbrev_attr_null() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let buf = &mut EndianSlice::new(&*buf, LittleEndian); match Abbreviations::parse(buf) { Err(Error::DuplicateAbbreviationCode) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_tag_ok() { let buf = [0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let tag = Abbreviation::parse_tag(rest).expect("Should parse tag"); assert_eq!(tag, constants::DW_TAG_array_type); assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); } #[test] fn test_parse_abbreviation_tag_zero() { let buf = [0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match Abbreviation::parse_tag(buf) { Err(Error::AbbreviationTagZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_has_children() { let buf = [0x00, 0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); assert_eq!(val, constants::DW_CHILDREN_no); let val = Abbreviation::parse_has_children(rest).expect("Should parse children"); assert_eq!(val, constants::DW_CHILDREN_yes); match Abbreviation::parse_has_children(rest) { Err(Error::BadHasChildren) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_abbreviation_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_string) .abbrev_attr_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let expect = Some(Abbreviation::new( 1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_string, None, )] .into(), )); let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); assert_eq!(abbrev, expect); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviation_implicit_const_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr_implicit_const(constants::DW_AT_name, -42) .abbrev_attr_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let expect = Some(Abbreviation::new( 1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no, vec![AttributeSpecification::new( constants::DW_AT_name, constants::DW_FORM_implicit_const, Some(-42), )] .into(), )); let abbrev = Abbreviation::parse(rest).expect("Should parse abbreviation"); assert_eq!(abbrev, expect); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_abbreviation_implicit_const_no_const() { let buf = Section::new() .abbrev(1, constants::DW_TAG_subprogram, constants::DW_CHILDREN_no) .abbrev_attr(constants::DW_AT_name, constants::DW_FORM_implicit_const) .get_contents() .unwrap(); let buf = &mut EndianSlice::new(&*buf, LittleEndian); match Abbreviation::parse(buf) { Err(Error::UnexpectedEof(_)) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), } } #[test] fn test_parse_null_abbreviation_ok() { let expected_rest = [0x01, 0x02, 0x03, 0x04]; let buf = Section::new() .abbrev_null() .append_bytes(&expected_rest) .get_contents() .unwrap(); let rest = &mut EndianSlice::new(&*buf, LittleEndian); let abbrev = Abbreviation::parse(rest).expect("Should parse null abbreviation"); assert!(abbrev.is_none()); assert_eq!(*rest, EndianSlice::new(&expected_rest, LittleEndian)); } #[test] fn test_parse_attribute_form_ok() { let buf = [0x01, 0x02]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let tag = AttributeSpecification::parse_form(rest).expect("Should parse form"); assert_eq!(tag, constants::DW_FORM_addr); assert_eq!(*rest, EndianSlice::new(&buf[1..], LittleEndian)); } #[test] fn test_parse_attribute_form_zero() { let buf = [0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse_form(buf) { Err(Error::AttributeFormZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_null_attribute_specification_ok() { let buf = [0x00, 0x00, 0x01]; let rest = &mut EndianSlice::new(&buf, LittleEndian); let attr = AttributeSpecification::parse(rest).expect("Should parse null attribute specification"); assert!(attr.is_none()); assert_eq!(*rest, EndianSlice::new(&buf[2..], LittleEndian)); } #[test] fn test_parse_attribute_specifications_name_zero() { let buf = [0x00, 0x01, 0x00, 0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse(buf) { Err(Error::ExpectedZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_parse_attribute_specifications_form_zero() { let buf = [0x01, 0x00, 0x00, 0x00]; let buf = &mut EndianSlice::new(&buf, LittleEndian); match AttributeSpecification::parse(buf) { Err(Error::AttributeFormZero) => {} otherwise => panic!("Unexpected result: {:?}", otherwise), }; } #[test] fn test_get_abbrev_zero() { let mut abbrevs = Abbreviations::empty(); abbrevs .insert(Abbreviation::new( 1, constants::DwTag(1), constants::DW_CHILDREN_no, vec![].into(), )) .unwrap(); assert!(abbrevs.get(0).is_none()); } }