aboutsummaryrefslogtreecommitdiff
path: root/vendor/object/src/read/elf/attributes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/read/elf/attributes.rs')
-rw-r--r--vendor/object/src/read/elf/attributes.rs307
1 files changed, 307 insertions, 0 deletions
diff --git a/vendor/object/src/read/elf/attributes.rs b/vendor/object/src/read/elf/attributes.rs
new file mode 100644
index 0000000..bf6f35c
--- /dev/null
+++ b/vendor/object/src/read/elf/attributes.rs
@@ -0,0 +1,307 @@
+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<Self> {
+ let mut data = Bytes(data);
+
+ // Skip the version field that is one byte long.
+ let version = *data
+ .read::<u8>()
+ .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<AttributesSubsectionIterator<'data, Elf>> {
+ // 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<Option<AttributesSubsection<'data, Elf>>> {
+ 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<Option<AttributesSubsection<'data, Elf>>> {
+ // First read the subsection length.
+ let mut data = self.data;
+ let length = data
+ .read::<endian::U32Bytes<Elf::Endian>>()
+ .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<Option<AttributesSubsubsection<'data>>> {
+ 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<Option<AttributesSubsubsection<'data>>> {
+ // The format of a sub-section looks like this:
+ //
+ // <file-tag> <size> <attribute>*
+ // | <section-tag> <size> <section-number>* 0 <attribute>*
+ // | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
+ let mut data = self.data;
+ let tag = *data
+ .read::<u8>()
+ .read_error("ELF attributes subsection is too short")?;
+ let length = data
+ .read::<endian::U32Bytes<Elf::Endian>>()
+ .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<Option<u32>> {
+ 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<Option<u64>> {
+ 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<u64> {
+ 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)
+ }
+}