308 lines
9.1 KiB
Rust
308 lines
9.1 KiB
Rust
|
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)
|
||
|
}
|
||
|
}
|