From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/rust/goblin/src/elf/note.rs | 305 ++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 third_party/rust/goblin/src/elf/note.rs (limited to 'third_party/rust/goblin/src/elf/note.rs') 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>; + fn next(&mut self) -> Option { + 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>, + pub index: usize, + } + + impl<'a> Iterator for NoteIterator<'a> { + type Item = error::Result>; + fn next(&mut self) -> Option { + 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 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 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::(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()); + } + } +} -- cgit v1.2.3