summaryrefslogtreecommitdiffstats
path: root/third_party/rust/goblin/src/elf/note.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/goblin/src/elf/note.rs')
-rw-r--r--third_party/rust/goblin/src/elf/note.rs305
1 files changed, 305 insertions, 0 deletions
diff --git a/third_party/rust/goblin/src/elf/note.rs b/third_party/rust/goblin/src/elf/note.rs
new file mode 100644
index 0000000000..5ec1d47340
--- /dev/null
+++ b/third_party/rust/goblin/src/elf/note.rs
@@ -0,0 +1,305 @@
+// Defined note types for GNU systems.
+
+#[cfg(feature = "log")]
+use log::debug;
+#[cfg(feature = "alloc")]
+use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
+
+/// ABI information.
+///
+/// The descriptor consists of words:
+/// * word 0: OS descriptor
+/// * word 1: major version of the ABI
+/// * word 2: minor version of the ABI
+/// * word 3: subminor version of the ABI
+pub const NT_GNU_ABI_TAG: u32 = 1;
+
+/// Old name
+pub const ELF_NOTE_ABI: u32 = NT_GNU_ABI_TAG;
+// Known OSes. These values can appear in word 0 of an
+// `NT_GNU_ABI_TAG` note section entry.
+pub const ELF_NOTE_OS_LINUX: u32 = 0;
+pub const ELF_NOTE_OS_GNU: u32 = 1;
+pub const ELF_NOTE_OS_SOLARIS2: u32 = 2;
+pub const ELF_NOTE_OS_FREEBSD: u32 = 3;
+
+/// Synthetic `hwcap` information.
+///
+/// The descriptor begins with two words:
+/// * word 0: number of entries
+/// * word 1: bitmask of enabled entries
+///
+/// Then follow variable-length entries, one byte followed by a '\0'-terminated
+/// `hwcap` name string. The byte gives the bit number to test if enabled,
+/// `(1U << bit) & bitmask`.
+pub const NT_GNU_HWCAP: u32 = 2;
+
+/// Build ID bits as generated by ld --build-id.
+///
+/// The descriptor consists of any nonzero number of bytes.
+pub const NT_GNU_BUILD_ID: u32 = 3;
+
+/// Version note generated by GNU gold containing a version string.
+pub const NT_GNU_GOLD_VERSION: u32 = 4;
+
+///Contains copy of prstatus struct.
+pub const NT_PRSTATUS: u32 = 1;
+
+///Contains copy of prpsinfo struct.
+pub const NT_PRPSINFO: u32 = 3;
+
+///Fields of siginfo_t.
+pub const NT_SIGINFO: u32 = 0x5349_4749;
+
+///Description of mapped files.
+pub const NT_FILE: u32 = 0x4649_4c45;
+
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))]
+#[repr(C)]
+/// Note section contents. Each entry in the note section begins with a header
+/// of a fixed form.
+pub struct Nhdr32 {
+ /// Length of the note's name (includes the terminator)
+ pub n_namesz: u32,
+ /// Length of the note's descriptor
+ pub n_descsz: u32,
+ /// Type of the note
+ pub n_type: u32,
+}
+
+// Declare that this is a plain type.
+unsafe impl plain::Plain for Nhdr32 {}
+
+#[derive(Clone, Copy, Debug)]
+#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))]
+#[repr(C)]
+/// Note section contents. Each entry in the note section begins with a header
+/// of a fixed form.
+pub struct Nhdr64 {
+ /// Length of the note's name (includes the terminator)
+ pub n_namesz: u64,
+ /// Length of the note's descriptor.
+ pub n_descsz: u64,
+ /// Type of the note.
+ pub n_type: u64,
+}
+
+// Declare that this is a plain type.
+unsafe impl plain::Plain for Nhdr64 {}
+
+if_alloc! {
+ use crate::error;
+ use crate::container;
+ use scroll::ctx;
+ use alloc::vec::Vec;
+
+ /// An iterator over ELF binary notes in a note section or segment
+ pub struct NoteDataIterator<'a> {
+ pub data: &'a [u8],
+ pub size: usize,
+ pub offset: usize,
+ pub ctx: (usize, container::Ctx), // (alignment, ctx)
+ }
+
+ impl<'a> Iterator for NoteDataIterator<'a> {
+ type Item = error::Result<Note<'a>>;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.offset >= self.size {
+ None
+ } else {
+ debug!("NoteIterator - {:#x}", self.offset);
+ match self.data.gread_with(&mut self.offset, self.ctx) {
+ Ok(res) => Some(Ok(res)),
+ Err(e) => Some(Err(e))
+ }
+ }
+ }
+ }
+
+ /// An iterator over ELF binary notes
+ pub struct NoteIterator<'a> {
+ pub iters: Vec<NoteDataIterator<'a>>,
+ pub index: usize,
+ }
+
+ impl<'a> Iterator for NoteIterator<'a> {
+ type Item = error::Result<Note<'a>>;
+ fn next(&mut self) -> Option<Self::Item> {
+ while self.index < self.iters.len() {
+ if let Some(note_result) = self.iters[self.index].next() {
+ return Some(note_result);
+ }
+
+ self.index += 1;
+ }
+
+ None
+ }
+ }
+
+ #[derive(Debug)]
+ struct NoteHeader {
+ n_namesz: usize,
+ n_descsz: usize,
+ n_type: u32,
+ }
+
+ impl From<Nhdr32> for NoteHeader {
+ fn from(header: Nhdr32) -> Self {
+ NoteHeader {
+ n_namesz: header.n_namesz as usize,
+ n_descsz: header.n_descsz as usize,
+ n_type: header.n_type,
+ }
+ }
+ }
+
+ impl From<Nhdr64> for NoteHeader {
+ fn from(header: Nhdr64) -> Self {
+ NoteHeader {
+ n_namesz: header.n_namesz as usize,
+ n_descsz: header.n_descsz as usize,
+ n_type: header.n_type as u32,
+ }
+ }
+ }
+
+ fn align(alignment: usize, offset: &mut usize) {
+ let diff = *offset % alignment;
+ if diff != 0 {
+ *offset += alignment - diff;
+ }
+ }
+
+ /// A 32/64 bit Note struct, with the name and desc pre-parsed
+ #[derive(Debug)]
+ pub struct Note<'a> {
+ /// The type of this note
+ pub n_type: u32,
+ /// NUL terminated string, where `namesz` includes the terminator
+ pub name: &'a str, // needs padding such that namesz + padding % {wordsize} == 0
+ /// arbitrary data of length `descsz`
+ pub desc: &'a [u8], // needs padding such that descsz + padding % {wordsize} == 0
+ }
+
+ impl<'a> Note<'a> {
+ pub fn type_to_str(&self) -> &'static str {
+ match self.n_type {
+ NT_GNU_ABI_TAG => "NT_GNU_ABI_TAG",
+ NT_GNU_HWCAP => "NT_GNU_HWCAP",
+ NT_GNU_BUILD_ID => "NT_GNU_BUILD_ID",
+ NT_GNU_GOLD_VERSION => "NT_GNU_GOLD_VERSION",
+ _ => "NT_UNKNOWN"
+ }
+ }
+ }
+
+ impl<'a> ctx::TryFromCtx<'a, (usize, container::Ctx)> for Note<'a> {
+ type Error = error::Error;
+ fn try_from_ctx(bytes: &'a [u8], (alignment, ctx): (usize, container::Ctx)) -> Result<(Self, usize), Self::Error> {
+ let offset = &mut 0;
+ let mut alignment = alignment;
+ if alignment < 4 {
+ alignment = 4;
+ }
+ let header: NoteHeader = {
+ match alignment {
+ 4|8 => bytes.gread_with::<Nhdr32>(offset, ctx.le)?.into(),
+ _ => return Err(error::Error::Malformed(format!("Notes has unimplemented alignment requirement: {:#x}", alignment)))
+ }
+ };
+ debug!("{:?} - {:#x}", header, *offset);
+ // -1 because includes \0 terminator
+ let name = bytes.gread_with::<&'a str>(offset, ctx::StrCtx::Length(header.n_namesz.saturating_sub(1)))?;
+ if header.n_namesz > 0 {
+ *offset += 1;
+ }
+ align(alignment, offset);
+ debug!("note name {} - {:#x}", name, *offset);
+ let desc = bytes.gread_with::<&'a [u8]>(offset, header.n_descsz)?;
+ align(alignment, offset);
+ debug!("desc {:?} - {:#x}", desc, *offset);
+ Ok((Note {
+ name,
+ desc,
+ n_type: header.n_type,
+ }, *offset))
+ }
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use super::*;
+
+ static NOTE_DATA: [u8; 68] = [0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
+ 0xbc, 0xfc, 0x66, 0xcd, 0xc7, 0xd5, 0x14, 0x7b,
+ 0x53, 0xb1, 0x10, 0x11, 0x94, 0x86, 0x8e, 0xf9,
+ 0x4f, 0xe8, 0xdd, 0xdb];
+
+ static CONTEXT: (usize, container::Ctx) = (4, container::Ctx {
+ container: container::Container::Big,
+ le: ::scroll::Endian::Little,
+ });
+
+ fn make_note_iter(start: usize, end: usize) -> NoteDataIterator<'static> {
+ NoteDataIterator {
+ data: &NOTE_DATA,
+ size: end,
+ offset: start,
+ ctx: CONTEXT,
+ }
+ }
+
+ #[test]
+ fn iter_single_section() {
+ let mut notes = NoteIterator {
+ iters: vec![make_note_iter(0, 68)],
+ index: 0,
+ };
+
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
+ assert!(notes.next().is_none());
+ }
+
+ #[test]
+ fn iter_multiple_sections() {
+ let mut notes = NoteIterator {
+ iters: vec![make_note_iter(0, 32), make_note_iter(32, 68)],
+ index: 0,
+ };
+
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
+ assert!(notes.next().is_none());
+ }
+
+ #[test]
+ fn skip_empty_sections() {
+ let mut notes = NoteIterator {
+ iters: vec![
+ make_note_iter(0, 32),
+ make_note_iter(0, 0),
+ make_note_iter(32, 68),
+ ],
+ index: 0,
+ };
+
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
+ assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
+ assert!(notes.next().is_none());
+ }
+
+ #[test]
+ fn ignore_no_sections() {
+ let mut notes = NoteIterator { iters: vec![], index: 0 };
+ assert!(notes.next().is_none());
+ }
+ }
+}