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 [`AttributesSubsection`]. /// /// Returned by [`SectionHeader::attributes`](super::SectionHeader::attributes) /// and [`SectionHeader::gnu_attributes`](super::SectionHeader::gnu_attributes). #[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 for the subsections in an [`AttributesSection`]. #[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 [`AttributesSection`]. /// /// A subsection is identified by a vendor name. It contains a series of /// [`AttributesSubsubsection`]. #[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 for the sub-subsections in an [`AttributesSubsection`]. #[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 [`AttributesSubsection`]. /// /// 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 an [`AttributesSubsubsection`]. #[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 an [`AttributesSubsubsection`]. /// /// 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) } }