1use alloc::fmt;
2use alloc::vec::Vec;
3use core::fmt::Debug;
4use core::slice;
5use core::str;
6
7use crate::elf;
8use crate::endian::{self, Endianness, U32};
9use crate::pod::Pod;
10use crate::read::util::StringTable;
11use crate::read::{
12 self, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, SectionIndex, SymbolFlags,
13 SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection,
14};
15
16use super::{FileHeader, SectionHeader, SectionTable};
17
18#[derive(Debug, Clone, Copy)]
24pub struct SymbolTable<'data, Elf: FileHeader, R = &'data [u8]>
25where
26 R: ReadRef<'data>,
27{
28 section: SectionIndex,
29 string_section: SectionIndex,
30 shndx_section: SectionIndex,
31 symbols: &'data [Elf::Sym],
32 strings: StringTable<'data, R>,
33 shndx: &'data [U32<Elf::Endian>],
34}
35
36impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for SymbolTable<'data, Elf, R> {
37 fn default() -> Self {
38 SymbolTable {
39 section: SectionIndex(0),
40 string_section: SectionIndex(0),
41 shndx_section: SectionIndex(0),
42 symbols: &[],
43 strings: Default::default(),
44 shndx: &[],
45 }
46 }
47}
48
49impl<'data, Elf: FileHeader, R: ReadRef<'data>> SymbolTable<'data, Elf, R> {
50 pub fn parse(
52 endian: Elf::Endian,
53 data: R,
54 sections: &SectionTable<'data, Elf, R>,
55 section_index: SectionIndex,
56 section: &Elf::SectionHeader,
57 ) -> read::Result<SymbolTable<'data, Elf, R>> {
58 debug_assert!(
59 section.sh_type(endian) == elf::SHT_DYNSYM
60 || section.sh_type(endian) == elf::SHT_SYMTAB
61 );
62
63 let symbols = section
64 .data_as_array(endian, data)
65 .read_error("Invalid ELF symbol table data")?;
66
67 let link = SectionIndex(section.sh_link(endian) as usize);
68 let strings = sections.strings(endian, data, link)?;
69
70 let mut shndx_section = SectionIndex(0);
71 let mut shndx = &[][..];
72 for (i, s) in sections.enumerate() {
73 if s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX && s.link(endian) == section_index {
74 shndx_section = 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 #[inline]
93 pub fn section(&self) -> SectionIndex {
94 self.section
95 }
96
97 #[inline]
99 pub fn shndx_section(&self) -> SectionIndex {
100 self.shndx_section
101 }
102
103 #[inline]
105 pub fn string_section(&self) -> SectionIndex {
106 self.string_section
107 }
108
109 #[inline]
111 pub fn strings(&self) -> StringTable<'data, R> {
112 self.strings
113 }
114
115 #[inline]
117 pub fn symbols(&self) -> &'data [Elf::Sym] {
118 self.symbols
119 }
120
121 #[inline]
125 pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> {
126 self.symbols.iter()
127 }
128
129 #[inline]
133 pub fn enumerate(&self) -> impl Iterator<Item = (SymbolIndex, &'data Elf::Sym)> {
134 self.symbols
135 .iter()
136 .enumerate()
137 .map(|(i, sym)| (SymbolIndex(i), sym))
138 }
139
140 #[inline]
142 pub fn is_empty(&self) -> bool {
143 self.symbols.is_empty()
144 }
145
146 #[inline]
148 pub fn len(&self) -> usize {
149 self.symbols.len()
150 }
151
152 pub fn symbol(&self, index: SymbolIndex) -> read::Result<&'data Elf::Sym> {
156 if index == SymbolIndex(0) {
157 return Err(read::Error("Invalid ELF symbol index"));
158 }
159 self.symbols
160 .get(index.0)
161 .read_error("Invalid ELF symbol index")
162 }
163
164 #[inline]
166 pub fn shndx(&self, endian: Elf::Endian, index: SymbolIndex) -> Option<u32> {
167 self.shndx.get(index.0).map(|x| x.get(endian))
168 }
169
170 pub fn symbol_section(
174 &self,
175 endian: Elf::Endian,
176 symbol: &Elf::Sym,
177 index: SymbolIndex,
178 ) -> read::Result<Option<SectionIndex>> {
179 match symbol.st_shndx(endian) {
180 elf::SHN_UNDEF => Ok(None),
181 elf::SHN_XINDEX => {
182 let shndx = self
183 .shndx(endian, index)
184 .read_error("Missing ELF symbol extended index")?;
185 if shndx == 0 {
186 Ok(None)
187 } else {
188 Ok(Some(SectionIndex(shndx as usize)))
189 }
190 }
191 shndx if shndx < elf::SHN_LORESERVE => Ok(Some(SectionIndex(shndx.into()))),
192 _ => Ok(None),
193 }
194 }
195
196 pub fn symbol_name(&self, endian: Elf::Endian, symbol: &Elf::Sym) -> read::Result<&'data [u8]> {
198 symbol.name(endian, self.strings)
199 }
200
201 pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Elf::Sym) -> Option<Entry>>(
203 &self,
204 endian: Elf::Endian,
205 f: F,
206 ) -> SymbolMap<Entry> {
207 let mut symbols = Vec::with_capacity(self.symbols.len());
208 for symbol in self.symbols {
209 if !symbol.is_definition(endian, self.strings) {
210 continue;
211 }
212 if let Some(entry) = f(symbol) {
213 symbols.push(entry);
214 }
215 }
216 SymbolMap::new(symbols)
217 }
218}
219
220pub type ElfSymbolTable32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
222 ElfSymbolTable<'data, 'file, elf::FileHeader32<Endian>, R>;
223pub type ElfSymbolTable64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
225 ElfSymbolTable<'data, 'file, elf::FileHeader64<Endian>, R>;
226
227#[derive(Debug, Clone, Copy)]
229pub struct ElfSymbolTable<'data, 'file, Elf, R = &'data [u8]>
230where
231 Elf: FileHeader,
232 R: ReadRef<'data>,
233{
234 pub(super) endian: Elf::Endian,
235 pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
236}
237
238impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
239 for ElfSymbolTable<'data, 'file, Elf, R>
240{
241}
242
243impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
244 for ElfSymbolTable<'data, 'file, Elf, R>
245{
246 type Symbol = ElfSymbol<'data, 'file, Elf, R>;
247 type SymbolIterator = ElfSymbolIterator<'data, 'file, Elf, R>;
248
249 fn symbols(&self) -> Self::SymbolIterator {
250 ElfSymbolIterator::new(self.endian, self.symbols)
251 }
252
253 fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
254 let symbol = self.symbols.symbol(index)?;
255 Ok(ElfSymbol {
256 endian: self.endian,
257 symbols: self.symbols,
258 index,
259 symbol,
260 })
261 }
262}
263
264pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
266 ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
267pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
269 ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
270
271pub struct ElfSymbolIterator<'data, 'file, Elf, R = &'data [u8]>
273where
274 Elf: FileHeader,
275 R: ReadRef<'data>,
276{
277 endian: Elf::Endian,
278 symbols: &'file SymbolTable<'data, Elf, R>,
279 index: SymbolIndex,
280}
281
282impl<'data, 'file, Elf, R> ElfSymbolIterator<'data, 'file, Elf, R>
283where
284 Elf: FileHeader,
285 R: ReadRef<'data>,
286{
287 pub(super) fn new(endian: Elf::Endian, symbols: &'file SymbolTable<'data, Elf, R>) -> Self {
288 ElfSymbolIterator {
289 endian,
290 symbols,
291 index: SymbolIndex(1),
292 }
293 }
294}
295
296impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> fmt::Debug
297 for ElfSymbolIterator<'data, 'file, Elf, R>
298{
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 f.debug_struct("ElfSymbolIterator").finish()
301 }
302}
303
304impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> Iterator
305 for ElfSymbolIterator<'data, 'file, Elf, R>
306{
307 type Item = ElfSymbol<'data, 'file, Elf, R>;
308
309 fn next(&mut self) -> Option<Self::Item> {
310 let index = self.index;
311 let symbol = self.symbols.symbols.get(index.0)?;
312 self.index.0 += 1;
313 Some(ElfSymbol {
314 endian: self.endian,
315 symbols: self.symbols,
316 index,
317 symbol,
318 })
319 }
320}
321
322pub type ElfSymbol32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
324 ElfSymbol<'data, 'file, elf::FileHeader32<Endian>, R>;
325pub type ElfSymbol64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
327 ElfSymbol<'data, 'file, elf::FileHeader64<Endian>, R>;
328
329#[derive(Debug, Clone, Copy)]
333pub struct ElfSymbol<'data, 'file, Elf, R = &'data [u8]>
334where
335 Elf: FileHeader,
336 R: ReadRef<'data>,
337{
338 pub(super) endian: Elf::Endian,
339 pub(super) symbols: &'file SymbolTable<'data, Elf, R>,
340 pub(super) index: SymbolIndex,
341 pub(super) symbol: &'data Elf::Sym,
342}
343
344impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSymbol<'data, 'file, Elf, R> {
345 pub fn endian(&self) -> Elf::Endian {
347 self.endian
348 }
349
350 #[inline]
352 #[deprecated(note = "Use `elf_symbol` instead")]
353 pub fn raw_symbol(&self) -> &'data Elf::Sym {
354 self.symbol
355 }
356
357 pub fn elf_symbol(&self) -> &'data Elf::Sym {
359 self.symbol
360 }
361}
362
363impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> read::private::Sealed
364 for ElfSymbol<'data, 'file, Elf, R>
365{
366}
367
368impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
369 for ElfSymbol<'data, 'file, Elf, R>
370{
371 #[inline]
372 fn index(&self) -> SymbolIndex {
373 self.index
374 }
375
376 fn name_bytes(&self) -> read::Result<&'data [u8]> {
377 self.symbol.name(self.endian, self.symbols.strings())
378 }
379
380 fn name(&self) -> read::Result<&'data str> {
381 let name = self.name_bytes()?;
382 str::from_utf8(name)
383 .ok()
384 .read_error("Non UTF-8 ELF symbol name")
385 }
386
387 #[inline]
388 fn address(&self) -> u64 {
389 self.symbol.st_value(self.endian).into()
390 }
391
392 #[inline]
393 fn size(&self) -> u64 {
394 self.symbol.st_size(self.endian).into()
395 }
396
397 fn kind(&self) -> SymbolKind {
398 match self.symbol.st_type() {
399 elf::STT_NOTYPE => SymbolKind::Unknown,
400 elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data,
401 elf::STT_FUNC | elf::STT_GNU_IFUNC => SymbolKind::Text,
402 elf::STT_SECTION => SymbolKind::Section,
403 elf::STT_FILE => SymbolKind::File,
404 elf::STT_TLS => SymbolKind::Tls,
405 _ => SymbolKind::Unknown,
406 }
407 }
408
409 fn section(&self) -> SymbolSection {
410 match self.symbol.st_shndx(self.endian) {
411 elf::SHN_UNDEF => SymbolSection::Undefined,
412 elf::SHN_ABS => {
413 if self.symbol.st_type() == elf::STT_FILE {
414 SymbolSection::None
415 } else {
416 SymbolSection::Absolute
417 }
418 }
419 elf::SHN_COMMON => SymbolSection::Common,
420 elf::SHN_XINDEX => match self.symbols.shndx(self.endian, self.index) {
421 Some(0) => SymbolSection::None,
422 Some(index) => SymbolSection::Section(SectionIndex(index as usize)),
423 None => SymbolSection::Unknown,
424 },
425 index if index < elf::SHN_LORESERVE => {
426 SymbolSection::Section(SectionIndex(index as usize))
427 }
428 _ => SymbolSection::Unknown,
429 }
430 }
431
432 #[inline]
433 fn is_undefined(&self) -> bool {
434 self.symbol.is_undefined(self.endian)
435 }
436
437 #[inline]
438 fn is_definition(&self) -> bool {
439 self.symbol
440 .is_definition(self.endian, self.symbols.strings())
441 }
442
443 #[inline]
444 fn is_common(&self) -> bool {
445 self.symbol.is_common(self.endian)
446 }
447
448 #[inline]
449 fn is_weak(&self) -> bool {
450 self.symbol.is_weak()
451 }
452
453 fn scope(&self) -> SymbolScope {
454 if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF {
455 SymbolScope::Unknown
456 } else {
457 match self.symbol.st_bind() {
458 elf::STB_LOCAL => SymbolScope::Compilation,
459 elf::STB_GLOBAL | elf::STB_WEAK => {
460 if self.symbol.st_visibility() == elf::STV_HIDDEN {
461 SymbolScope::Linkage
462 } else {
463 SymbolScope::Dynamic
464 }
465 }
466 _ => SymbolScope::Unknown,
467 }
468 }
469 }
470
471 #[inline]
472 fn is_global(&self) -> bool {
473 !self.symbol.is_local()
474 }
475
476 #[inline]
477 fn is_local(&self) -> bool {
478 self.symbol.is_local()
479 }
480
481 #[inline]
482 fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
483 SymbolFlags::Elf {
484 st_info: self.symbol.st_info(),
485 st_other: self.symbol.st_other(),
486 }
487 }
488}
489
490#[allow(missing_docs)]
492pub trait Sym: Debug + Pod {
493 type Word: Into<u64>;
494 type Endian: endian::Endian;
495
496 fn st_name(&self, endian: Self::Endian) -> u32;
497 fn st_info(&self) -> u8;
498 fn st_bind(&self) -> u8;
499 fn st_type(&self) -> u8;
500 fn st_other(&self) -> u8;
501 fn st_visibility(&self) -> u8;
502 fn st_shndx(&self, endian: Self::Endian) -> u16;
503 fn st_value(&self, endian: Self::Endian) -> Self::Word;
504 fn st_size(&self, endian: Self::Endian) -> Self::Word;
505
506 fn name<'data, R: ReadRef<'data>>(
508 &self,
509 endian: Self::Endian,
510 strings: StringTable<'data, R>,
511 ) -> read::Result<&'data [u8]> {
512 strings
513 .get(self.st_name(endian))
514 .read_error("Invalid ELF symbol name offset")
515 }
516
517 #[inline]
519 fn is_undefined(&self, endian: Self::Endian) -> bool {
520 self.st_shndx(endian) == elf::SHN_UNDEF
521 }
522
523 fn is_definition<'data, R: ReadRef<'data>>(
525 &self,
526 endian: Self::Endian,
527 strings: StringTable<'data, R>,
528 ) -> bool {
529 let shndx = self.st_shndx(endian);
530 if shndx == elf::SHN_UNDEF || (shndx >= elf::SHN_LORESERVE && shndx != elf::SHN_XINDEX) {
531 return false;
532 }
533 match self.st_type() {
534 elf::STT_NOTYPE if self.st_bind() == elf::STB_LOCAL => {
535 let Ok(name) = self.name(endian, strings) else {
537 return true;
540 };
541 !name.starts_with(b"$")
542 }
543 elf::STT_FUNC | elf::STT_OBJECT | elf::STT_NOTYPE => true,
544 _ => false,
545 }
546 }
547
548 fn is_common(&self, endian: Self::Endian) -> bool {
550 self.st_shndx(endian) == elf::SHN_COMMON
551 }
552
553 fn is_absolute(&self, endian: Self::Endian) -> bool {
555 self.st_shndx(endian) == elf::SHN_ABS
556 }
557
558 fn is_local(&self) -> bool {
560 self.st_bind() == elf::STB_LOCAL
561 }
562
563 fn is_weak(&self) -> bool {
565 self.st_bind() == elf::STB_WEAK
566 }
567}
568
569impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> {
570 type Word = u32;
571 type Endian = Endian;
572
573 #[inline]
574 fn st_name(&self, endian: Self::Endian) -> u32 {
575 self.st_name.get(endian)
576 }
577
578 #[inline]
579 fn st_info(&self) -> u8 {
580 self.st_info
581 }
582
583 #[inline]
584 fn st_bind(&self) -> u8 {
585 self.st_bind()
586 }
587
588 #[inline]
589 fn st_type(&self) -> u8 {
590 self.st_type()
591 }
592
593 #[inline]
594 fn st_other(&self) -> u8 {
595 self.st_other
596 }
597
598 #[inline]
599 fn st_visibility(&self) -> u8 {
600 self.st_visibility()
601 }
602
603 #[inline]
604 fn st_shndx(&self, endian: Self::Endian) -> u16 {
605 self.st_shndx.get(endian)
606 }
607
608 #[inline]
609 fn st_value(&self, endian: Self::Endian) -> Self::Word {
610 self.st_value.get(endian)
611 }
612
613 #[inline]
614 fn st_size(&self, endian: Self::Endian) -> Self::Word {
615 self.st_size.get(endian)
616 }
617}
618
619impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> {
620 type Word = u64;
621 type Endian = Endian;
622
623 #[inline]
624 fn st_name(&self, endian: Self::Endian) -> u32 {
625 self.st_name.get(endian)
626 }
627
628 #[inline]
629 fn st_info(&self) -> u8 {
630 self.st_info
631 }
632
633 #[inline]
634 fn st_bind(&self) -> u8 {
635 self.st_bind()
636 }
637
638 #[inline]
639 fn st_type(&self) -> u8 {
640 self.st_type()
641 }
642
643 #[inline]
644 fn st_other(&self) -> u8 {
645 self.st_other
646 }
647
648 #[inline]
649 fn st_visibility(&self) -> u8 {
650 self.st_visibility()
651 }
652
653 #[inline]
654 fn st_shndx(&self, endian: Self::Endian) -> u16 {
655 self.st_shndx.get(endian)
656 }
657
658 #[inline]
659 fn st_value(&self, endian: Self::Endian) -> Self::Word {
660 self.st_value.get(endian)
661 }
662
663 #[inline]
664 fn st_size(&self, endian: Self::Endian) -> Self::Word {
665 self.st_size.get(endian)
666 }
667}