]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.26.2/src/read/elf/symbol.rs
New upstream version 1.66.0+dfsg1
[rustc.git] / vendor / object-0.26.2 / src / read / elf / symbol.rs
1 use alloc::fmt;
2 use alloc::vec::Vec;
3 use core::fmt::Debug;
4 use core::slice;
5 use core::str;
6
7 use crate::elf;
8 use crate::endian::{self, Endianness};
9 use crate::pod::Pod;
10 use crate::read::util::StringTable;
11 use crate::read::{
12 self, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, SectionIndex, SymbolFlags,
13 SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection,
14 };
15
16 use super::{FileHeader, SectionHeader, SectionTable};
17
18 /// A table of symbol entries in an ELF file.
19 ///
20 /// Also includes the string table used for the symbol names.
21 #[derive(Debug, Clone, Copy)]
22 pub struct SymbolTable<'data, Elf: FileHeader, R = &'data [u8]>
23 where
24 R: ReadRef<'data>,
25 {
26 section: usize,
27 symbols: &'data [Elf::Sym],
28 strings: StringTable<'data, R>,
29 shndx: &'data [u32],
30 }
31
32 impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Elf, R> {
33 fn default() -> Self {
34 SymbolTable {
35 section: 0,
36 symbols: &[],
37 strings: Default::default(),
38 shndx: &[],
39 }
40 }
41 }
42
43 impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> {
44 /// Parse the given symbol table section.
45 pub fn parse(
46 endian: Elf::Endian,
47 data: R,
48 sections: &SectionTable<'data, Elf, R>,
49 section_index: usize,
50 section: &Elf::SectionHeader,
51 ) -> read::Result<SymbolTable<'data, Elf, R>> {
52 debug_assert!(
53 section.sh_type(endian) == elf::SHT_DYNSYM
54 || section.sh_type(endian) == elf::SHT_SYMTAB
55 );
56
57 let symbols = section
58 .data_as_array(endian, data)
59 .read_error("Invalid ELF symbol table data")?;
60
61 let strtab = sections.section(section.sh_link(endian) as usize)?;
62 let strings = if let Some((str_offset, str_size)) = strtab.file_range(endian) {
63 let str_end = str_offset
64 .checked_add(str_size)
65 .read_error("Invalid str_size")?;
66 StringTable::new(data, str_offset, str_end)
67 } else {
68 StringTable::default()
69 };
70
71 let shndx = sections
72 .iter()
73 .find(|s| {
74 s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX
75 && s.sh_link(endian) as usize == section_index
76 })
77 .map(|section| {
78 section
79 .data_as_array(endian, data)
80 .read_error("Invalid ELF symtab_shndx data")
81 })
82 .transpose()?
83 .unwrap_or(&[]);
84
85 Ok(SymbolTable {
86 section: section_index,
87 symbols,
88 strings,
89 shndx,
90 })
91 }
92
93 /// Return the section index of this symbol table.
94 #[inline]
95 pub fn section(&self) -> usize {
96 self.section
97 }
98
99 /// Return the string table used for the symbol names.
100 #[inline]
101 pub fn strings(&self) -> StringTable<'data, R> {
102 self.strings
103 }
104
105 /// Return the symbol table.
106 #[inline]
107 pub fn symbols(&self) -> &'data [Elf::Sym] {
108 self.symbols
109 }
110
111 /// Iterate over the symbols.
112 #[inline]
113 pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> {
114 self.symbols.iter()
115 }
116
117 /// Return true if the symbol table is empty.
118 #[inline]
119 pub fn is_empty(&self) -> bool {
120 self.symbols.is_empty()
121 }
122
123 /// The number of symbols.
124 #[inline]
125 pub fn len(&self) -> usize {
126 self.symbols.len()
127 }
128
129 /// Return the symbol at the given index.
130 pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> {
131 self.symbols
132 .get(index)
133 .read_error("Invalid ELF symbol index")
134 }
135
136 /// Return the extended section index for the given symbol if present.
137 #[inline]
138 pub fn shndx(&self, index: usize) -> Option<u32> {
139 self.shndx.get(index).cloned()
140 }
141
142 /// Return the symbol name for the given symbol.
143 pub fn symbol_name(
144 &self,
145 endian: Elf::Endian,
146 symbol: &'data Elf::Sym,
147 ) -> read::Result<&'data [u8]> {
148 symbol.name(endian, self.strings)
149 }
150
151 /// Construct a map from addresses to a user-defined map entry.
152 pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Elf::Sym) -> Option<Entry>>(
153 &self,
154 endian: Elf::Endian,
155 f: F,
156 ) -> SymbolMap<Entry> {
157 let mut symbols = Vec::with_capacity(self.symbols.len());
158 for symbol in self.symbols {
159 if !symbol.is_definition(endian) {
160 continue;
161 }
162 if let Some(entry) = f(symbol) {
163 symbols.push(entry);
164 }
165 }
166 SymbolMap::new(symbols)
167 }
168 }
169
170 /// A symbol table of an `ElfFile32`.
171 pub type ElfSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
172 ElfSymbolTable<'data, 'file, elf::FileHeader32<Endian>, R>;
173 /// A symbol table of an `ElfFile32`.
174 pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
175 ElfSymbolTable<'data, 'file, elf::FileHeader64<Endian>, R>;
176
177 /// A symbol table of an `ElfFile`.
178 #[derive(Debug, Clone, Copy)]
179 pub struct ElfSymbolTable<'data, 'file, Elf, R = &'data [u8]>
180 where
181 'data: 'file,
182 Elf: FileHeader,
183 R: ReadRef<'data>,
184 {
185 pub(super) endian: Elf::Endian,
186 pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
187 }
188
189 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
190 for ElfSymbolTable<'data, 'file, Elf, R>
191 {
192 }
193
194 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
195 for ElfSymbolTable<'data, 'file, Elf, R>
196 {
197 type Symbol = ElfSymbol<'data, 'file, Elf, R>;
198 type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>;
199
200 fn symbols(&self) -> Self::SymbolIterator {
201 ElfSymbolIterator {
202 endian: self.endian,
203 symbols: self.symbols,
204 index: 0,
205 }
206 }
207
208 fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
209 let symbol = self.symbols.symbol(index.0)?;
210 Ok(ElfSymbol {
211 endian: self.endian,
212 symbols: self.symbols,
213 index,
214 symbol,
215 })
216 }
217 }
218
219 /// An iterator over the symbols of an `ElfFile32`.
220 pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
221 ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
222 /// An iterator over the symbols of an `ElfFile64`.
223 pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
224 ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
225
226 /// An iterator over the symbols of an `ElfFile`.
227 pub struct ElfSymbolIterator<'data, 'file, Elf, R = &'data [u8]>
228 where
229 'data: 'file,
230 Elf: FileHeader,
231 R: ReadRef<'data>,
232 {
233 pub(super) endian: Elf::Endian,
234 pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
235 pub(super) index: usize,
236 }
237
238 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> fmt::Debug
239 for ElfSymbolIterator<'data, 'file, Elf, R>
240 {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 f.debug_struct("ElfSymbolIterator").finish()
243 }
244 }
245
246 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> Iterator
247 for ElfSymbolIterator<'data, 'file, Elf, R>
248 {
249 type Item = ElfSymbol<'data, 'file, Elf, R>;
250
251 fn next(&mut self) -> Option<Self::Item> {
252 let index = self.index;
253 let symbol = self.symbols.symbols.get(index)?;
254 self.index += 1;
255 Some(ElfSymbol {
256 endian: self.endian,
257 symbols: self.symbols,
258 index: SymbolIndex(index),
259 symbol,
260 })
261 }
262 }
263
264 /// A symbol of an `ElfFile32`.
265 pub type ElfSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
266 ElfSymbol<'data, 'file, elf::FileHeader32<Endian>, R>;
267 /// A symbol of an `ElfFile64`.
268 pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
269 ElfSymbol<'data, 'file, elf::FileHeader64<Endian>, R>;
270
271 /// A symbol of an `ElfFile`.
272 #[derive(Debug, Clone, Copy)]
273 pub struct ElfSymbol<'data, 'file, Elf, R = &'data [u8]>
274 where
275 'data: 'file,
276 Elf: FileHeader,
277 R: ReadRef<'data>,
278 {
279 pub(super) endian: Elf::Endian,
280 pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
281 pub(super) index: SymbolIndex,
282 pub(super) symbol: &'data Elf::Sym,
283 }
284
285 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
286 for ElfSymbol<'data, 'file, Elf, R>
287 {
288 }
289
290 impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
291 for ElfSymbol<'data, 'file, Elf, R>
292 {
293 #[inline]
294 fn index(&self) -> SymbolIndex {
295 self.index
296 }
297
298 fn name(&self) -> read::Result<&'data str> {
299 let name = self.symbol.name(self.endian, self.symbols.strings())?;
300 str::from_utf8(name)
301 .ok()
302 .read_error("Non UTF-8 ELF symbol name")
303 }
304
305 #[inline]
306 fn address(&self) -> u64 {
307 self.symbol.st_value(self.endian).into()
308 }
309
310 #[inline]
311 fn size(&self) -> u64 {
312 self.symbol.st_size(self.endian).into()
313 }
314
315 fn kind(&self) -> SymbolKind {
316 match self.symbol.st_type() {
317 elf::STT_NOTYPE if self.index.0 == 0 => SymbolKind::Null,
318 elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data,
319 elf::STT_FUNC => SymbolKind::Text,
320 elf::STT_SECTION => SymbolKind::Section,
321 elf::STT_FILE => SymbolKind::File,
322 elf::STT_TLS => SymbolKind::Tls,
323 _ => SymbolKind::Unknown,
324 }
325 }
326
327 fn section(&self) -> SymbolSection {
328 match self.symbol.st_shndx(self.endian) {
329 elf::SHN_UNDEF => SymbolSection::Undefined,
330 elf::SHN_ABS => {
331 if self.symbol.st_type() == elf::STT_FILE {
332 SymbolSection::None
333 } else {
334 SymbolSection::Absolute
335 }
336 }
337 elf::SHN_COMMON => SymbolSection::Common,
338 elf::SHN_XINDEX => match self.symbols.shndx(self.index.0) {
339 Some(index) => SymbolSection::Section(SectionIndex(index as usize)),
340 None => SymbolSection::Unknown,
341 },
342 index if index < elf::SHN_LORESERVE => {
343 SymbolSection::Section(SectionIndex(index as usize))
344 }
345 _ => SymbolSection::Unknown,
346 }
347 }
348
349 #[inline]
350 fn is_undefined(&self) -> bool {
351 self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF
352 }
353
354 #[inline]
355 fn is_definition(&self) -> bool {
356 self.symbol.is_definition(self.endian)
357 }
358
359 #[inline]
360 fn is_common(&self) -> bool {
361 self.symbol.st_shndx(self.endian) == elf::SHN_COMMON
362 }
363
364 #[inline]
365 fn is_weak(&self) -> bool {
366 self.symbol.st_bind() == elf::STB_WEAK
367 }
368
369 fn scope(&self) -> SymbolScope {
370 if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF {
371 SymbolScope::Unknown
372 } else {
373 match self.symbol.st_bind() {
374 elf::STB_LOCAL => SymbolScope::Compilation,
375 elf::STB_GLOBAL | elf::STB_WEAK => {
376 if self.symbol.st_visibility() == elf::STV_HIDDEN {
377 SymbolScope::Linkage
378 } else {
379 SymbolScope::Dynamic
380 }
381 }
382 _ => SymbolScope::Unknown,
383 }
384 }
385 }
386
387 #[inline]
388 fn is_global(&self) -> bool {
389 self.symbol.st_bind() != elf::STB_LOCAL
390 }
391
392 #[inline]
393 fn is_local(&self) -> bool {
394 self.symbol.st_bind() == elf::STB_LOCAL
395 }
396
397 #[inline]
398 fn flags(&self) -> SymbolFlags<SectionIndex> {
399 SymbolFlags::Elf {
400 st_info: self.symbol.st_info(),
401 st_other: self.symbol.st_other(),
402 }
403 }
404 }
405
406 /// A trait for generic access to `Sym32` and `Sym64`.
407 #[allow(missing_docs)]
408 pub trait Sym: Debug + Pod {
409 type Word: Into<u64>;
410 type Endian: endian::Endian;
411
412 fn st_name(&self, endian: Self::Endian) -> u32;
413 fn st_info(&self) -> u8;
414 fn st_bind(&self) -> u8;
415 fn st_type(&self) -> u8;
416 fn st_other(&self) -> u8;
417 fn st_visibility(&self) -> u8;
418 fn st_shndx(&self, endian: Self::Endian) -> u16;
419 fn st_value(&self, endian: Self::Endian) -> Self::Word;
420 fn st_size(&self, endian: Self::Endian) -> Self::Word;
421
422 /// Parse the symbol name from the string table.
423 fn name<'data, R: ReadRef<'data>>(
424 &self,
425 endian: Self::Endian,
426 strings: StringTable<'data, R>,
427 ) -> read::Result<&'data [u8]> {
428 strings
429 .get(self.st_name(endian))
430 .read_error("Invalid ELF symbol name offset")
431 }
432
433 /// Return true if the symbol is undefined.
434 #[inline]
435 fn is_undefined(&self, endian: Self::Endian) -> bool {
436 self.st_shndx(endian) == elf::SHN_UNDEF
437 }
438
439 /// Return true if the symbol is a definition of a function or data object.
440 fn is_definition(&self, endian: Self::Endian) -> bool {
441 let st_type = self.st_type();
442 (st_type == elf::STT_NOTYPE || st_type == elf::STT_FUNC || st_type == elf::STT_OBJECT)
443 && self.st_shndx(endian) != elf::SHN_UNDEF
444 }
445 }
446
447 impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> {
448 type Word = u32;
449 type Endian = Endian;
450
451 #[inline]
452 fn st_name(&self, endian: Self::Endian) -> u32 {
453 self.st_name.get(endian)
454 }
455
456 #[inline]
457 fn st_info(&self) -> u8 {
458 self.st_info
459 }
460
461 #[inline]
462 fn st_bind(&self) -> u8 {
463 self.st_bind()
464 }
465
466 #[inline]
467 fn st_type(&self) -> u8 {
468 self.st_type()
469 }
470
471 #[inline]
472 fn st_other(&self) -> u8 {
473 self.st_other
474 }
475
476 #[inline]
477 fn st_visibility(&self) -> u8 {
478 self.st_visibility()
479 }
480
481 #[inline]
482 fn st_shndx(&self, endian: Self::Endian) -> u16 {
483 self.st_shndx.get(endian)
484 }
485
486 #[inline]
487 fn st_value(&self, endian: Self::Endian) -> Self::Word {
488 self.st_value.get(endian)
489 }
490
491 #[inline]
492 fn st_size(&self, endian: Self::Endian) -> Self::Word {
493 self.st_size.get(endian)
494 }
495 }
496
497 impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> {
498 type Word = u64;
499 type Endian = Endian;
500
501 #[inline]
502 fn st_name(&self, endian: Self::Endian) -> u32 {
503 self.st_name.get(endian)
504 }
505
506 #[inline]
507 fn st_info(&self) -> u8 {
508 self.st_info
509 }
510
511 #[inline]
512 fn st_bind(&self) -> u8 {
513 self.st_bind()
514 }
515
516 #[inline]
517 fn st_type(&self) -> u8 {
518 self.st_type()
519 }
520
521 #[inline]
522 fn st_other(&self) -> u8 {
523 self.st_other
524 }
525
526 #[inline]
527 fn st_visibility(&self) -> u8 {
528 self.st_visibility()
529 }
530
531 #[inline]
532 fn st_shndx(&self, endian: Self::Endian) -> u16 {
533 self.st_shndx.get(endian)
534 }
535
536 #[inline]
537 fn st_value(&self, endian: Self::Endian) -> Self::Word {
538 self.st_value.get(endian)
539 }
540
541 #[inline]
542 fn st_size(&self, endian: Self::Endian) -> Self::Word {
543 self.st_size.get(endian)
544 }
545 }