]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.31.1/src/read/elf/version.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / vendor / object-0.31.1 / src / read / elf / version.rs
1 use alloc::vec::Vec;
2
3 use crate::read::{Bytes, ReadError, ReadRef, Result, StringTable};
4 use crate::{elf, endian};
5
6 use super::FileHeader;
7
8 /// A version index.
9 #[derive(Debug, Default, Clone, Copy)]
10 pub struct VersionIndex(pub u16);
11
12 impl VersionIndex {
13 /// Return the version index.
14 pub fn index(&self) -> u16 {
15 self.0 & elf::VERSYM_VERSION
16 }
17
18 /// Return true if it is the local index.
19 pub fn is_local(&self) -> bool {
20 self.index() == elf::VER_NDX_LOCAL
21 }
22
23 /// Return true if it is the global index.
24 pub fn is_global(&self) -> bool {
25 self.index() == elf::VER_NDX_GLOBAL
26 }
27
28 /// Return the hidden flag.
29 pub fn is_hidden(&self) -> bool {
30 self.0 & elf::VERSYM_HIDDEN != 0
31 }
32 }
33
34 /// A version definition or requirement.
35 ///
36 /// This is derived from entries in the `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
37 #[derive(Debug, Default, Clone, Copy)]
38 pub struct Version<'data> {
39 name: &'data [u8],
40 hash: u32,
41 // Used to keep track of valid indices in `VersionTable`.
42 valid: bool,
43 }
44
45 impl<'data> Version<'data> {
46 /// Return the version name.
47 pub fn name(&self) -> &'data [u8] {
48 self.name
49 }
50
51 /// Return hash of the version name.
52 pub fn hash(&self) -> u32 {
53 self.hash
54 }
55 }
56
57 /// A table of version definitions and requirements.
58 ///
59 /// It allows looking up the version information for a given symbol index.
60 ///
61 /// This is derived from entries in the `SHT_GNU_versym`, `SHT_GNU_verdef` and `SHT_GNU_verneed` sections.
62 #[derive(Debug, Clone)]
63 pub struct VersionTable<'data, Elf: FileHeader> {
64 symbols: &'data [elf::Versym<Elf::Endian>],
65 versions: Vec<Version<'data>>,
66 }
67
68 impl<'data, Elf: FileHeader> Default for VersionTable<'data, Elf> {
69 fn default() -> Self {
70 VersionTable {
71 symbols: &[],
72 versions: Vec::new(),
73 }
74 }
75 }
76
77 impl<'data, Elf: FileHeader> VersionTable<'data, Elf> {
78 /// Parse the version sections.
79 pub fn parse<R: ReadRef<'data>>(
80 endian: Elf::Endian,
81 versyms: &'data [elf::Versym<Elf::Endian>],
82 verdefs: Option<VerdefIterator<'data, Elf>>,
83 verneeds: Option<VerneedIterator<'data, Elf>>,
84 strings: StringTable<'data, R>,
85 ) -> Result<Self> {
86 let mut max_index = 0;
87 if let Some(mut verdefs) = verdefs.clone() {
88 while let Some((verdef, _)) = verdefs.next()? {
89 if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 {
90 continue;
91 }
92 let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION;
93 if max_index < index {
94 max_index = index;
95 }
96 }
97 }
98 if let Some(mut verneeds) = verneeds.clone() {
99 while let Some((_, mut vernauxs)) = verneeds.next()? {
100 while let Some(vernaux) = vernauxs.next()? {
101 let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION;
102 if max_index < index {
103 max_index = index;
104 }
105 }
106 }
107 }
108
109 // Indices should be sequential, but this could be up to
110 // 32k * size_of::<Version>() if max_index is bad.
111 let mut versions = vec![Version::default(); max_index as usize + 1];
112
113 if let Some(mut verdefs) = verdefs {
114 while let Some((verdef, mut verdauxs)) = verdefs.next()? {
115 if verdef.vd_flags.get(endian) & elf::VER_FLG_BASE != 0 {
116 continue;
117 }
118 let index = verdef.vd_ndx.get(endian) & elf::VERSYM_VERSION;
119 if index <= elf::VER_NDX_GLOBAL {
120 // TODO: return error?
121 continue;
122 }
123 if let Some(verdaux) = verdauxs.next()? {
124 versions[usize::from(index)] = Version {
125 name: verdaux.name(endian, strings)?,
126 hash: verdef.vd_hash.get(endian),
127 valid: true,
128 };
129 }
130 }
131 }
132 if let Some(mut verneeds) = verneeds {
133 while let Some((_, mut vernauxs)) = verneeds.next()? {
134 while let Some(vernaux) = vernauxs.next()? {
135 let index = vernaux.vna_other.get(endian) & elf::VERSYM_VERSION;
136 if index <= elf::VER_NDX_GLOBAL {
137 // TODO: return error?
138 continue;
139 }
140 versions[usize::from(index)] = Version {
141 name: vernaux.name(endian, strings)?,
142 hash: vernaux.vna_hash.get(endian),
143 valid: true,
144 };
145 }
146 }
147 }
148
149 Ok(VersionTable {
150 symbols: versyms,
151 versions,
152 })
153 }
154
155 /// Return true if the version table is empty.
156 pub fn is_empty(&self) -> bool {
157 self.symbols.is_empty()
158 }
159
160 /// Return version index for a given symbol index.
161 pub fn version_index(&self, endian: Elf::Endian, index: usize) -> VersionIndex {
162 let version_index = match self.symbols.get(index) {
163 Some(x) => x.0.get(endian),
164 // Ideally this would be VER_NDX_LOCAL for undefined symbols,
165 // but currently there are no checks that need this distinction.
166 None => elf::VER_NDX_GLOBAL,
167 };
168 VersionIndex(version_index)
169 }
170
171 /// Return version information for a given symbol version index.
172 ///
173 /// Returns `Ok(None)` for local and global versions.
174 /// Returns `Err(_)` if index is invalid.
175 pub fn version(&self, index: VersionIndex) -> Result<Option<&Version<'data>>> {
176 if index.index() <= elf::VER_NDX_GLOBAL {
177 return Ok(None);
178 }
179 self.versions
180 .get(usize::from(index.index()))
181 .filter(|version| version.valid)
182 .read_error("Invalid ELF symbol version index")
183 .map(Some)
184 }
185
186 /// Return true if the given symbol index satisfies the requirements of `need`.
187 ///
188 /// Returns false for any error.
189 ///
190 /// Note: this function hasn't been fully tested and is likely to be incomplete.
191 pub fn matches(&self, endian: Elf::Endian, index: usize, need: Option<&Version<'_>>) -> bool {
192 let version_index = self.version_index(endian, index);
193 let def = match self.version(version_index) {
194 Ok(def) => def,
195 Err(_) => return false,
196 };
197 match (def, need) {
198 (Some(def), Some(need)) => need.hash == def.hash && need.name == def.name,
199 (None, Some(_need)) => {
200 // Version must be present if needed.
201 false
202 }
203 (Some(_def), None) => {
204 // For a dlsym call, use the newest version.
205 // TODO: if not a dlsym call, then use the oldest version.
206 !version_index.is_hidden()
207 }
208 (None, None) => true,
209 }
210 }
211 }
212
213 /// An iterator over the entries in an ELF `SHT_GNU_verdef` section.
214 #[derive(Debug, Clone)]
215 pub struct VerdefIterator<'data, Elf: FileHeader> {
216 endian: Elf::Endian,
217 data: Bytes<'data>,
218 }
219
220 impl<'data, Elf: FileHeader> VerdefIterator<'data, Elf> {
221 pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self {
222 VerdefIterator {
223 endian,
224 data: Bytes(data),
225 }
226 }
227
228 /// Return the next `Verdef` entry.
229 pub fn next(
230 &mut self,
231 ) -> Result<Option<(&'data elf::Verdef<Elf::Endian>, VerdauxIterator<'data, Elf>)>> {
232 if self.data.is_empty() {
233 return Ok(None);
234 }
235
236 let verdef = self
237 .data
238 .read_at::<elf::Verdef<_>>(0)
239 .read_error("ELF verdef is too short")?;
240
241 let mut verdaux_data = self.data;
242 verdaux_data
243 .skip(verdef.vd_aux.get(self.endian) as usize)
244 .read_error("Invalid ELF vd_aux")?;
245 let verdaux =
246 VerdauxIterator::new(self.endian, verdaux_data.0, verdef.vd_cnt.get(self.endian));
247
248 let next = verdef.vd_next.get(self.endian);
249 if next != 0 {
250 self.data
251 .skip(next as usize)
252 .read_error("Invalid ELF vd_next")?;
253 } else {
254 self.data = Bytes(&[]);
255 }
256 Ok(Some((verdef, verdaux)))
257 }
258 }
259
260 /// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verdef` section.
261 #[derive(Debug, Clone)]
262 pub struct VerdauxIterator<'data, Elf: FileHeader> {
263 endian: Elf::Endian,
264 data: Bytes<'data>,
265 count: u16,
266 }
267
268 impl<'data, Elf: FileHeader> VerdauxIterator<'data, Elf> {
269 pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self {
270 VerdauxIterator {
271 endian,
272 data: Bytes(data),
273 count,
274 }
275 }
276
277 /// Return the next `Verdaux` entry.
278 pub fn next(&mut self) -> Result<Option<&'data elf::Verdaux<Elf::Endian>>> {
279 if self.count == 0 {
280 return Ok(None);
281 }
282
283 let verdaux = self
284 .data
285 .read_at::<elf::Verdaux<_>>(0)
286 .read_error("ELF verdaux is too short")?;
287
288 self.data
289 .skip(verdaux.vda_next.get(self.endian) as usize)
290 .read_error("Invalid ELF vda_next")?;
291 self.count -= 1;
292 Ok(Some(verdaux))
293 }
294 }
295
296 /// An iterator over the entries in an ELF `SHT_GNU_verneed` section.
297 #[derive(Debug, Clone)]
298 pub struct VerneedIterator<'data, Elf: FileHeader> {
299 endian: Elf::Endian,
300 data: Bytes<'data>,
301 }
302
303 impl<'data, Elf: FileHeader> VerneedIterator<'data, Elf> {
304 pub(super) fn new(endian: Elf::Endian, data: &'data [u8]) -> Self {
305 VerneedIterator {
306 endian,
307 data: Bytes(data),
308 }
309 }
310
311 /// Return the next `Verneed` entry.
312 pub fn next(
313 &mut self,
314 ) -> Result<
315 Option<(
316 &'data elf::Verneed<Elf::Endian>,
317 VernauxIterator<'data, Elf>,
318 )>,
319 > {
320 if self.data.is_empty() {
321 return Ok(None);
322 }
323
324 let verneed = self
325 .data
326 .read_at::<elf::Verneed<_>>(0)
327 .read_error("ELF verneed is too short")?;
328
329 let mut vernaux_data = self.data;
330 vernaux_data
331 .skip(verneed.vn_aux.get(self.endian) as usize)
332 .read_error("Invalid ELF vn_aux")?;
333 let vernaux =
334 VernauxIterator::new(self.endian, vernaux_data.0, verneed.vn_cnt.get(self.endian));
335
336 let next = verneed.vn_next.get(self.endian);
337 if next != 0 {
338 self.data
339 .skip(next as usize)
340 .read_error("Invalid ELF vn_next")?;
341 } else {
342 self.data = Bytes(&[]);
343 }
344 Ok(Some((verneed, vernaux)))
345 }
346 }
347
348 /// An iterator over the auxiliary records for an entry in an ELF `SHT_GNU_verneed` section.
349 #[derive(Debug, Clone)]
350 pub struct VernauxIterator<'data, Elf: FileHeader> {
351 endian: Elf::Endian,
352 data: Bytes<'data>,
353 count: u16,
354 }
355
356 impl<'data, Elf: FileHeader> VernauxIterator<'data, Elf> {
357 pub(super) fn new(endian: Elf::Endian, data: &'data [u8], count: u16) -> Self {
358 VernauxIterator {
359 endian,
360 data: Bytes(data),
361 count,
362 }
363 }
364
365 /// Return the next `Vernaux` entry.
366 pub fn next(&mut self) -> Result<Option<&'data elf::Vernaux<Elf::Endian>>> {
367 if self.count == 0 {
368 return Ok(None);
369 }
370
371 let vernaux = self
372 .data
373 .read_at::<elf::Vernaux<_>>(0)
374 .read_error("ELF vernaux is too short")?;
375
376 self.data
377 .skip(vernaux.vna_next.get(self.endian) as usize)
378 .read_error("Invalid ELF vna_next")?;
379 self.count -= 1;
380 Ok(Some(vernaux))
381 }
382 }
383
384 impl<Endian: endian::Endian> elf::Verdaux<Endian> {
385 /// Parse the version name from the string table.
386 pub fn name<'data, R: ReadRef<'data>>(
387 &self,
388 endian: Endian,
389 strings: StringTable<'data, R>,
390 ) -> Result<&'data [u8]> {
391 strings
392 .get(self.vda_name.get(endian))
393 .read_error("Invalid ELF vda_name")
394 }
395 }
396
397 impl<Endian: endian::Endian> elf::Verneed<Endian> {
398 /// Parse the file from the string table.
399 pub fn file<'data, R: ReadRef<'data>>(
400 &self,
401 endian: Endian,
402 strings: StringTable<'data, R>,
403 ) -> Result<&'data [u8]> {
404 strings
405 .get(self.vn_file.get(endian))
406 .read_error("Invalid ELF vn_file")
407 }
408 }
409
410 impl<Endian: endian::Endian> elf::Vernaux<Endian> {
411 /// Parse the version name from the string table.
412 pub fn name<'data, R: ReadRef<'data>>(
413 &self,
414 endian: Endian,
415 strings: StringTable<'data, R>,
416 ) -> Result<&'data [u8]> {
417 strings
418 .get(self.vna_name.get(endian))
419 .read_error("Invalid ELF vna_name")
420 }
421 }