Source code

Revision control

Copy as Markdown

Other Tools

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<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 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<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 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<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 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<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 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<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)
}
}