]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.20.0/src/read/elf/symbol.rs
New upstream version 1.49.0+dfsg1
[rustc.git] / vendor / object-0.20.0 / src / read / elf / symbol.rs
1 use alloc::fmt;
2 use core::fmt::Debug;
3 use core::slice;
4 use core::str;
5
6 use crate::elf;
7 use crate::endian::{self, Endianness};
8 use crate::pod::{Bytes, Pod};
9 use crate::read::util::StringTable;
10 use crate::read::{
11 self, ReadError, SectionIndex, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope,
12 SymbolSection,
13 };
14
15 use super::{ElfFile, FileHeader, SectionHeader, SectionTable};
16
17 /// A table of symbol entries in an ELF file.
18 ///
19 /// Also includes the string table used for the symbol names.
20 #[derive(Debug, Clone, Copy)]
21 pub struct SymbolTable<'data, Elf: FileHeader> {
22 section: usize,
23 symbols: &'data [Elf::Sym],
24 strings: StringTable<'data>,
25 shndx: &'data [u32],
26 }
27
28 impl<'data, Elf: FileHeader> Default for SymbolTable<'data, Elf> {
29 fn default() -> Self {
30 SymbolTable {
31 section: 0,
32 symbols: &[],
33 strings: Default::default(),
34 shndx: &[],
35 }
36 }
37 }
38
39 impl<'data, Elf: FileHeader> SymbolTable<'data, Elf> {
40 /// Parse the symbol table of the given section type.
41 ///
42 /// Returns an empty symbol table if the symbol table does not exist.
43 pub fn parse(
44 endian: Elf::Endian,
45 data: Bytes<'data>,
46 sections: &SectionTable<Elf>,
47 sh_type: u32,
48 ) -> read::Result<SymbolTable<'data, Elf>> {
49 debug_assert!(sh_type == elf::SHT_DYNSYM || sh_type == elf::SHT_SYMTAB);
50
51 let (section, symtab) = match sections
52 .iter()
53 .enumerate()
54 .find(|s| s.1.sh_type(endian) == sh_type)
55 {
56 Some(s) => s,
57 None => return Ok(SymbolTable::default()),
58 };
59 let symbols = symtab
60 .data_as_array(endian, data)
61 .read_error("Invalid ELF symbol table data")?;
62
63 let strtab = sections.section(symtab.sh_link(endian) as usize)?;
64 let strtab_data = strtab
65 .data(endian, data)
66 .read_error("Invalid ELF string table data")?;
67 let strings = StringTable::new(strtab_data);
68
69 let shndx = sections
70 .iter()
71 .find(|s| {
72 s.sh_type(endian) == elf::SHT_SYMTAB_SHNDX && s.sh_link(endian) as usize == section
73 })
74 .map(|section| {
75 section
76 .data_as_array(endian, data)
77 .read_error("Invalid ELF symtab_shndx data")
78 })
79 .transpose()?
80 .unwrap_or(&[]);
81
82 Ok(SymbolTable {
83 section,
84 symbols,
85 strings,
86 shndx,
87 })
88 }
89
90 /// Return the section index of this symbol table.
91 #[inline]
92 pub fn section(&self) -> usize {
93 self.section
94 }
95
96 /// Return the string table used for the symbol names.
97 #[inline]
98 pub fn strings(&self) -> StringTable<'data> {
99 self.strings
100 }
101
102 /// Iterate over the symbols.
103 #[inline]
104 pub fn iter(&self) -> slice::Iter<'data, Elf::Sym> {
105 self.symbols.iter()
106 }
107
108 /// Return true if the symbol table is empty.
109 #[inline]
110 pub fn is_empty(&self) -> bool {
111 self.symbols.is_empty()
112 }
113
114 /// Return the symbol at the given index.
115 pub fn symbol(&self, index: usize) -> read::Result<&'data Elf::Sym> {
116 self.symbols
117 .get(index)
118 .read_error("Invalid ELF symbol index")
119 }
120
121 /// Return the extended section index for the given symbol if present.
122 #[inline]
123 pub fn shndx(&self, index: usize) -> Option<u32> {
124 self.shndx.get(index).cloned()
125 }
126 }
127
128 /// An iterator over the symbols of an `ElfFile32`.
129 pub type ElfSymbolIterator32<'data, 'file, Endian = Endianness> =
130 ElfSymbolIterator<'data, 'file, elf::FileHeader32<Endian>>;
131 /// An iterator over the symbols of an `ElfFile64`.
132 pub type ElfSymbolIterator64<'data, 'file, Endian = Endianness> =
133 ElfSymbolIterator<'data, 'file, elf::FileHeader64<Endian>>;
134
135 /// An iterator over the symbols of an `ElfFile`.
136 pub struct ElfSymbolIterator<'data, 'file, Elf>
137 where
138 'data: 'file,
139 Elf: FileHeader,
140 {
141 pub(super) file: &'file ElfFile<'data, Elf>,
142 pub(super) symbols: SymbolTable<'data, Elf>,
143 pub(super) index: usize,
144 }
145
146 impl<'data, 'file, Elf: FileHeader> fmt::Debug for ElfSymbolIterator<'data, 'file, Elf> {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 f.debug_struct("ElfSymbolIterator").finish()
149 }
150 }
151
152 impl<'data, 'file, Elf: FileHeader> Iterator for ElfSymbolIterator<'data, 'file, Elf> {
153 type Item = (SymbolIndex, Symbol<'data>);
154
155 fn next(&mut self) -> Option<Self::Item> {
156 let index = self.index;
157 let shndx = self.symbols.shndx(index);
158 self.symbols.symbols.get(index).map(|symbol| {
159 self.index += 1;
160 let name = symbol.name(self.file.endian, self.symbols.strings()).ok();
161 (
162 SymbolIndex(index),
163 parse_symbol::<Elf>(self.file.endian, index, symbol, name, shndx),
164 )
165 })
166 }
167 }
168
169 pub(super) fn parse_symbol<'data, Elf: FileHeader>(
170 endian: Elf::Endian,
171 index: usize,
172 symbol: &Elf::Sym,
173 name: Option<&'data [u8]>,
174 shndx: Option<u32>,
175 ) -> Symbol<'data> {
176 let name = name.and_then(|s| str::from_utf8(s).ok());
177 let kind = match symbol.st_type() {
178 elf::STT_NOTYPE if index == 0 => SymbolKind::Null,
179 elf::STT_OBJECT | elf::STT_COMMON => SymbolKind::Data,
180 elf::STT_FUNC => SymbolKind::Text,
181 elf::STT_SECTION => SymbolKind::Section,
182 elf::STT_FILE => SymbolKind::File,
183 elf::STT_TLS => SymbolKind::Tls,
184 _ => SymbolKind::Unknown,
185 };
186 let section = match symbol.st_shndx(endian) {
187 elf::SHN_UNDEF => SymbolSection::Undefined,
188 elf::SHN_ABS => {
189 if kind == SymbolKind::File {
190 SymbolSection::None
191 } else {
192 SymbolSection::Absolute
193 }
194 }
195 elf::SHN_COMMON => SymbolSection::Common,
196 elf::SHN_XINDEX => match shndx {
197 Some(index) => SymbolSection::Section(SectionIndex(index as usize)),
198 None => SymbolSection::Unknown,
199 },
200 index if index < elf::SHN_LORESERVE => SymbolSection::Section(SectionIndex(index as usize)),
201 _ => SymbolSection::Unknown,
202 };
203 let weak = symbol.st_bind() == elf::STB_WEAK;
204 let scope = match symbol.st_bind() {
205 _ if section == SymbolSection::Undefined => SymbolScope::Unknown,
206 elf::STB_LOCAL => SymbolScope::Compilation,
207 elf::STB_GLOBAL | elf::STB_WEAK => {
208 if symbol.st_visibility() == elf::STV_HIDDEN {
209 SymbolScope::Linkage
210 } else {
211 SymbolScope::Dynamic
212 }
213 }
214 _ => SymbolScope::Unknown,
215 };
216 let flags = SymbolFlags::Elf {
217 st_info: symbol.st_info(),
218 st_other: symbol.st_other(),
219 };
220 Symbol {
221 name,
222 address: symbol.st_value(endian).into(),
223 size: symbol.st_size(endian).into(),
224 kind,
225 section,
226 weak,
227 scope,
228 flags,
229 }
230 }
231
232 /// A trait for generic access to `Sym32` and `Sym64`.
233 #[allow(missing_docs)]
234 pub trait Sym: Debug + Pod {
235 type Word: Into<u64>;
236 type Endian: endian::Endian;
237
238 fn st_name(&self, endian: Self::Endian) -> u32;
239 fn st_info(&self) -> u8;
240 fn st_bind(&self) -> u8;
241 fn st_type(&self) -> u8;
242 fn st_other(&self) -> u8;
243 fn st_visibility(&self) -> u8;
244 fn st_shndx(&self, endian: Self::Endian) -> u16;
245 fn st_value(&self, endian: Self::Endian) -> Self::Word;
246 fn st_size(&self, endian: Self::Endian) -> Self::Word;
247
248 /// Parse the symbol name from the string table.
249 fn name<'data>(
250 &self,
251 endian: Self::Endian,
252 strings: StringTable<'data>,
253 ) -> read::Result<&'data [u8]> {
254 strings
255 .get(self.st_name(endian))
256 .read_error("Invalid ELF symbol name offset")
257 }
258 }
259
260 impl<Endian: endian::Endian> Sym for elf::Sym32<Endian> {
261 type Word = u32;
262 type Endian = Endian;
263
264 #[inline]
265 fn st_name(&self, endian: Self::Endian) -> u32 {
266 self.st_name.get(endian)
267 }
268
269 #[inline]
270 fn st_info(&self) -> u8 {
271 self.st_info
272 }
273
274 #[inline]
275 fn st_bind(&self) -> u8 {
276 self.st_bind()
277 }
278
279 #[inline]
280 fn st_type(&self) -> u8 {
281 self.st_type()
282 }
283
284 #[inline]
285 fn st_other(&self) -> u8 {
286 self.st_other
287 }
288
289 #[inline]
290 fn st_visibility(&self) -> u8 {
291 self.st_visibility()
292 }
293
294 #[inline]
295 fn st_shndx(&self, endian: Self::Endian) -> u16 {
296 self.st_shndx.get(endian)
297 }
298
299 #[inline]
300 fn st_value(&self, endian: Self::Endian) -> Self::Word {
301 self.st_value.get(endian)
302 }
303
304 #[inline]
305 fn st_size(&self, endian: Self::Endian) -> Self::Word {
306 self.st_size.get(endian)
307 }
308 }
309
310 impl<Endian: endian::Endian> Sym for elf::Sym64<Endian> {
311 type Word = u64;
312 type Endian = Endian;
313
314 #[inline]
315 fn st_name(&self, endian: Self::Endian) -> u32 {
316 self.st_name.get(endian)
317 }
318
319 #[inline]
320 fn st_info(&self) -> u8 {
321 self.st_info
322 }
323
324 #[inline]
325 fn st_bind(&self) -> u8 {
326 self.st_bind()
327 }
328
329 #[inline]
330 fn st_type(&self) -> u8 {
331 self.st_type()
332 }
333
334 #[inline]
335 fn st_other(&self) -> u8 {
336 self.st_other
337 }
338
339 #[inline]
340 fn st_visibility(&self) -> u8 {
341 self.st_visibility()
342 }
343
344 #[inline]
345 fn st_shndx(&self, endian: Self::Endian) -> u16 {
346 self.st_shndx.get(endian)
347 }
348
349 #[inline]
350 fn st_value(&self, endian: Self::Endian) -> Self::Word {
351 self.st_value.get(endian)
352 }
353
354 #[inline]
355 fn st_size(&self, endian: Self::Endian) -> Self::Word {
356 self.st_size.get(endian)
357 }
358 }