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