1 use core::fmt::Debug;
2 use core::mem;
3 
4 use crate::elf;
5 use crate::endian;
6 use crate::pod::{Bytes, Pod};
7 use crate::read::util;
8 use crate::read::{self, Error, ReadError};
9 
10 use super::FileHeader;
11 
12 /// An iterator over the notes in an ELF section or segment.
13 #[derive(Debug)]
14 pub struct NoteIterator<'data, Elf>
15 where
16     Elf: FileHeader,
17 {
18     endian: Elf::Endian,
19     align: usize,
20     data: Bytes<'data>,
21 }
22 
23 impl<'data, Elf> NoteIterator<'data, Elf>
24 where
25     Elf: FileHeader,
26 {
27     /// Returns `Err` if `align` is invalid.
new( endian: Elf::Endian, align: Elf::Word, data: &'data [u8], ) -> read::Result<Self>28     pub(super) fn new(
29         endian: Elf::Endian,
30         align: Elf::Word,
31         data: &'data [u8],
32     ) -> read::Result<Self> {
33         let align = match align.into() {
34             0u64..=4 => 4,
35             8 => 8,
36             _ => return Err(Error("Invalid ELF note alignment")),
37         };
38         // TODO: check data alignment?
39         Ok(NoteIterator {
40             endian,
41             align,
42             data: Bytes(data),
43         })
44     }
45 
46     /// Returns the next note.
next(&mut self) -> read::Result<Option<Note<'data, Elf>>>47     pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> {
48         let mut data = self.data;
49         if data.is_empty() {
50             return Ok(None);
51         }
52 
53         let header = data
54             .read_at::<Elf::NoteHeader>(0)
55             .read_error("ELF note is too short")?;
56 
57         // The name has no alignment requirement.
58         let offset = mem::size_of::<Elf::NoteHeader>();
59         let namesz = header.n_namesz(self.endian) as usize;
60         let name = data
61             .read_bytes_at(offset, namesz)
62             .read_error("Invalid ELF note namesz")?
63             .0;
64 
65         // The descriptor must be aligned.
66         let offset = util::align(offset + namesz, self.align);
67         let descsz = header.n_descsz(self.endian) as usize;
68         let desc = data
69             .read_bytes_at(offset, descsz)
70             .read_error("Invalid ELF note descsz")?
71             .0;
72 
73         // The next note (if any) must be aligned.
74         let offset = util::align(offset + descsz, self.align);
75         if data.skip(offset).is_err() {
76             data = Bytes(&[]);
77         }
78         self.data = data;
79 
80         Ok(Some(Note { header, name, desc }))
81     }
82 }
83 
84 /// A parsed `NoteHeader`.
85 #[derive(Debug)]
86 pub struct Note<'data, Elf>
87 where
88     Elf: FileHeader,
89 {
90     header: &'data Elf::NoteHeader,
91     name: &'data [u8],
92     desc: &'data [u8],
93 }
94 
95 impl<'data, Elf: FileHeader> Note<'data, Elf> {
96     /// Return the `n_type` field of the `NoteHeader`.
97     ///
98     /// The meaning of this field is determined by `name`.
n_type(&self, endian: Elf::Endian) -> u3299     pub fn n_type(&self, endian: Elf::Endian) -> u32 {
100         self.header.n_type(endian)
101     }
102 
103     /// Return the `n_namesz` field of the `NoteHeader`.
n_namesz(&self, endian: Elf::Endian) -> u32104     pub fn n_namesz(&self, endian: Elf::Endian) -> u32 {
105         self.header.n_namesz(endian)
106     }
107 
108     /// Return the `n_descsz` field of the `NoteHeader`.
n_descsz(&self, endian: Elf::Endian) -> u32109     pub fn n_descsz(&self, endian: Elf::Endian) -> u32 {
110         self.header.n_descsz(endian)
111     }
112 
113     /// Return the bytes for the name field following the `NoteHeader`,
114     /// excluding any null terminator.
115     ///
116     /// This field is usually a string including a null terminator
117     /// (but it is not required to be).
118     ///
119     /// The length of this field (including any null terminator) is given by
120     /// `n_namesz`.
name(&self) -> &'data [u8]121     pub fn name(&self) -> &'data [u8] {
122         if let Some((last, name)) = self.name.split_last() {
123             if *last == 0 {
124                 return name;
125             }
126         }
127         self.name
128     }
129 
130     /// Return the bytes for the desc field following the `NoteHeader`.
131     ///
132     /// The length of this field is given by `n_descsz`. The meaning
133     /// of this field is determined by `name` and `n_type`.
desc(&self) -> &'data [u8]134     pub fn desc(&self) -> &'data [u8] {
135         self.desc
136     }
137 }
138 
139 /// A trait for generic access to `NoteHeader32` and `NoteHeader64`.
140 #[allow(missing_docs)]
141 pub trait NoteHeader: Debug + Pod {
142     type Endian: endian::Endian;
143 
n_namesz(&self, endian: Self::Endian) -> u32144     fn n_namesz(&self, endian: Self::Endian) -> u32;
n_descsz(&self, endian: Self::Endian) -> u32145     fn n_descsz(&self, endian: Self::Endian) -> u32;
n_type(&self, endian: Self::Endian) -> u32146     fn n_type(&self, endian: Self::Endian) -> u32;
147 }
148 
149 impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader32<Endian> {
150     type Endian = Endian;
151 
152     #[inline]
n_namesz(&self, endian: Self::Endian) -> u32153     fn n_namesz(&self, endian: Self::Endian) -> u32 {
154         self.n_namesz.get(endian)
155     }
156 
157     #[inline]
n_descsz(&self, endian: Self::Endian) -> u32158     fn n_descsz(&self, endian: Self::Endian) -> u32 {
159         self.n_descsz.get(endian)
160     }
161 
162     #[inline]
n_type(&self, endian: Self::Endian) -> u32163     fn n_type(&self, endian: Self::Endian) -> u32 {
164         self.n_type.get(endian)
165     }
166 }
167 
168 impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> {
169     type Endian = Endian;
170 
171     #[inline]
n_namesz(&self, endian: Self::Endian) -> u32172     fn n_namesz(&self, endian: Self::Endian) -> u32 {
173         self.n_namesz.get(endian)
174     }
175 
176     #[inline]
n_descsz(&self, endian: Self::Endian) -> u32177     fn n_descsz(&self, endian: Self::Endian) -> u32 {
178         self.n_descsz.get(endian)
179     }
180 
181     #[inline]
n_type(&self, endian: Self::Endian) -> u32182     fn n_type(&self, endian: Self::Endian) -> u32 {
183         self.n_type.get(endian)
184     }
185 }
186