object/read/elf/
note.rs
1use core::fmt::Debug;
2use core::mem;
3
4use crate::elf;
5use crate::endian::{self, U32};
6use crate::pod::Pod;
7use crate::read::util;
8use crate::read::{self, Bytes, Error, ReadError};
9
10use super::FileHeader;
11
12#[derive(Debug)]
17pub struct NoteIterator<'data, Elf>
18where
19 Elf: FileHeader,
20{
21 endian: Elf::Endian,
22 align: usize,
23 data: Bytes<'data>,
24}
25
26impl<'data, Elf> NoteIterator<'data, Elf>
27where
28 Elf: FileHeader,
29{
30 pub fn new(endian: Elf::Endian, align: Elf::Word, data: &'data [u8]) -> read::Result<Self> {
39 let align = match align.into() {
40 0u64..=4 => 4,
41 8 => 8,
42 _ => return Err(Error("Invalid ELF note alignment")),
43 };
44 Ok(NoteIterator {
46 endian,
47 align,
48 data: Bytes(data),
49 })
50 }
51
52 pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> {
54 if self.data.is_empty() {
55 return Ok(None);
56 }
57
58 let result = self.parse().map(Some);
59 if result.is_err() {
60 self.data = Bytes(&[]);
61 }
62 result
63 }
64
65 fn parse(&mut self) -> read::Result<Note<'data, Elf>> {
66 let header = self
67 .data
68 .read_at::<Elf::NoteHeader>(0)
69 .read_error("ELF note is too short")?;
70
71 let offset = mem::size_of::<Elf::NoteHeader>();
73 let namesz = header.n_namesz(self.endian) as usize;
74 let name = self
75 .data
76 .read_bytes_at(offset, namesz)
77 .read_error("Invalid ELF note namesz")?
78 .0;
79
80 let offset = util::align(offset + namesz, self.align);
82 let descsz = header.n_descsz(self.endian) as usize;
83 let desc = self
84 .data
85 .read_bytes_at(offset, descsz)
86 .read_error("Invalid ELF note descsz")?
87 .0;
88
89 let offset = util::align(offset + descsz, self.align);
91 if self.data.skip(offset).is_err() {
92 self.data = Bytes(&[]);
93 }
94
95 Ok(Note { header, name, desc })
96 }
97}
98
99impl<'data, Elf: FileHeader> Iterator for NoteIterator<'data, Elf> {
100 type Item = read::Result<Note<'data, Elf>>;
101
102 fn next(&mut self) -> Option<Self::Item> {
103 self.next().transpose()
104 }
105}
106
107#[derive(Debug)]
109pub struct Note<'data, Elf>
110where
111 Elf: FileHeader,
112{
113 header: &'data Elf::NoteHeader,
114 name: &'data [u8],
115 desc: &'data [u8],
116}
117
118impl<'data, Elf: FileHeader> Note<'data, Elf> {
119 pub fn n_type(&self, endian: Elf::Endian) -> u32 {
123 self.header.n_type(endian)
124 }
125
126 pub fn n_namesz(&self, endian: Elf::Endian) -> u32 {
128 self.header.n_namesz(endian)
129 }
130
131 pub fn n_descsz(&self, endian: Elf::Endian) -> u32 {
133 self.header.n_descsz(endian)
134 }
135
136 pub fn name_bytes(&self) -> &'data [u8] {
143 self.name
144 }
145
146 pub fn name(&self) -> &'data [u8] {
149 let mut name = self.name;
150 while let [rest @ .., 0] = name {
151 name = rest;
152 }
153 name
154 }
155
156 pub fn desc(&self) -> &'data [u8] {
161 self.desc
162 }
163
164 pub fn gnu_properties(
166 &self,
167 endian: Elf::Endian,
168 ) -> Option<GnuPropertyIterator<'data, Elf::Endian>> {
169 if self.name() != elf::ELF_NOTE_GNU || self.n_type(endian) != elf::NT_GNU_PROPERTY_TYPE_0 {
170 return None;
171 }
172 let align = if Elf::is_type_64_sized() { 8 } else { 4 };
175 Some(GnuPropertyIterator {
176 endian,
177 align,
178 data: Bytes(self.desc),
179 })
180 }
181}
182
183#[allow(missing_docs)]
185pub trait NoteHeader: Debug + Pod {
186 type Endian: endian::Endian;
187
188 fn n_namesz(&self, endian: Self::Endian) -> u32;
189 fn n_descsz(&self, endian: Self::Endian) -> u32;
190 fn n_type(&self, endian: Self::Endian) -> u32;
191}
192
193impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader32<Endian> {
194 type Endian = Endian;
195
196 #[inline]
197 fn n_namesz(&self, endian: Self::Endian) -> u32 {
198 self.n_namesz.get(endian)
199 }
200
201 #[inline]
202 fn n_descsz(&self, endian: Self::Endian) -> u32 {
203 self.n_descsz.get(endian)
204 }
205
206 #[inline]
207 fn n_type(&self, endian: Self::Endian) -> u32 {
208 self.n_type.get(endian)
209 }
210}
211
212impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> {
213 type Endian = Endian;
214
215 #[inline]
216 fn n_namesz(&self, endian: Self::Endian) -> u32 {
217 self.n_namesz.get(endian)
218 }
219
220 #[inline]
221 fn n_descsz(&self, endian: Self::Endian) -> u32 {
222 self.n_descsz.get(endian)
223 }
224
225 #[inline]
226 fn n_type(&self, endian: Self::Endian) -> u32 {
227 self.n_type.get(endian)
228 }
229}
230
231#[derive(Debug)]
235pub struct GnuPropertyIterator<'data, Endian: endian::Endian> {
236 endian: Endian,
237 align: usize,
238 data: Bytes<'data>,
239}
240
241impl<'data, Endian: endian::Endian> GnuPropertyIterator<'data, Endian> {
242 pub fn next(&mut self) -> read::Result<Option<GnuProperty<'data>>> {
244 if self.data.is_empty() {
245 return Ok(None);
246 }
247
248 let result = self.parse().map(Some);
249 if result.is_err() {
250 self.data = Bytes(&[]);
251 }
252 result
253 }
254
255 fn parse(&mut self) -> read::Result<GnuProperty<'data>> {
256 (|| -> Result<_, ()> {
257 let pr_type = self.data.read_at::<U32<Endian>>(0)?.get(self.endian);
258 let pr_datasz = self.data.read_at::<U32<Endian>>(4)?.get(self.endian) as usize;
259 let pr_data = self.data.read_bytes_at(8, pr_datasz)?.0;
260 self.data.skip(util::align(8 + pr_datasz, self.align))?;
261 Ok(GnuProperty { pr_type, pr_data })
262 })()
263 .read_error("Invalid ELF GNU property")
264 }
265}
266
267impl<'data, Endian: endian::Endian> Iterator for GnuPropertyIterator<'data, Endian> {
268 type Item = read::Result<GnuProperty<'data>>;
269
270 fn next(&mut self) -> Option<Self::Item> {
271 self.next().transpose()
272 }
273}
274
275#[derive(Debug)]
277pub struct GnuProperty<'data> {
278 pr_type: u32,
279 pr_data: &'data [u8],
280}
281
282impl<'data> GnuProperty<'data> {
283 pub fn pr_type(&self) -> u32 {
287 self.pr_type
288 }
289
290 pub fn pr_data(&self) -> &'data [u8] {
292 self.pr_data
293 }
294
295 pub fn data_u32<E: endian::Endian>(&self, endian: E) -> read::Result<u32> {
297 Bytes(self.pr_data)
298 .read_at::<U32<E>>(0)
299 .read_error("Invalid ELF GNU property data")
300 .map(|val| val.get(endian))
301 }
302}