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