]> git.proxmox.com Git - rustc.git/blob - vendor/object-0.29.0/src/read/coff/symbol.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / vendor / object-0.29.0 / src / read / coff / symbol.rs
1 use alloc::fmt;
2 use alloc::vec::Vec;
3 use core::convert::TryInto;
4 use core::str;
5
6 use super::{CoffCommon, SectionTable};
7 use crate::endian::{LittleEndian as LE, U32Bytes};
8 use crate::pe;
9 use crate::pod::{bytes_of_slice, Pod};
10 use crate::read::util::StringTable;
11 use crate::read::{
12 self, Bytes, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex,
13 SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection,
14 };
15
16 /// A table of symbol entries in a COFF or PE file.
17 ///
18 /// Also includes the string table used for the symbol names.
19 #[derive(Debug)]
20 pub struct SymbolTable<'data, R = &'data [u8]>
21 where
22 R: ReadRef<'data>,
23 {
24 symbols: &'data [pe::ImageSymbolBytes],
25 strings: StringTable<'data, R>,
26 }
27
28 impl<'data, R: ReadRef<'data>> Default for SymbolTable<'data, R> {
29 fn default() -> Self {
30 Self {
31 symbols: &[],
32 strings: StringTable::default(),
33 }
34 }
35 }
36
37 impl<'data, R: ReadRef<'data>> SymbolTable<'data, R> {
38 /// Read the symbol table.
39 pub fn parse(header: &pe::ImageFileHeader, data: R) -> Result<Self> {
40 // The symbol table may not be present.
41 let mut offset = header.pointer_to_symbol_table.get(LE).into();
42 let (symbols, strings) = if offset != 0 {
43 let symbols = data
44 .read_slice(&mut offset, header.number_of_symbols.get(LE) as usize)
45 .read_error("Invalid COFF symbol table offset or size")?;
46
47 // Note: don't update data when reading length; the length includes itself.
48 let length = data
49 .read_at::<U32Bytes<_>>(offset)
50 .read_error("Missing COFF string table")?
51 .get(LE);
52 let str_end = offset
53 .checked_add(length as u64)
54 .read_error("Invalid COFF string table length")?;
55 let strings = StringTable::new(data, offset, str_end);
56
57 (symbols, strings)
58 } else {
59 (&[][..], StringTable::default())
60 };
61
62 Ok(SymbolTable { symbols, strings })
63 }
64
65 /// Return the string table used for the symbol names.
66 #[inline]
67 pub fn strings(&self) -> StringTable<'data, R> {
68 self.strings
69 }
70
71 /// Return true if the symbol table is empty.
72 #[inline]
73 pub fn is_empty(&self) -> bool {
74 self.symbols.is_empty()
75 }
76
77 /// The number of symbol table entries.
78 ///
79 /// This includes auxiliary symbol table entries.
80 #[inline]
81 pub fn len(&self) -> usize {
82 self.symbols.len()
83 }
84
85 /// Iterate over the symbols.
86 #[inline]
87 pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, R> {
88 SymbolIterator {
89 symbols: self,
90 index: 0,
91 }
92 }
93
94 /// Return the symbol table entry at the given index.
95 #[inline]
96 pub fn symbol(&self, index: usize) -> Result<&'data pe::ImageSymbol> {
97 self.get::<pe::ImageSymbol>(index, 0)
98 }
99
100 /// Return the auxiliary function symbol for the symbol table entry at the given index.
101 ///
102 /// Note that the index is of the symbol, not the first auxiliary record.
103 #[inline]
104 pub fn aux_function(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolFunction> {
105 self.get::<pe::ImageAuxSymbolFunction>(index, 1)
106 }
107
108 /// Return the auxiliary section symbol for the symbol table entry at the given index.
109 ///
110 /// Note that the index is of the symbol, not the first auxiliary record.
111 #[inline]
112 pub fn aux_section(&self, index: usize) -> Result<&'data pe::ImageAuxSymbolSection> {
113 self.get::<pe::ImageAuxSymbolSection>(index, 1)
114 }
115
116 /// Return the auxiliary file name for the symbol table entry at the given index.
117 ///
118 /// Note that the index is of the symbol, not the first auxiliary record.
119 pub fn aux_file_name(&self, index: usize, aux_count: u8) -> Result<&'data [u8]> {
120 let entries = index
121 .checked_add(1)
122 .and_then(|x| Some(x..x.checked_add(aux_count.into())?))
123 .and_then(|x| self.symbols.get(x))
124 .read_error("Invalid COFF symbol index")?;
125 let bytes = bytes_of_slice(entries);
126 // The name is padded with nulls.
127 Ok(match memchr::memchr(b'\0', bytes) {
128 Some(end) => &bytes[..end],
129 None => bytes,
130 })
131 }
132
133 /// Return the symbol table entry or auxiliary record at the given index and offset.
134 pub fn get<T: Pod>(&self, index: usize, offset: usize) -> Result<&'data T> {
135 let bytes = index
136 .checked_add(offset)
137 .and_then(|x| self.symbols.get(x))
138 .read_error("Invalid COFF symbol index")?;
139 Bytes(&bytes.0[..])
140 .read()
141 .read_error("Invalid COFF symbol data")
142 }
143
144 /// Construct a map from addresses to a user-defined map entry.
145 pub fn map<Entry: SymbolMapEntry, F: Fn(&'data pe::ImageSymbol) -> Option<Entry>>(
146 &self,
147 f: F,
148 ) -> SymbolMap<Entry> {
149 let mut symbols = Vec::with_capacity(self.symbols.len());
150 for (_, symbol) in self.iter() {
151 if !symbol.is_definition() {
152 continue;
153 }
154 if let Some(entry) = f(symbol) {
155 symbols.push(entry);
156 }
157 }
158 SymbolMap::new(symbols)
159 }
160 }
161
162 /// An iterator for symbol entries in a COFF or PE file.
163 ///
164 /// Yields the index and symbol structure for each symbol.
165 #[derive(Debug)]
166 pub struct SymbolIterator<'data, 'table, R = &'data [u8]>
167 where
168 R: ReadRef<'data>,
169 {
170 symbols: &'table SymbolTable<'data, R>,
171 index: usize,
172 }
173
174 impl<'data, 'table, R: ReadRef<'data>> Iterator for SymbolIterator<'data, 'table, R> {
175 type Item = (usize, &'data pe::ImageSymbol);
176
177 fn next(&mut self) -> Option<Self::Item> {
178 let index = self.index;
179 let symbol = self.symbols.symbol(index).ok()?;
180 self.index += 1 + symbol.number_of_aux_symbols as usize;
181 Some((index, symbol))
182 }
183 }
184
185 impl pe::ImageSymbol {
186 /// Parse a COFF symbol name.
187 ///
188 /// `strings` must be the string table used for symbol names.
189 pub fn name<'data, R: ReadRef<'data>>(
190 &'data self,
191 strings: StringTable<'data, R>,
192 ) -> Result<&'data [u8]> {
193 if self.name[0] == 0 {
194 // If the name starts with 0 then the last 4 bytes are a string table offset.
195 let offset = u32::from_le_bytes(self.name[4..8].try_into().unwrap());
196 strings
197 .get(offset)
198 .read_error("Invalid COFF symbol name offset")
199 } else {
200 // The name is inline and padded with nulls.
201 Ok(match memchr::memchr(b'\0', &self.name) {
202 Some(end) => &self.name[..end],
203 None => &self.name[..],
204 })
205 }
206 }
207
208 /// Return the symbol address.
209 ///
210 /// This takes into account the image base and the section address.
211 pub fn address(&self, image_base: u64, sections: &SectionTable) -> Result<u64> {
212 let section_number = self.section_number.get(LE) as usize;
213 let section = sections.section(section_number)?;
214 let virtual_address = u64::from(section.virtual_address.get(LE));
215 let value = u64::from(self.value.get(LE));
216 Ok(image_base + virtual_address + value)
217 }
218
219 /// Return true if the symbol is a definition of a function or data object.
220 pub fn is_definition(&self) -> bool {
221 let section_number = self.section_number.get(LE);
222 if section_number == pe::IMAGE_SYM_UNDEFINED {
223 return false;
224 }
225 match self.storage_class {
226 pe::IMAGE_SYM_CLASS_STATIC => {
227 // Exclude section symbols.
228 !(self.value.get(LE) == 0 && self.number_of_aux_symbols > 0)
229 }
230 pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true,
231 _ => false,
232 }
233 }
234
235 /// Return true if the symbol has an auxiliary file name.
236 pub fn has_aux_file_name(&self) -> bool {
237 self.number_of_aux_symbols > 0 && self.storage_class == pe::IMAGE_SYM_CLASS_FILE
238 }
239
240 /// Return true if the symbol has an auxiliary function symbol.
241 pub fn has_aux_function(&self) -> bool {
242 self.number_of_aux_symbols > 0 && self.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION
243 }
244
245 /// Return true if the symbol has an auxiliary section symbol.
246 pub fn has_aux_section(&self) -> bool {
247 self.number_of_aux_symbols > 0
248 && self.storage_class == pe::IMAGE_SYM_CLASS_STATIC
249 && self.value.get(LE) == 0
250 }
251 }
252
253 /// A symbol table of a `CoffFile`.
254 #[derive(Debug, Clone, Copy)]
255 pub struct CoffSymbolTable<'data, 'file, R = &'data [u8]>
256 where
257 R: ReadRef<'data>,
258 {
259 pub(crate) file: &'file CoffCommon<'data, R>,
260 }
261
262 impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffSymbolTable<'data, 'file, R> {}
263
264 impl<'data, 'file, R: ReadRef<'data>> ObjectSymbolTable<'data>
265 for CoffSymbolTable<'data, 'file, R>
266 {
267 type Symbol = CoffSymbol<'data, 'file, R>;
268 type SymbolIterator = CoffSymbolIterator<'data, 'file, R>;
269
270 fn symbols(&self) -> Self::SymbolIterator {
271 CoffSymbolIterator {
272 file: self.file,
273 index: 0,
274 }
275 }
276
277 fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> {
278 let symbol = self.file.symbols.symbol(index.0)?;
279 Ok(CoffSymbol {
280 file: self.file,
281 index,
282 symbol,
283 })
284 }
285 }
286
287 /// An iterator over the symbols of a `CoffFile`.
288 pub struct CoffSymbolIterator<'data, 'file, R = &'data [u8]>
289 where
290 R: ReadRef<'data>,
291 {
292 pub(crate) file: &'file CoffCommon<'data, R>,
293 pub(crate) index: usize,
294 }
295
296 impl<'data, 'file, R: ReadRef<'data>> fmt::Debug for CoffSymbolIterator<'data, 'file, R> {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 f.debug_struct("CoffSymbolIterator").finish()
299 }
300 }
301
302 impl<'data, 'file, R: ReadRef<'data>> Iterator for CoffSymbolIterator<'data, 'file, R> {
303 type Item = CoffSymbol<'data, 'file, R>;
304
305 fn next(&mut self) -> Option<Self::Item> {
306 let index = self.index;
307 let symbol = self.file.symbols.symbol(index).ok()?;
308 self.index += 1 + symbol.number_of_aux_symbols as usize;
309 Some(CoffSymbol {
310 file: self.file,
311 index: SymbolIndex(index),
312 symbol,
313 })
314 }
315 }
316
317 /// A symbol of a `CoffFile`.
318 #[derive(Debug, Clone, Copy)]
319 pub struct CoffSymbol<'data, 'file, R = &'data [u8]>
320 where
321 R: ReadRef<'data>,
322 {
323 pub(crate) file: &'file CoffCommon<'data, R>,
324 pub(crate) index: SymbolIndex,
325 pub(crate) symbol: &'data pe::ImageSymbol,
326 }
327
328 impl<'data, 'file, R: ReadRef<'data>> read::private::Sealed for CoffSymbol<'data, 'file, R> {}
329
330 impl<'data, 'file, R: ReadRef<'data>> ObjectSymbol<'data> for CoffSymbol<'data, 'file, R> {
331 #[inline]
332 fn index(&self) -> SymbolIndex {
333 self.index
334 }
335
336 fn name_bytes(&self) -> read::Result<&'data [u8]> {
337 if self.symbol.has_aux_file_name() {
338 self.file
339 .symbols
340 .aux_file_name(self.index.0, self.symbol.number_of_aux_symbols)
341 } else {
342 self.symbol.name(self.file.symbols.strings())
343 }
344 }
345
346 fn name(&self) -> read::Result<&'data str> {
347 let name = self.name_bytes()?;
348 str::from_utf8(name)
349 .ok()
350 .read_error("Non UTF-8 COFF symbol name")
351 }
352
353 fn address(&self) -> u64 {
354 // Only return an address for storage classes that we know use an address.
355 match self.symbol.storage_class {
356 pe::IMAGE_SYM_CLASS_STATIC
357 | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL
358 | pe::IMAGE_SYM_CLASS_LABEL => {}
359 pe::IMAGE_SYM_CLASS_EXTERNAL => {
360 if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED {
361 // Undefined or common data, neither of which have an address.
362 return 0;
363 }
364 }
365 _ => return 0,
366 }
367 self.symbol
368 .address(self.file.image_base, &self.file.sections)
369 .unwrap_or(0)
370 }
371
372 fn size(&self) -> u64 {
373 match self.symbol.storage_class {
374 pe::IMAGE_SYM_CLASS_STATIC => {
375 // Section symbols may duplicate the size from the section table.
376 if self.symbol.has_aux_section() {
377 if let Ok(aux) = self.file.symbols.aux_section(self.index.0) {
378 u64::from(aux.length.get(LE))
379 } else {
380 0
381 }
382 } else {
383 0
384 }
385 }
386 pe::IMAGE_SYM_CLASS_EXTERNAL => {
387 if self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED {
388 // For undefined symbols, symbol.value is 0 and the size is 0.
389 // For common data, symbol.value is the size.
390 u64::from(self.symbol.value.get(LE))
391 } else if self.symbol.has_aux_function() {
392 // Function symbols may have a size.
393 if let Ok(aux) = self.file.symbols.aux_function(self.index.0) {
394 u64::from(aux.total_size.get(LE))
395 } else {
396 0
397 }
398 } else {
399 0
400 }
401 }
402 // Most symbols don't have sizes.
403 _ => 0,
404 }
405 }
406
407 fn kind(&self) -> SymbolKind {
408 let derived_kind = if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION {
409 SymbolKind::Text
410 } else {
411 SymbolKind::Data
412 };
413 match self.symbol.storage_class {
414 pe::IMAGE_SYM_CLASS_STATIC => {
415 if self.symbol.value.get(LE) == 0 && self.symbol.number_of_aux_symbols > 0 {
416 SymbolKind::Section
417 } else {
418 derived_kind
419 }
420 }
421 pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => derived_kind,
422 pe::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section,
423 pe::IMAGE_SYM_CLASS_FILE => SymbolKind::File,
424 pe::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label,
425 _ => SymbolKind::Unknown,
426 }
427 }
428
429 fn section(&self) -> SymbolSection {
430 match self.symbol.section_number.get(LE) {
431 pe::IMAGE_SYM_UNDEFINED => {
432 if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL
433 && self.symbol.value.get(LE) == 0
434 {
435 SymbolSection::Undefined
436 } else {
437 SymbolSection::Common
438 }
439 }
440 pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute,
441 pe::IMAGE_SYM_DEBUG => {
442 if self.symbol.storage_class == pe::IMAGE_SYM_CLASS_FILE {
443 SymbolSection::None
444 } else {
445 SymbolSection::Unknown
446 }
447 }
448 index if index > 0 => SymbolSection::Section(SectionIndex(index.into())),
449 _ => SymbolSection::Unknown,
450 }
451 }
452
453 #[inline]
454 fn is_undefined(&self) -> bool {
455 self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL
456 && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED
457 && self.symbol.value.get(LE) == 0
458 }
459
460 #[inline]
461 fn is_definition(&self) -> bool {
462 self.symbol.is_definition()
463 }
464
465 #[inline]
466 fn is_common(&self) -> bool {
467 self.symbol.storage_class == pe::IMAGE_SYM_CLASS_EXTERNAL
468 && self.symbol.section_number.get(LE) == pe::IMAGE_SYM_UNDEFINED
469 && self.symbol.value.get(LE) != 0
470 }
471
472 #[inline]
473 fn is_weak(&self) -> bool {
474 self.symbol.storage_class == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL
475 }
476
477 #[inline]
478 fn scope(&self) -> SymbolScope {
479 match self.symbol.storage_class {
480 pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => {
481 // TODO: determine if symbol is exported
482 SymbolScope::Linkage
483 }
484 _ => SymbolScope::Compilation,
485 }
486 }
487
488 #[inline]
489 fn is_global(&self) -> bool {
490 match self.symbol.storage_class {
491 pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true,
492 _ => false,
493 }
494 }
495
496 #[inline]
497 fn is_local(&self) -> bool {
498 !self.is_global()
499 }
500
501 fn flags(&self) -> SymbolFlags<SectionIndex> {
502 if self.symbol.has_aux_section() {
503 if let Ok(aux) = self.file.symbols.aux_section(self.index.0) {
504 // TODO: use high_number for bigobj
505 let number = aux.number.get(LE) as usize;
506 return SymbolFlags::CoffSection {
507 selection: aux.selection,
508 associative_section: if number == 0 {
509 None
510 } else {
511 Some(SectionIndex(number))
512 },
513 };
514 }
515 }
516 SymbolFlags::None
517 }
518 }