]>
Commit | Line | Data |
---|---|---|
9c376795 FG |
1 | use core::fmt::Debug; |
2 | use core::mem; | |
3 | ||
4 | use crate::elf; | |
5 | use crate::endian; | |
6 | use crate::pod::Pod; | |
7 | use crate::read::util; | |
8 | use crate::read::{self, Bytes, 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. | |
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. | |
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`. | |
99 | 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`. | |
104 | 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`. | |
109 | 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`. | |
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`. | |
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 | ||
144 | fn n_namesz(&self, endian: Self::Endian) -> u32; | |
145 | fn n_descsz(&self, endian: Self::Endian) -> u32; | |
146 | 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] | |
153 | fn n_namesz(&self, endian: Self::Endian) -> u32 { | |
154 | self.n_namesz.get(endian) | |
155 | } | |
156 | ||
157 | #[inline] | |
158 | fn n_descsz(&self, endian: Self::Endian) -> u32 { | |
159 | self.n_descsz.get(endian) | |
160 | } | |
161 | ||
162 | #[inline] | |
163 | 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] | |
172 | fn n_namesz(&self, endian: Self::Endian) -> u32 { | |
173 | self.n_namesz.get(endian) | |
174 | } | |
175 | ||
176 | #[inline] | |
177 | fn n_descsz(&self, endian: Self::Endian) -> u32 { | |
178 | self.n_descsz.get(endian) | |
179 | } | |
180 | ||
181 | #[inline] | |
182 | fn n_type(&self, endian: Self::Endian) -> u32 { | |
183 | self.n_type.get(endian) | |
184 | } | |
185 | } |