/rust/registry/src/index.crates.io-6f17d22bba15001f/object-0.28.4/src/read/elf/note.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | pub(super) fn new( |
29 | 0 | endian: Elf::Endian, |
30 | 0 | align: Elf::Word, |
31 | 0 | data: &'data [u8], |
32 | 0 | ) -> read::Result<Self> { |
33 | 0 | let align = match align.into() { |
34 | 0 | 0u64..=4 => 4, |
35 | 0 | 8 => 8, |
36 | 0 | _ => return Err(Error("Invalid ELF note alignment")), |
37 | | }; |
38 | | // TODO: check data alignment? |
39 | 0 | Ok(NoteIterator { |
40 | 0 | endian, |
41 | 0 | align, |
42 | 0 | data: Bytes(data), |
43 | 0 | }) |
44 | 0 | } |
45 | | |
46 | | /// Returns the next note. |
47 | 0 | pub fn next(&mut self) -> read::Result<Option<Note<'data, Elf>>> { |
48 | 0 | let mut data = self.data; |
49 | 0 | if data.is_empty() { |
50 | 0 | return Ok(None); |
51 | 0 | } |
52 | | |
53 | 0 | let header = data |
54 | 0 | .read_at::<Elf::NoteHeader>(0) |
55 | 0 | .read_error("ELF note is too short")?; |
56 | | |
57 | | // The name has no alignment requirement. |
58 | 0 | let offset = mem::size_of::<Elf::NoteHeader>(); |
59 | 0 | let namesz = header.n_namesz(self.endian) as usize; |
60 | 0 | let name = data |
61 | 0 | .read_bytes_at(offset, namesz) |
62 | 0 | .read_error("Invalid ELF note namesz")? |
63 | | .0; |
64 | | |
65 | | // The descriptor must be aligned. |
66 | 0 | let offset = util::align(offset + namesz, self.align); |
67 | 0 | let descsz = header.n_descsz(self.endian) as usize; |
68 | 0 | let desc = data |
69 | 0 | .read_bytes_at(offset, descsz) |
70 | 0 | .read_error("Invalid ELF note descsz")? |
71 | | .0; |
72 | | |
73 | | // The next note (if any) must be aligned. |
74 | 0 | let offset = util::align(offset + descsz, self.align); |
75 | 0 | if data.skip(offset).is_err() { |
76 | 0 | data = Bytes(&[]); |
77 | 0 | } |
78 | 0 | self.data = data; |
79 | 0 |
|
80 | 0 | Ok(Some(Note { header, name, desc })) |
81 | 0 | } |
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 | 0 | pub fn n_type(&self, endian: Elf::Endian) -> u32 { |
100 | 0 | self.header.n_type(endian) |
101 | 0 | } |
102 | | |
103 | | /// Return the `n_namesz` field of the `NoteHeader`. |
104 | 0 | pub fn n_namesz(&self, endian: Elf::Endian) -> u32 { |
105 | 0 | self.header.n_namesz(endian) |
106 | 0 | } |
107 | | |
108 | | /// Return the `n_descsz` field of the `NoteHeader`. |
109 | 0 | pub fn n_descsz(&self, endian: Elf::Endian) -> u32 { |
110 | 0 | self.header.n_descsz(endian) |
111 | 0 | } |
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 | 0 | pub fn name(&self) -> &'data [u8] { |
122 | 0 | if let Some((last, name)) = self.name.split_last() { |
123 | 0 | if *last == 0 { |
124 | 0 | return name; |
125 | 0 | } |
126 | 0 | } |
127 | 0 | self.name |
128 | 0 | } |
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 | 0 | pub fn desc(&self) -> &'data [u8] { |
135 | 0 | self.desc |
136 | 0 | } |
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 | 0 | fn n_namesz(&self, endian: Self::Endian) -> u32 { |
154 | 0 | self.n_namesz.get(endian) |
155 | 0 | } |
156 | | |
157 | | #[inline] |
158 | 0 | fn n_descsz(&self, endian: Self::Endian) -> u32 { |
159 | 0 | self.n_descsz.get(endian) |
160 | 0 | } |
161 | | |
162 | | #[inline] |
163 | 0 | fn n_type(&self, endian: Self::Endian) -> u32 { |
164 | 0 | self.n_type.get(endian) |
165 | 0 | } |
166 | | } |
167 | | |
168 | | impl<Endian: endian::Endian> NoteHeader for elf::NoteHeader64<Endian> { |
169 | | type Endian = Endian; |
170 | | |
171 | | #[inline] |
172 | 0 | fn n_namesz(&self, endian: Self::Endian) -> u32 { |
173 | 0 | self.n_namesz.get(endian) |
174 | 0 | } |
175 | | |
176 | | #[inline] |
177 | 0 | fn n_descsz(&self, endian: Self::Endian) -> u32 { |
178 | 0 | self.n_descsz.get(endian) |
179 | 0 | } |
180 | | |
181 | | #[inline] |
182 | 0 | fn n_type(&self, endian: Self::Endian) -> u32 { |
183 | 0 | self.n_type.get(endian) |
184 | 0 | } |
185 | | } |