From 9835e2ae736235810b4ea1c162ca5e65c547e770 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 18 May 2024 04:49:50 +0200 Subject: Merging upstream version 1.71.1+dfsg1. Signed-off-by: Daniel Baumann --- vendor/object/src/read/elf/attributes.rs | 303 +++++++++++++++++++++++++++++++ vendor/object/src/read/elf/comdat.rs | 2 - vendor/object/src/read/elf/file.rs | 25 +++ vendor/object/src/read/elf/hash.rs | 4 +- vendor/object/src/read/elf/mod.rs | 3 + vendor/object/src/read/elf/note.rs | 90 ++++++++- vendor/object/src/read/elf/section.rs | 112 +++++++++--- vendor/object/src/read/elf/segment.rs | 1 - vendor/object/src/read/elf/symbol.rs | 5 +- vendor/object/src/read/elf/version.rs | 4 +- 10 files changed, 504 insertions(+), 45 deletions(-) create mode 100644 vendor/object/src/read/elf/attributes.rs (limited to 'vendor/object/src/read/elf') diff --git a/vendor/object/src/read/elf/attributes.rs b/vendor/object/src/read/elf/attributes.rs new file mode 100644 index 000000000..6ec535d72 --- /dev/null +++ b/vendor/object/src/read/elf/attributes.rs @@ -0,0 +1,303 @@ +use core::convert::TryInto; + +use crate::elf; +use crate::endian; +use crate::read::{Bytes, Error, ReadError, Result}; + +use super::FileHeader; + +/// An ELF attributes section. +/// +/// This may be a GNU attributes section, or an architecture specific attributes section. +/// +/// An attributes section contains a series of subsections. +#[derive(Debug, Clone)] +pub struct AttributesSection<'data, Elf: FileHeader> { + endian: Elf::Endian, + version: u8, + data: Bytes<'data>, +} + +impl<'data, Elf: FileHeader> AttributesSection<'data, Elf> { + /// Parse an ELF attributes section given the section data. + pub fn new(endian: Elf::Endian, data: &'data [u8]) -> Result { + let mut data = Bytes(data); + + // Skip the version field that is one byte long. + let version = *data + .read::() + .read_error("Invalid ELF attributes section offset or size")?; + + Ok(AttributesSection { + endian, + version, + data, + }) + } + + /// Return the version of the attributes section. + pub fn version(&self) -> u8 { + self.version + } + + /// Return an iterator over the subsections. + pub fn subsections(&self) -> Result> { + // There is currently only one format version. + if self.version != b'A' { + return Err(Error("Unsupported ELF attributes section version")); + } + + Ok(AttributesSubsectionIterator { + endian: self.endian, + data: self.data, + }) + } +} + +/// An iterator over the subsections in an ELF attributes section. +#[derive(Debug, Clone)] +pub struct AttributesSubsectionIterator<'data, Elf: FileHeader> { + endian: Elf::Endian, + data: Bytes<'data>, +} + +impl<'data, Elf: FileHeader> AttributesSubsectionIterator<'data, Elf> { + /// Return the next subsection. + pub fn next(&mut self) -> Result>> { + if self.data.is_empty() { + return Ok(None); + } + + let result = self.parse(); + if result.is_err() { + self.data = Bytes(&[]); + } + result + } + + fn parse(&mut self) -> Result>> { + // First read the subsection length. + let mut data = self.data; + let length = data + .read::>() + .read_error("ELF attributes section is too short")? + .get(self.endian); + + // Now read the entire subsection, updating self.data. + let mut data = self + .data + .read_bytes(length as usize) + .read_error("Invalid ELF attributes subsection length")?; + // Skip the subsection length field. + data.skip(4) + .read_error("Invalid ELF attributes subsection length")?; + + let vendor = data + .read_string() + .read_error("Invalid ELF attributes vendor")?; + + Ok(Some(AttributesSubsection { + endian: self.endian, + length, + vendor, + data, + })) + } +} + +/// A subsection in an ELF attributes section. +/// +/// A subsection is identified by a vendor name. It contains a series of sub-subsections. +#[derive(Debug, Clone)] +pub struct AttributesSubsection<'data, Elf: FileHeader> { + endian: Elf::Endian, + length: u32, + vendor: &'data [u8], + data: Bytes<'data>, +} + +impl<'data, Elf: FileHeader> AttributesSubsection<'data, Elf> { + /// Return the length of the attributes subsection. + pub fn length(&self) -> u32 { + self.length + } + + /// Return the vendor name of the attributes subsection. + pub fn vendor(&self) -> &'data [u8] { + self.vendor + } + + /// Return an iterator over the sub-subsections. + pub fn subsubsections(&self) -> AttributesSubsubsectionIterator<'data, Elf> { + AttributesSubsubsectionIterator { + endian: self.endian, + data: self.data, + } + } +} + +/// An iterator over the sub-subsections in an ELF attributes section. +#[derive(Debug, Clone)] +pub struct AttributesSubsubsectionIterator<'data, Elf: FileHeader> { + endian: Elf::Endian, + data: Bytes<'data>, +} + +impl<'data, Elf: FileHeader> AttributesSubsubsectionIterator<'data, Elf> { + /// Return the next sub-subsection. + pub fn next(&mut self) -> Result>> { + if self.data.is_empty() { + return Ok(None); + } + + let result = self.parse(); + if result.is_err() { + self.data = Bytes(&[]); + } + result + } + + fn parse(&mut self) -> Result>> { + // The format of a sub-section looks like this: + // + // * + // | * 0 * + // | * 0 * + let mut data = self.data; + let tag = *data + .read::() + .read_error("ELF attributes subsection is too short")?; + let length = data + .read::>() + .read_error("ELF attributes subsection is too short")? + .get(self.endian); + + // Now read the entire sub-subsection, updating self.data. + let mut data = self + .data + .read_bytes(length as usize) + .read_error("Invalid ELF attributes sub-subsection length")?; + // Skip the tag and sub-subsection size field. + data.skip(1 + 4) + .read_error("Invalid ELF attributes sub-subsection length")?; + + let indices = if tag == elf::Tag_Section || tag == elf::Tag_Symbol { + data.read_string() + .map(Bytes) + .read_error("Missing ELF attributes sub-subsection indices")? + } else if tag == elf::Tag_File { + Bytes(&[]) + } else { + return Err(Error("Unimplemented ELF attributes sub-subsection tag")); + }; + + Ok(Some(AttributesSubsubsection { + tag, + length, + indices, + data, + })) + } +} + +/// A sub-subsection in an ELF attributes section. +/// +/// A sub-subsection is identified by a tag. It contains an optional series of indices, +/// followed by a series of attributes. +#[derive(Debug, Clone)] +pub struct AttributesSubsubsection<'data> { + tag: u8, + length: u32, + indices: Bytes<'data>, + data: Bytes<'data>, +} + +impl<'data> AttributesSubsubsection<'data> { + /// Return the tag of the attributes sub-subsection. + pub fn tag(&self) -> u8 { + self.tag + } + + /// Return the length of the attributes sub-subsection. + pub fn length(&self) -> u32 { + self.length + } + + /// Return the data containing the indices. + pub fn indices_data(&self) -> &'data [u8] { + self.indices.0 + } + + /// Return the indices. + /// + /// This will be section indices if the tag is `Tag_Section`, + /// or symbol indices if the tag is `Tag_Symbol`, + /// and otherwise it will be empty. + pub fn indices(&self) -> AttributeIndexIterator<'data> { + AttributeIndexIterator { data: self.indices } + } + + /// Return the data containing the attributes. + pub fn attributes_data(&self) -> &'data [u8] { + self.data.0 + } + + /// Return a parser for the data containing the attributes. + pub fn attributes(&self) -> AttributeReader<'data> { + AttributeReader { data: self.data } + } +} + +/// An iterator over the indices in a sub-subsection in an ELF attributes section. +#[derive(Debug, Clone)] +pub struct AttributeIndexIterator<'data> { + data: Bytes<'data>, +} + +impl<'data> AttributeIndexIterator<'data> { + /// Parse the next index. + pub fn next(&mut self) -> Result> { + if self.data.is_empty() { + return Ok(None); + } + let err = "Invalid ELF attribute index"; + self.data + .read_uleb128() + .read_error(err)? + .try_into() + .map_err(|_| ()) + .read_error(err) + .map(Some) + } +} + +/// A parser for the attributes in a sub-subsection in an ELF attributes section. +/// +/// The parser relies on the caller to know the format of the data for each attribute tag. +#[derive(Debug, Clone)] +pub struct AttributeReader<'data> { + data: Bytes<'data>, +} + +impl<'data> AttributeReader<'data> { + /// Parse a tag. + pub fn read_tag(&mut self) -> Result> { + if self.data.is_empty() { + return Ok(None); + } + let err = "Invalid ELF attribute tag"; + self.data.read_uleb128().read_error(err).map(Some) + } + + /// Parse an integer value. + pub fn read_integer(&mut self) -> Result { + let err = "Invalid ELF attribute integer value"; + self.data.read_uleb128().read_error(err) + } + + /// Parse a string value. + pub fn read_string(&mut self) -> Result<&'data [u8]> { + let err = "Invalid ELF attribute string value"; + self.data.read_string().read_error(err) + } +} diff --git a/vendor/object/src/read/elf/comdat.rs b/vendor/object/src/read/elf/comdat.rs index 7cee85bb4..1a2f2f44a 100644 --- a/vendor/object/src/read/elf/comdat.rs +++ b/vendor/object/src/read/elf/comdat.rs @@ -18,7 +18,6 @@ pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> #[derive(Debug)] pub struct ElfComdatIterator<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { @@ -140,7 +139,6 @@ pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'dat #[derive(Debug)] pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { diff --git a/vendor/object/src/read/elf/file.rs b/vendor/object/src/read/elf/file.rs index 259da7906..aac66e7cc 100644 --- a/vendor/object/src/read/elf/file.rs +++ b/vendor/object/src/read/elf/file.rs @@ -456,6 +456,15 @@ pub trait FileHeader: Debug + Pod { /// This is a property of the type, not a value in the header data. fn is_type_64(&self) -> bool; + /// Return true if this type is a 64-bit header. + /// + /// This is a property of the type, not a value in the header data. + /// + /// This is the same as `is_type_64`, but is non-dispatchable. + fn is_type_64_sized() -> bool + where + Self: Sized; + fn e_ident(&self) -> &elf::Ident; fn e_type(&self, endian: Self::Endian) -> u16; fn e_machine(&self, endian: Self::Endian) -> u16; @@ -724,6 +733,14 @@ impl FileHeader for elf::FileHeader32 { false } + #[inline] + fn is_type_64_sized() -> bool + where + Self: Sized, + { + false + } + #[inline] fn e_ident(&self) -> &elf::Ident { &self.e_ident @@ -813,6 +830,14 @@ impl FileHeader for elf::FileHeader64 { true } + #[inline] + fn is_type_64_sized() -> bool + where + Self: Sized, + { + true + } + #[inline] fn e_ident(&self) -> &elf::Ident { &self.e_ident diff --git a/vendor/object/src/read/elf/hash.rs b/vendor/object/src/read/elf/hash.rs index aa1039ac1..aadbb9208 100644 --- a/vendor/object/src/read/elf/hash.rs +++ b/vendor/object/src/read/elf/hash.rs @@ -45,7 +45,7 @@ impl<'data, Elf: FileHeader> HashTable<'data, Elf> { endian: Elf::Endian, name: &[u8], hash: u32, - version: Option<&Version>, + version: Option<&Version<'_>>, symbols: &SymbolTable<'data, Elf, R>, versions: &VersionTable<'data, Elf>, ) -> Option<(usize, &'data Elf::Sym)> { @@ -160,7 +160,7 @@ impl<'data, Elf: FileHeader> GnuHashTable<'data, Elf> { endian: Elf::Endian, name: &[u8], hash: u32, - version: Option<&Version>, + version: Option<&Version<'_>>, symbols: &SymbolTable<'data, Elf, R>, versions: &VersionTable<'data, Elf>, ) -> Option<(usize, &'data Elf::Sym)> { diff --git a/vendor/object/src/read/elf/mod.rs b/vendor/object/src/read/elf/mod.rs index 5b7d7f9f7..07db6cd66 100644 --- a/vendor/object/src/read/elf/mod.rs +++ b/vendor/object/src/read/elf/mod.rs @@ -37,3 +37,6 @@ pub use hash::*; mod version; pub use version::*; + +mod attributes; +pub use attributes::*; diff --git a/vendor/object/src/read/elf/note.rs b/vendor/object/src/read/elf/note.rs index 34024dbb8..fc5aa7753 100644 --- a/vendor/object/src/read/elf/note.rs +++ b/vendor/object/src/read/elf/note.rs @@ -2,7 +2,7 @@ use core::fmt::Debug; use core::mem; use crate::elf; -use crate::endian; +use crate::endian::{self, U32}; use crate::pod::Pod; use crate::read::util; use crate::read::{self, Bytes, Error, ReadError}; @@ -24,12 +24,15 @@ impl<'data, Elf> NoteIterator<'data, Elf> where Elf: FileHeader, { + /// An iterator over the notes in an ELF section or segment. + /// + /// `align` should be from the `p_align` field of the segment, + /// or the `sh_addralign` field of the section. Supported values are + /// either 4 or 8, but values less than 4 are treated as 4. + /// This matches the behaviour of binutils. + /// /// Returns `Err` if `align` is invalid. - pub(super) fn new( - endian: Elf::Endian, - align: Elf::Word, - data: &'data [u8], - ) -> read::Result { + pub fn new(endian: Elf::Endian, align: Elf::Word, data: &'data [u8]) -> read::Result { let align = match align.into() { 0u64..=4 => 4, 8 => 8, @@ -134,6 +137,24 @@ impl<'data, Elf: FileHeader> Note<'data, Elf> { pub fn desc(&self) -> &'data [u8] { self.desc } + + /// Return an iterator for properties if this note's type is `NT_GNU_PROPERTY_TYPE_0`. + pub fn gnu_properties( + &self, + endian: Elf::Endian, + ) -> Option> { + if self.name() != elf::ELF_NOTE_GNU || self.n_type(endian) != elf::NT_GNU_PROPERTY_TYPE_0 { + return None; + } + // Use the ELF class instead of the section alignment. + // This matches what other parsers do. + let align = if Elf::is_type_64_sized() { 8 } else { 4 }; + Some(GnuPropertyIterator { + endian, + align, + data: Bytes(self.desc), + }) + } } /// A trait for generic access to `NoteHeader32` and `NoteHeader64`. @@ -183,3 +204,60 @@ impl NoteHeader for elf::NoteHeader64 { self.n_type.get(endian) } } + +/// An iterator over the properties in a `NT_GNU_PROPERTY_TYPE_0` note. +#[derive(Debug)] +pub struct GnuPropertyIterator<'data, Endian: endian::Endian> { + endian: Endian, + align: usize, + data: Bytes<'data>, +} + +impl<'data, Endian: endian::Endian> GnuPropertyIterator<'data, Endian> { + /// Returns the next property. + pub fn next(&mut self) -> read::Result>> { + let mut data = self.data; + if data.is_empty() { + return Ok(None); + } + + (|| -> Result<_, ()> { + let pr_type = data.read_at::>(0)?.get(self.endian); + let pr_datasz = data.read_at::>(4)?.get(self.endian) as usize; + let pr_data = data.read_bytes_at(8, pr_datasz)?.0; + data.skip(util::align(8 + pr_datasz, self.align))?; + self.data = data; + Ok(Some(GnuProperty { pr_type, pr_data })) + })() + .read_error("Invalid ELF GNU property") + } +} + +/// A property in a `NT_GNU_PROPERTY_TYPE_0` note. +#[derive(Debug)] +pub struct GnuProperty<'data> { + pr_type: u32, + pr_data: &'data [u8], +} + +impl<'data> GnuProperty<'data> { + /// Return the property type. + /// + /// This is one of the `GNU_PROPERTY_*` constants. + pub fn pr_type(&self) -> u32 { + self.pr_type + } + + /// Return the property data. + pub fn pr_data(&self) -> &'data [u8] { + self.pr_data + } + + /// Parse the property data as an unsigned 32-bit integer. + pub fn data_u32(&self, endian: E) -> read::Result { + Bytes(self.pr_data) + .read_at::>(0) + .read_error("Invalid ELF GNU property data") + .map(|val| val.get(endian)) + } +} diff --git a/vendor/object/src/read/elf/section.rs b/vendor/object/src/read/elf/section.rs index 3f8a08216..df08f9e3e 100644 --- a/vendor/object/src/read/elf/section.rs +++ b/vendor/object/src/read/elf/section.rs @@ -10,8 +10,9 @@ use crate::read::{ }; use super::{ - CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader, GnuHashTable, HashTable, - NoteIterator, RelocationSections, SymbolTable, VerdefIterator, VerneedIterator, VersionTable, + AttributesSection, CompressionHeader, ElfFile, ElfSectionRelocationIterator, FileHeader, + GnuHashTable, HashTable, NoteIterator, RelocationSections, SymbolTable, VerdefIterator, + VerneedIterator, VersionTable, }; /// The table of section headers in an ELF file. @@ -362,7 +363,6 @@ pub type ElfSection64<'data, 'file, Endian = Endianness, R = &'data [u8]> = #[derive(Debug)] pub struct ElfSection<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { @@ -380,32 +380,24 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSection<'data, 'file, fn maybe_compressed(&self) -> read::Result> { let endian = self.file.endian; - if (self.section.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 { - return Ok(None); - } - let (section_offset, section_size) = self - .section - .file_range(endian) - .read_error("Invalid ELF compressed section type")?; - let mut offset = section_offset; - let header = self - .file - .data - .read::(&mut offset) - .read_error("Invalid ELF compressed section offset")?; - if header.ch_type(endian) != elf::ELFCOMPRESS_ZLIB { - return Err(Error("Unsupported ELF compression type")); + if let Some((header, offset, compressed_size)) = + self.section.compression(endian, self.file.data)? + { + let format = match header.ch_type(endian) { + elf::ELFCOMPRESS_ZLIB => CompressionFormat::Zlib, + elf::ELFCOMPRESS_ZSTD => CompressionFormat::Zstandard, + _ => return Err(Error("Unsupported ELF compression type")), + }; + let uncompressed_size = header.ch_size(endian).into(); + Ok(Some(CompressedFileRange { + format, + offset, + compressed_size, + uncompressed_size, + })) + } else { + Ok(None) } - let uncompressed_size = header.ch_size(endian).into(); - let compressed_size = section_size - .checked_sub(offset - section_offset) - .read_error("Invalid ELF compressed section size")?; - Ok(Some(CompressedFileRange { - format: CompressionFormat::Zlib, - offset, - compressed_size, - uncompressed_size, - })) } /// Try GNU-style "ZLIB" header decompression. @@ -975,6 +967,70 @@ pub trait SectionHeader: Debug + Pod { let link = SectionIndex(self.sh_link(endian) as usize); Ok(Some((VerneedIterator::new(endian, verneed), link))) } + + /// Return the contents of a `SHT_GNU_ATTRIBUTES` section. + /// + /// Returns `Ok(None)` if the section type is not `SHT_GNU_ATTRIBUTES`. + /// Returns `Err` for invalid values. + fn gnu_attributes<'data, R: ReadRef<'data>>( + &self, + endian: Self::Endian, + data: R, + ) -> read::Result>> { + if self.sh_type(endian) != elf::SHT_GNU_ATTRIBUTES { + return Ok(None); + } + self.attributes(endian, data).map(Some) + } + + /// Parse the contents of the section as attributes. + /// + /// This function does not check whether section type corresponds + /// to a section that contains attributes. + /// + /// Returns `Err` for invalid values. + fn attributes<'data, R: ReadRef<'data>>( + &self, + endian: Self::Endian, + data: R, + ) -> read::Result> { + let data = self.data(endian, data)?; + AttributesSection::new(endian, data) + } + + /// Parse the compression header if present. + /// + /// Returns the header, and the offset and size of the compressed section data + /// in the file. + /// + /// Returns `Ok(None)` if the section flags do not have `SHF_COMPRESSED`. + /// Returns `Err` for invalid values. + fn compression<'data, R: ReadRef<'data>>( + &self, + endian: Self::Endian, + data: R, + ) -> read::Result< + Option<( + &'data ::CompressionHeader, + u64, + u64, + )>, + > { + if (self.sh_flags(endian).into() & u64::from(elf::SHF_COMPRESSED)) == 0 { + return Ok(None); + } + let (section_offset, section_size) = self + .file_range(endian) + .read_error("Invalid ELF compressed section type")?; + let mut offset = section_offset; + let header = data + .read::<::CompressionHeader>(&mut offset) + .read_error("Invalid ELF compressed section offset")?; + let compressed_size = section_size + .checked_sub(offset - section_offset) + .read_error("Invalid ELF compressed section size")?; + Ok(Some((header, offset, compressed_size))) + } } impl SectionHeader for elf::SectionHeader32 { diff --git a/vendor/object/src/read/elf/segment.rs b/vendor/object/src/read/elf/segment.rs index 445893c8d..3972731ec 100644 --- a/vendor/object/src/read/elf/segment.rs +++ b/vendor/object/src/read/elf/segment.rs @@ -57,7 +57,6 @@ pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> = #[derive(Debug)] pub struct ElfSegment<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { diff --git a/vendor/object/src/read/elf/symbol.rs b/vendor/object/src/read/elf/symbol.rs index 5d8d29f27..ac1095705 100644 --- a/vendor/object/src/read/elf/symbol.rs +++ b/vendor/object/src/read/elf/symbol.rs @@ -208,7 +208,6 @@ pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> = #[derive(Debug, Clone, Copy)] pub struct ElfSymbolTable<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { @@ -256,7 +255,6 @@ pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> /// An iterator over the symbols of an `ElfFile`. pub struct ElfSymbolIterator<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { @@ -302,7 +300,6 @@ pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> = #[derive(Debug, Clone, Copy)] pub struct ElfSymbol<'data, 'file, Elf, R = &'data [u8]> where - 'data: 'file, Elf: FileHeader, R: ReadRef<'data>, { @@ -430,7 +427,7 @@ impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data> } #[inline] - fn flags(&self) -> SymbolFlags { + fn flags(&self) -> SymbolFlags { SymbolFlags::Elf { st_info: self.symbol.st_info(), st_other: self.symbol.st_other(), diff --git a/vendor/object/src/read/elf/version.rs b/vendor/object/src/read/elf/version.rs index 6d80ba1e3..cc87bbef1 100644 --- a/vendor/object/src/read/elf/version.rs +++ b/vendor/object/src/read/elf/version.rs @@ -183,12 +183,12 @@ impl<'data, Elf: FileHeader> VersionTable<'data, Elf> { .map(Some) } - /// Return true if the given symbol index satisifies the requirements of `need`. + /// Return true if the given symbol index satisfies the requirements of `need`. /// /// Returns false for any error. /// /// Note: this function hasn't been fully tested and is likely to be incomplete. - pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version>) -> bool { + pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version<'_>>) -> bool { let version_index = self.version_index(endian, index); let def = match self.version(version_index) { Ok(def) => def, -- cgit v1.2.3