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