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) {
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.is_definition(self.endian)
440 }
441
442 #[inline]
443 fn is_common(&self) -> bool {
444 self.symbol.is_common(self.endian)
445 }
446
447 #[inline]
448 fn is_weak(&self) -> bool {
449 self.symbol.is_weak()
450 }
451
452 fn scope(&self) -> SymbolScope {
453 if self.symbol.st_shndx(self.endian) == elf::SHN_UNDEF {
454 SymbolScope::Unknown
455 } else {
456 match self.symbol.st_bind() {
457 elf::STB_LOCAL => SymbolScope::Compilation,
458 elf::STB_GLOBAL | elf::STB_WEAK => {
459 if self.symbol.st_visibility() == elf::STV_HIDDEN {
460 SymbolScope::Linkage
461 } else {
462 SymbolScope::Dynamic
463 }
464 }
465 _ => SymbolScope::Unknown,
466 }
467 }
468 }
469
470 #[inline]
471 fn is_global(&self) -> bool {
472 !self.symbol.is_local()
473 }
474
475 #[inline]
476 fn is_local(&self) -> bool {
477 self.symbol.is_local()
478 }
479
480 #[inline]
481 fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
482 SymbolFlags::Elf {
483 st_info: self.symbol.st_info(),
484 st_other: self.symbol.st_other(),
485 }
486 }
487}
488
489#[allow(missing_docs)]
491pub trait Sym: Debug + Pod {
492 type Word: Into<u64>;
493 type Endian: endian::Endian;
494
495 fn st_name(&self, endian: Self::Endian) -> u32;
496 fn st_info(&self) -> u8;
497 fn st_bind(&self) -> u8;
498 fn st_type(&self) -> u8;
499 fn st_other(&self) -> u8;
500 fn st_visibility(&self) -> u8;
501 fn st_shndx(&self, endian: Self::Endian) -> u16;
502 fn st_value(&self, endian: Self::Endian) -> Self::Word;
503 fn st_size(&self, endian: Self::Endian) -> Self::Word;
504
505 fn name<'data, R: ReadRef<'data>>(
507 &self,
508 endian: Self::Endian,
509 strings: StringTable<'data, R>,
510 ) -> read::Result<&'data [u8]> {
511 strings
512 .get(self.st_name(endian))
513 .read_error("Invalid ELF symbol name offset")
514 }
515
516 #[inline]
518 fn is_undefined(&self, endian: Self::Endian) -> bool {
519 self.st_shndx(endian) == elf::SHN_UNDEF
520 }
521
522 fn is_definition(&self, endian: Self::Endian) -> bool {
524 let shndx = self.st_shndx(endian);
525 if shndx == elf::SHN_UNDEF || (shndx >= elf::SHN_LORESERVE && shndx != elf::SHN_XINDEX) {
526 return false;
527 }
528 match self.st_type() {
529 elf::STT_NOTYPE => self.st_size(endian).into() != 0,
530 elf::STT_FUNC | elf::STT_OBJECT => true,
531 _ => false,
532 }
533 }
534
535 fn is_common(&self, endian: Self::Endian) -> bool {
537 self.st_shndx(endian) == elf::SHN_COMMON
538 }
539
540 fn is_absolute(&self, endian: Self::Endian) -> bool {
542 self.st_shndx(endian) == elf::SHN_ABS
543 }
544
545 fn is_local(&self) -> bool {
547 self.st_bind() == elf::STB_LOCAL
548 }
549
550 fn is_weak(&self) -> bool {
552 self.st_bind() == elf::STB_WEAK
553 }
554}
555
556impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> {
557 type Word = u32;
558 type Endian = Endian;
559
560 #[inline]
561 fn st_name(&self, endian: Self::Endian) -> u32 {
562 self.st_name.get(endian)
563 }
564
565 #[inline]
566 fn st_info(&self) -> u8 {
567 self.st_info
568 }
569
570 #[inline]
571 fn st_bind(&self) -> u8 {
572 self.st_bind()
573 }
574
575 #[inline]
576 fn st_type(&self) -> u8 {
577 self.st_type()
578 }
579
580 #[inline]
581 fn st_other(&self) -> u8 {
582 self.st_other
583 }
584
585 #[inline]
586 fn st_visibility(&self) -> u8 {
587 self.st_visibility()
588 }
589
590 #[inline]
591 fn st_shndx(&self, endian: Self::Endian) -> u16 {
592 self.st_shndx.get(endian)
593 }
594
595 #[inline]
596 fn st_value(&self, endian: Self::Endian) -> Self::Word {
597 self.st_value.get(endian)
598 }
599
600 #[inline]
601 fn st_size(&self, endian: Self::Endian) -> Self::Word {
602 self.st_size.get(endian)
603 }
604}
605
606impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> {
607 type Word = u64;
608 type Endian = Endian;
609
610 #[inline]
611 fn st_name(&self, endian: Self::Endian) -> u32 {
612 self.st_name.get(endian)
613 }
614
615 #[inline]
616 fn st_info(&self) -> u8 {
617 self.st_info
618 }
619
620 #[inline]
621 fn st_bind(&self) -> u8 {
622 self.st_bind()
623 }
624
625 #[inline]
626 fn st_type(&self) -> u8 {
627 self.st_type()
628 }
629
630 #[inline]
631 fn st_other(&self) -> u8 {
632 self.st_other
633 }
634
635 #[inline]
636 fn st_visibility(&self) -> u8 {
637 self.st_visibility()
638 }
639
640 #[inline]
641 fn st_shndx(&self, endian: Self::Endian) -> u16 {
642 self.st_shndx.get(endian)
643 }
644
645 #[inline]
646 fn st_value(&self, endian: Self::Endian) -> Self::Word {
647 self.st_value.get(endian)
648 }
649
650 #[inline]
651 fn st_size(&self, endian: Self::Endian) -> Self::Word {
652 self.st_size.get(endian)
653 }
654}