Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
307
vendor/object/src/read/elf/attributes.rs
vendored
Normal file
307
vendor/object/src/read/elf/attributes.rs
vendored
Normal file
@ -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)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user