1#[cfg(feature = "log")]
4use log::debug;
5#[cfg(feature = "alloc")]
6use scroll::{IOread, IOwrite, Pread, Pwrite, SizeWith};
7
8pub const NT_GNU_ABI_TAG: u32 = 1;
16
17pub const ELF_NOTE_ABI: u32 = NT_GNU_ABI_TAG;
19pub const ELF_NOTE_OS_LINUX: u32 = 0;
22pub const ELF_NOTE_OS_GNU: u32 = 1;
23pub const ELF_NOTE_OS_SOLARIS2: u32 = 2;
24pub const ELF_NOTE_OS_FREEBSD: u32 = 3;
25
26pub const NT_GNU_HWCAP: u32 = 2;
36
37pub const NT_GNU_BUILD_ID: u32 = 3;
41
42pub const NT_GNU_GOLD_VERSION: u32 = 4;
44
45pub const NT_GNU_PROPERTY_TYPE_0: u32 = 5;
47
48pub const NT_PRSTATUS: u32 = 1;
50
51pub const NT_PRPSINFO: u32 = 3;
53
54pub const NT_SIGINFO: u32 = 0x5349_4749;
56
57pub const NT_FILE: u32 = 0x4649_4c45;
59
60#[derive(Clone, Copy, Debug)]
61#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))]
62#[repr(C)]
63pub struct Nhdr32 {
66 pub n_namesz: u32,
68 pub n_descsz: u32,
70 pub n_type: u32,
72}
73
74unsafe impl plain::Plain for Nhdr32 {}
76
77#[derive(Clone, Copy, Debug)]
78#[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))]
79#[repr(C)]
80pub struct Nhdr64 {
83 pub n_namesz: u64,
85 pub n_descsz: u64,
87 pub n_type: u64,
89}
90
91unsafe impl plain::Plain for Nhdr64 {}
93
94if_alloc! {
95 use crate::error;
96 use crate::container;
97 use scroll::ctx;
98 use alloc::vec::Vec;
99
100 pub struct NoteDataIterator<'a> {
102 pub data: &'a [u8],
103 pub size: usize,
104 pub offset: usize,
105 pub ctx: (usize, container::Ctx), }
107
108 impl<'a> Iterator for NoteDataIterator<'a> {
109 type Item = error::Result<Note<'a>>;
110 fn next(&mut self) -> Option<Self::Item> {
111 if self.offset >= self.size {
112 None
113 } else {
114 debug!("NoteIterator - {:#x}", self.offset);
115 match self.data.gread_with(&mut self.offset, self.ctx) {
116 Ok(res) => Some(Ok(res)),
117 Err(e) => Some(Err(e))
118 }
119 }
120 }
121 }
122
123 pub struct NoteIterator<'a> {
125 pub iters: Vec<NoteDataIterator<'a>>,
126 pub index: usize,
127 }
128
129 impl<'a> Iterator for NoteIterator<'a> {
130 type Item = error::Result<Note<'a>>;
131 fn next(&mut self) -> Option<Self::Item> {
132 while self.index < self.iters.len() {
133 if let Some(note_result) = self.iters[self.index].next() {
134 return Some(note_result);
135 }
136
137 self.index += 1;
138 }
139
140 None
141 }
142 }
143
144 #[derive(Debug)]
145 struct NoteHeader {
146 n_namesz: usize,
147 n_descsz: usize,
148 n_type: u32,
149 }
150
151 impl From<Nhdr32> for NoteHeader {
152 fn from(header: Nhdr32) -> Self {
153 NoteHeader {
154 n_namesz: header.n_namesz as usize,
155 n_descsz: header.n_descsz as usize,
156 n_type: header.n_type,
157 }
158 }
159 }
160
161 impl From<Nhdr64> for NoteHeader {
162 fn from(header: Nhdr64) -> Self {
163 NoteHeader {
164 n_namesz: header.n_namesz as usize,
165 n_descsz: header.n_descsz as usize,
166 n_type: header.n_type as u32,
167 }
168 }
169 }
170
171 fn align(alignment: usize, offset: &mut usize) {
172 let diff = *offset % alignment;
173 if diff != 0 {
174 *offset += alignment - diff;
175 }
176 }
177
178 #[derive(Debug)]
180 pub struct Note<'a> {
181 pub n_type: u32,
183 pub name: &'a str, pub desc: &'a [u8], }
188
189 impl<'a> Note<'a> {
190 pub fn type_to_str(&self) -> &'static str {
191 match self.n_type {
192 NT_GNU_ABI_TAG => "NT_GNU_ABI_TAG",
193 NT_GNU_HWCAP => "NT_GNU_HWCAP",
194 NT_GNU_BUILD_ID => "NT_GNU_BUILD_ID",
195 NT_GNU_GOLD_VERSION => "NT_GNU_GOLD_VERSION",
196 NT_GNU_PROPERTY_TYPE_0 => "NT_GNU_PROPERTY_0",
197 _ => "NT_UNKNOWN"
198 }
199 }
200 }
201
202 impl<'a> ctx::TryFromCtx<'a, (usize, container::Ctx)> for Note<'a> {
203 type Error = error::Error;
204 fn try_from_ctx(bytes: &'a [u8], (alignment, ctx): (usize, container::Ctx)) -> Result<(Self, usize), Self::Error> {
205 let offset = &mut 0;
206 let mut alignment = alignment;
207 if alignment < 4 {
208 alignment = 4;
209 }
210 let header: NoteHeader = {
211 match alignment {
212 4|8 => bytes.gread_with::<Nhdr32>(offset, ctx.le)?.into(),
213 _ => return Err(error::Error::Malformed(format!("Notes has unimplemented alignment requirement: {:#x}", alignment)))
214 }
215 };
216 debug!("{:?} - {:#x}", header, *offset);
217 let name = bytes.gread_with::<&'a str>(offset, ctx::StrCtx::Length(header.n_namesz.saturating_sub(1)))?;
219 if header.n_namesz > 0 {
220 *offset += 1;
221 }
222 align(alignment, offset);
223 debug!("note name {} - {:#x}", name, *offset);
224 let desc = bytes.gread_with::<&'a [u8]>(offset, header.n_descsz)?;
225 align(alignment, offset);
226 debug!("desc {:?} - {:#x}", desc, *offset);
227 Ok((Note {
228 name,
229 desc,
230 n_type: header.n_type,
231 }, *offset))
232 }
233 }
234
235 #[cfg(test)]
236 mod tests {
237 use super::*;
238
239 static NOTE_DATA: [u8; 132] = [0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
240 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
242 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
243 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
244 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00,
245 0xbc, 0xfc, 0x66, 0xcd, 0xc7, 0xd5, 0x14, 0x7b,
246 0x53, 0xb1, 0x10, 0x11, 0x94, 0x86, 0x8e, 0xf9,
247 0x4f, 0xe8, 0xdd, 0xdb, 0x04, 0x00, 0x00, 0x00,
248 0x30, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
249 0x47, 0x4E, 0x55, 0x00, 0x02, 0x80, 0x00, 0xC0,
250 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
251 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xC0,
252 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
253 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xC0,
254 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00];
256
257 static CONTEXT: (usize, container::Ctx) = (4, container::Ctx {
258 container: container::Container::Big,
259 le: ::scroll::Endian::Little,
260 });
261
262 fn make_note_iter(start: usize, end: usize) -> NoteDataIterator<'static> {
263 NoteDataIterator {
264 data: &NOTE_DATA,
265 size: end,
266 offset: start,
267 ctx: CONTEXT,
268 }
269 }
270
271 #[test]
272 fn iter_single_section() {
273 let mut notes = NoteIterator {
274 iters: vec![make_note_iter(0, 132)],
275 index: 0,
276 };
277
278 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
279 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
280 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_PROPERTY_TYPE_0);
281 assert!(notes.next().is_none());
282 }
283
284 #[test]
285 fn iter_multiple_sections() {
286 let mut notes = NoteIterator {
287 iters: vec![make_note_iter(0, 32), make_note_iter(32, 68), make_note_iter(68, 132)],
288 index: 0,
289 };
290
291 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
292 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
293 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_PROPERTY_TYPE_0);
294 assert!(notes.next().is_none());
295 }
296
297 #[test]
298 fn skip_empty_sections() {
299 let mut notes = NoteIterator {
300 iters: vec![
301 make_note_iter(0, 32),
302 make_note_iter(0, 0),
303 make_note_iter(32, 68),
304 ],
305 index: 0,
306 };
307
308 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG);
309 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID);
310 assert!(notes.next().is_none());
311 }
312
313 #[test]
314 fn ignore_no_sections() {
315 let mut notes = NoteIterator { iters: vec![], index: 0 };
316 assert!(notes.next().is_none());
317 }
318 }
319}