summaryrefslogtreecommitdiffstats
path: root/vendor/object/src/read/elf/note.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/object/src/read/elf/note.rs')
-rw-r--r--vendor/object/src/read/elf/note.rs90
1 files changed, 84 insertions, 6 deletions
diff --git a/vendor/object/src/read/elf/note.rs b/vendor/object/src/read/elf/note.rs
index 34024dbb8..fc5aa7753 100644
--- a/vendor/object/src/read/elf/note.rs
+++ b/vendor/object/src/read/elf/note.rs
@@ -2,7 +2,7 @@ use core::fmt::Debug;
use core::mem;
use crate::elf;
-use crate::endian;
+use crate::endian::{self, U32};
use crate::pod::Pod;
use crate::read::util;
use crate::read::{self, Bytes, Error, ReadError};
@@ -24,12 +24,15 @@ impl<'data, Elf> NoteIterator<'data, Elf>
where
Elf: FileHeader,
{
+ /// An iterator over the notes in an ELF section or segment.
+ ///
+ /// `align` should be from the `p_align` field of the segment,
+ /// or the `sh_addralign` field of the section. Supported values are
+ /// either 4 or 8, but values less than 4 are treated as 4.
+ /// This matches the behaviour of binutils.
+ ///
/// Returns `Err` if `align` is invalid.
- pub(super) fn new(
- endian: Elf::Endian,
- align: Elf::Word,
- data: &'data [u8],
- ) -> read::Result<Self> {
+ pub fn new(endian: Elf::Endian, align: Elf::Word, data: &'data [u8]) -> read::Result<Self> {
let align = match align.into() {
0u64..=4 => 4,
8 => 8,
@@ -134,6 +137,24 @@ impl<'data, Elf: FileHeader> Note<'data, Elf> {
pub fn desc(&self) -> &'data [u8] {
self.desc
}
+
+ /// Return an iterator for properties if this note's type is `NT_GNU_PROPERTY_TYPE_0`.
+ pub fn gnu_properties(
+ &self,
+ endian: Elf::Endian,
+ ) -> Option<GnuPropertyIterator<'data, Elf::Endian>> {
+ if self.name() != elf::ELF_NOTE_GNU || self.n_type(endian) != elf::NT_GNU_PROPERTY_TYPE_0 {
+ return None;
+ }
+ // Use the ELF class instead of the section alignment.
+ // This matches what other parsers do.
+ let align = if Elf::is_type_64_sized() { 8 } else { 4 };
+ Some(GnuPropertyIterator {
+ endian,
+ align,
+ data: Bytes(self.desc),
+ })
+ }
}
/// A trait for generic access to `NoteHeader32` and `NoteHeader64`.
@@ -183,3 +204,60 @@ impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> {
self.n_type.get(endian)
}
}
+
+/// An iterator over the properties in a `NT_GNU_PROPERTY_TYPE_0` note.
+#[derive(Debug)]
+pub struct GnuPropertyIterator<'data, Endian: endian::Endian> {
+ endian: Endian,
+ align: usize,
+ data: Bytes<'data>,
+}
+
+impl<'data, Endian: endian::Endian> GnuPropertyIterator<'data, Endian> {
+ /// Returns the next property.
+ pub fn next(&mut self) -> read::Result<Option<GnuProperty<'data>>> {
+ let mut data = self.data;
+ if data.is_empty() {
+ return Ok(None);
+ }
+
+ (|| -> Result<_, ()> {
+ let pr_type = data.read_at::<U32<Endian>>(0)?.get(self.endian);
+ let pr_datasz = data.read_at::<U32<Endian>>(4)?.get(self.endian) as usize;
+ let pr_data = data.read_bytes_at(8, pr_datasz)?.0;
+ data.skip(util::align(8 + pr_datasz, self.align))?;
+ self.data = data;
+ Ok(Some(GnuProperty { pr_type, pr_data }))
+ })()
+ .read_error("Invalid ELF GNU property")
+ }
+}
+
+/// A property in a `NT_GNU_PROPERTY_TYPE_0` note.
+#[derive(Debug)]
+pub struct GnuProperty<'data> {
+ pr_type: u32,
+ pr_data: &'data [u8],
+}
+
+impl<'data> GnuProperty<'data> {
+ /// Return the property type.
+ ///
+ /// This is one of the `GNU_PROPERTY_*` constants.
+ pub fn pr_type(&self) -> u32 {
+ self.pr_type
+ }
+
+ /// Return the property data.
+ pub fn pr_data(&self) -> &'data [u8] {
+ self.pr_data
+ }
+
+ /// Parse the property data as an unsigned 32-bit integer.
+ pub fn data_u32<E: endian::Endian>(&self, endian: E) -> read::Result<u32> {
+ Bytes(self.pr_data)
+ .read_at::<U32<E>>(0)
+ .read_error("Invalid ELF GNU property data")
+ .map(|val| val.get(endian))
+ }
+}