]> git.proxmox.com Git - rustc.git/blob - vendor/goblin/src/elf/sym.rs
New upstream version 1.48.0+dfsg1
[rustc.git] / vendor / goblin / src / elf / sym.rs
1 /// === Sym bindings ===
2 /// Local symbol.
3 pub const STB_LOCAL: u8 = 0;
4 /// Global symbol.
5 pub const STB_GLOBAL: u8 = 1;
6 /// Weak symbol.
7 pub const STB_WEAK: u8 = 2;
8 /// Number of defined types..
9 pub const STB_NUM: u8 = 3;
10 /// Start of OS-specific.
11 pub const STB_LOOS: u8 = 10;
12 /// Unique symbol..
13 pub const STB_GNU_UNIQUE: u8 = 10;
14 /// End of OS-specific.
15 pub const STB_HIOS: u8 = 12;
16 /// Start of processor-specific.
17 pub const STB_LOPROC: u8 = 13;
18 /// End of processor-specific.
19 pub const STB_HIPROC: u8 = 15;
20
21 /// === Sym types ===
22 /// Symbol type is unspecified.
23 pub const STT_NOTYPE: u8 = 0;
24 /// Symbol is a data object.
25 pub const STT_OBJECT: u8 = 1;
26 /// Symbol is a code object.
27 pub const STT_FUNC: u8 = 2;
28 /// Symbol associated with a section.
29 pub const STT_SECTION: u8 = 3;
30 /// Symbol's name is file name.
31 pub const STT_FILE: u8 = 4;
32 /// Symbol is a common data object.
33 pub const STT_COMMON: u8 = 5;
34 /// Symbol is thread-local data object.
35 pub const STT_TLS: u8 = 6;
36 /// Number of defined types.
37 pub const STT_NUM: u8 = 7;
38 /// Start of OS-specific.
39 pub const STT_LOOS: u8 = 10;
40 /// Symbol is indirect code object.
41 pub const STT_GNU_IFUNC: u8 = 10;
42 /// End of OS-specific.
43 pub const STT_HIOS: u8 = 12;
44 /// Start of processor-specific.
45 pub const STT_LOPROC: u8 = 13;
46 /// End of processor-specific.
47 pub const STT_HIPROC: u8 = 15;
48
49 /// === Sym visibility ===
50 /// Default: Visibility is specified by the symbol's binding type
51 pub const STV_DEFAULT: u8 = 0;
52 /// Internal: use of this attribute is currently reserved.
53 pub const STV_INTERNAL: u8 = 1;
54 /// Hidden: Not visible to other components, necessarily protected. Binding scope becomes local
55 /// when the object is included in an executable or shared object.
56 pub const STV_HIDDEN: u8 = 2;
57 /// Protected: Symbol defined in current component is visible in other components, but cannot be preempted.
58 /// Any reference from within the defining component must be resolved to the definition in that
59 /// component.
60 pub const STV_PROTECTED: u8 = 3;
61 /// Exported: ensures a symbol remains global, cannot be demoted or eliminated by any other symbol
62 /// visibility technique.
63 pub const STV_EXPORTED: u8 = 4;
64 /// Singleton: ensures a symbol remains global, and that a single instance of the definition is
65 /// bound to by all references within a process. Cannot be demoted or eliminated.
66 pub const STV_SINGLETON: u8 = 5;
67 /// Eliminate: extends the hidden attribute. Not written in any symbol table of a dynamic
68 /// executable or shared object.
69 pub const STV_ELIMINATE: u8 = 6;
70
71 /// Get the ST bind.
72 ///
73 /// This is the first four bits of the "info" byte.
74 #[inline]
75 pub fn st_bind(info: u8) -> u8 {
76 info >> 4
77 }
78
79 /// Get the ST type.
80 ///
81 /// This is the last four bits of the "info" byte.
82 #[inline]
83 pub fn st_type(info: u8) -> u8 {
84 info & 0xf
85 }
86
87 /// Get the ST visibility.
88 ///
89 /// This is the last three bits of the "other" byte.
90 #[inline]
91 pub fn st_visibility(other: u8) -> u8 {
92 other & 0x7
93 }
94
95 /// Is this information defining an import?
96 #[inline]
97 pub fn is_import(info: u8, value: u64) -> bool {
98 let bind = st_bind(info);
99 bind == STB_GLOBAL && value == 0
100 }
101
102 /// Convenience function to get the &'static str type from the symbols `st_info`.
103 #[inline]
104 pub fn get_type(info: u8) -> &'static str {
105 type_to_str(st_type(info))
106 }
107
108 /// Get the string for some bind.
109 #[inline]
110 pub fn bind_to_str(typ: u8) -> &'static str {
111 match typ {
112 STB_LOCAL => "LOCAL",
113 STB_GLOBAL => "GLOBAL",
114 STB_WEAK => "WEAK",
115 STB_NUM => "NUM",
116 STB_GNU_UNIQUE => "GNU_UNIQUE",
117 _ => "UNKNOWN_STB",
118 }
119 }
120
121 /// Get the string for some type.
122 #[inline]
123 pub fn type_to_str(typ: u8) -> &'static str {
124 match typ {
125 STT_NOTYPE => "NOTYPE",
126 STT_OBJECT => "OBJECT",
127 STT_FUNC => "FUNC",
128 STT_SECTION => "SECTION",
129 STT_FILE => "FILE",
130 STT_COMMON => "COMMON",
131 STT_TLS => "TLS",
132 STT_NUM => "NUM",
133 STT_GNU_IFUNC => "GNU_IFUNC",
134 _ => "UNKNOWN_STT",
135 }
136 }
137
138 /// Get the string for some visibility
139 #[inline]
140 pub fn visibility_to_str(typ: u8) -> &'static str {
141 match typ {
142 STV_DEFAULT => "DEFAULT",
143 STV_INTERNAL => "INTERNAL",
144 STV_HIDDEN => "HIDDEN",
145 STV_PROTECTED => "PROTECTED",
146 STV_EXPORTED => "EXPORTED",
147 STV_SINGLETON => "SINGLETON",
148 STV_ELIMINATE => "ELIMINATE",
149 _ => "UNKNOWN_STV",
150 }
151 }
152
153 macro_rules! elf_sym_std_impl {
154 ($size:ty) => {
155 #[cfg(test)]
156 mod tests {
157 use super::*;
158 #[test]
159 fn size_of() {
160 assert_eq!(::std::mem::size_of::<Sym>(), SIZEOF_SYM);
161 }
162 }
163
164 use crate::elf::sym::Sym as ElfSym;
165
166 use core::fmt;
167 use core::slice;
168
169 impl Sym {
170 /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0
171 #[inline]
172 pub fn is_import(&self) -> bool {
173 let bind = self.st_info >> 4;
174 (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0
175 }
176 /// Checks whether this `Sym` has type `STT_FUNC`
177 #[inline]
178 pub fn is_function(&self) -> bool {
179 st_type(self.st_info) == STT_FUNC
180 }
181 }
182
183 impl From<Sym> for ElfSym {
184 #[inline]
185 fn from(sym: Sym) -> Self {
186 ElfSym {
187 st_name: sym.st_name as usize,
188 st_info: sym.st_info,
189 st_other: sym.st_other,
190 st_shndx: sym.st_shndx as usize,
191 st_value: u64::from(sym.st_value),
192 st_size: u64::from(sym.st_size),
193 }
194 }
195 }
196
197 impl From<ElfSym> for Sym {
198 #[inline]
199 fn from(sym: ElfSym) -> Self {
200 Sym {
201 st_name: sym.st_name as u32,
202 st_info: sym.st_info,
203 st_other: sym.st_other,
204 st_shndx: sym.st_shndx as u16,
205 st_value: sym.st_value as $size,
206 st_size: sym.st_size as $size,
207 }
208 }
209 }
210
211 impl fmt::Debug for Sym {
212 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213 let bind = st_bind(self.st_info);
214 let typ = st_type(self.st_info);
215 let vis = st_visibility(self.st_other);
216 f.debug_struct("Sym")
217 .field("st_name", &self.st_name)
218 .field("st_value", &format_args!("{:x}", self.st_value))
219 .field("st_size", &self.st_size)
220 .field(
221 "st_info",
222 &format_args!(
223 "{:x} {} {}",
224 self.st_info,
225 bind_to_str(bind),
226 type_to_str(typ)
227 ),
228 )
229 .field(
230 "st_other",
231 &format_args!("{} {}", self.st_other, visibility_to_str(vis)),
232 )
233 .field("st_shndx", &self.st_shndx)
234 .finish()
235 }
236 }
237
238 /// # Safety
239 ///
240 /// This function creates a `Sym` slice directly from a raw pointer
241 #[inline]
242 pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] {
243 slice::from_raw_parts(symp, count)
244 }
245
246 if_std! {
247 use crate::error::Result;
248
249 use std::fs::File;
250 use std::io::{Read, Seek};
251 use std::io::SeekFrom::Start;
252
253 pub fn from_fd(fd: &mut File, offset: usize, count: usize) -> Result<Vec<Sym>> {
254 // TODO: AFAIK this shouldn't work, since i pass in a byte size...
255 let mut syms = vec![Sym::default(); count];
256 fd.seek(Start(offset as u64))?;
257 unsafe {
258 fd.read_exact(plain::as_mut_bytes(&mut *syms))?;
259 }
260 syms.dedup();
261 Ok(syms)
262 }
263 }
264 };
265 }
266
267 #[cfg(feature = "alloc")]
268 use scroll::{Pread, Pwrite, SizeWith};
269
270 pub mod sym32 {
271 pub use crate::elf::sym::*;
272
273 #[repr(C)]
274 #[derive(Clone, Copy, PartialEq, Default)]
275 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
276 /// 32-bit Sym - used for both static and dynamic symbol information in a binary
277 pub struct Sym {
278 /// Symbol name (string tbl index)
279 pub st_name: u32,
280 /// Symbol value
281 pub st_value: u32,
282 /// Symbol size
283 pub st_size: u32,
284 /// Symbol type and binding
285 pub st_info: u8,
286 /// Symbol visibility
287 pub st_other: u8,
288 /// Section index
289 pub st_shndx: u16,
290 }
291
292 // Declare that the type is plain.
293 unsafe impl plain::Plain for Sym {}
294
295 pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 4 + 4;
296
297 elf_sym_std_impl!(u32);
298 }
299
300 pub mod sym64 {
301 pub use crate::elf::sym::*;
302
303 #[repr(C)]
304 #[derive(Clone, Copy, PartialEq, Default)]
305 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
306 /// 64-bit Sym - used for both static and dynamic symbol information in a binary
307 pub struct Sym {
308 /// Symbol name (string tbl index)
309 pub st_name: u32,
310 /// Symbol type and binding
311 pub st_info: u8,
312 /// Symbol visibility
313 pub st_other: u8,
314 /// Section index
315 pub st_shndx: u16,
316 /// Symbol value
317 pub st_value: u64,
318 /// Symbol size
319 pub st_size: u64,
320 }
321
322 // Declare that the type is plain.
323 unsafe impl plain::Plain for Sym {}
324
325 pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8;
326
327 elf_sym_std_impl!(u64);
328 }
329
330 use crate::container::{Container, Ctx};
331 #[cfg(feature = "alloc")]
332 use crate::error::Result;
333 #[cfg(feature = "alloc")]
334 use alloc::vec::Vec;
335 use core::fmt::{self, Debug};
336 use core::result;
337 use scroll::ctx;
338 use scroll::ctx::SizeWith;
339
340 #[derive(Clone, Copy, PartialEq, Default)]
341 /// A unified Sym definition - convertible to and from 32-bit and 64-bit variants
342 pub struct Sym {
343 pub st_name: usize,
344 pub st_info: u8,
345 pub st_other: u8,
346 pub st_shndx: usize,
347 pub st_value: u64,
348 pub st_size: u64,
349 }
350
351 impl Sym {
352 #[inline]
353 pub fn size(container: Container) -> usize {
354 Self::size_with(&Ctx::from(container))
355 }
356 /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0
357 #[inline]
358 pub fn is_import(&self) -> bool {
359 let bind = self.st_bind();
360 (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0
361 }
362 /// Checks whether this `Sym` has type `STT_FUNC`
363 #[inline]
364 pub fn is_function(&self) -> bool {
365 st_type(self.st_info) == STT_FUNC
366 }
367 /// Get the ST bind.
368 ///
369 /// This is the first four bits of the "info" byte.
370 #[inline]
371 pub fn st_bind(&self) -> u8 {
372 self.st_info >> 4
373 }
374 /// Get the ST type.
375 ///
376 /// This is the last four bits of the "info" byte.
377 #[inline]
378 pub fn st_type(&self) -> u8 {
379 st_type(self.st_info)
380 }
381 /// Get the ST visibility.
382 ///
383 /// This is the last three bits of the "other" byte.
384 #[inline]
385 pub fn st_visibility(&self) -> u8 {
386 st_visibility(self.st_other)
387 }
388 #[cfg(feature = "endian_fd")]
389 /// Parse `count` vector of ELF symbols from `offset`
390 pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>> {
391 let mut syms = Vec::with_capacity(count);
392 for _ in 0..count {
393 let sym = bytes.gread_with(&mut offset, ctx)?;
394 syms.push(sym);
395 }
396 Ok(syms)
397 }
398 }
399
400 impl fmt::Debug for Sym {
401 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
402 let bind = self.st_bind();
403 let typ = self.st_type();
404 let vis = self.st_visibility();
405 f.debug_struct("Sym")
406 .field("st_name", &self.st_name)
407 .field(
408 "st_info",
409 &format_args!(
410 "0x{:x} {} {}",
411 self.st_info,
412 bind_to_str(bind),
413 type_to_str(typ)
414 ),
415 )
416 .field(
417 "st_other",
418 &format_args!("{} {}", self.st_other, visibility_to_str(vis)),
419 )
420 .field("st_shndx", &self.st_shndx)
421 .field("st_value", &format_args!("0x{:x}", self.st_value))
422 .field("st_size", &self.st_size)
423 .finish()
424 }
425 }
426
427 impl ctx::SizeWith<Ctx> for Sym {
428 #[inline]
429 fn size_with(&Ctx { container, .. }: &Ctx) -> usize {
430 match container {
431 Container::Little => sym32::SIZEOF_SYM,
432 Container::Big => sym64::SIZEOF_SYM,
433 }
434 }
435 }
436
437 if_alloc! {
438 impl<'a> ctx::TryFromCtx<'a, Ctx> for Sym {
439 type Error = crate::error::Error;
440 #[inline]
441 fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
442 let sym = match container {
443 Container::Little => {
444 (bytes.pread_with::<sym32::Sym>(0, le)?.into(), sym32::SIZEOF_SYM)
445 },
446 Container::Big => {
447 (bytes.pread_with::<sym64::Sym>(0, le)?.into(), sym64::SIZEOF_SYM)
448 }
449 };
450 Ok(sym)
451 }
452 }
453
454 impl ctx::TryIntoCtx<Ctx> for Sym {
455 type Error = crate::error::Error;
456 #[inline]
457 fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
458 match container {
459 Container::Little => {
460 let sym: sym32::Sym = self.into();
461 Ok(bytes.pwrite_with(sym, 0, le)?)
462 },
463 Container::Big => {
464 let sym: sym64::Sym = self.into();
465 Ok(bytes.pwrite_with(sym, 0, le)?)
466 }
467 }
468 }
469 }
470
471 impl ctx::IntoCtx<Ctx> for Sym {
472 #[inline]
473 fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
474 match container {
475 Container::Little => {
476 let sym: sym32::Sym = self.into();
477 bytes.pwrite_with(sym, 0, le).unwrap();
478 },
479 Container::Big => {
480 let sym: sym64::Sym = self.into();
481 bytes.pwrite_with(sym, 0, le).unwrap();
482 }
483 }
484 }
485 }
486 }
487
488 if_alloc! {
489 #[derive(Default)]
490 /// An ELF symbol table, allowing lazy iteration over symbols
491 pub struct Symtab<'a> {
492 bytes: &'a [u8],
493 count: usize,
494 ctx: Ctx,
495 start: usize,
496 end: usize,
497 }
498
499 impl<'a> Debug for Symtab<'a> {
500 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
501 let len = self.bytes.len();
502 fmt.debug_struct("Symtab")
503 .field("bytes", &len)
504 .field("range", &format_args!("{:#x}..{:#x}", self.start, self.end))
505 .field("count", &self.count)
506 .field("Symbols", &self.to_vec())
507 .finish()
508 }
509 }
510
511 impl<'a> Symtab<'a> {
512 /// Parse a table of `count` ELF symbols from `offset`.
513 pub fn parse(bytes: &'a [u8], offset: usize, count: usize, ctx: Ctx) -> Result<Symtab<'a>> {
514 let size = count
515 .checked_mul(Sym::size_with(&ctx))
516 .ok_or_else(|| crate::error::Error::Malformed(
517 format!("Too many ELF symbols (offset {:#x}, count {})", offset, count)
518 ))?;
519 // TODO: make this a better error message when too large
520 let bytes = bytes.pread_with(offset, size)?;
521 Ok(Symtab { bytes, count, ctx, start: offset, end: offset+size })
522 }
523
524 /// Try to parse a single symbol from the binary, at `index`.
525 #[inline]
526 pub fn get(&self, index: usize) -> Option<Sym> {
527 if index >= self.count {
528 None
529 } else {
530 Some(self.bytes.pread_with(index * Sym::size_with(&self.ctx), self.ctx).unwrap())
531 }
532 }
533
534 /// The number of symbols in the table.
535 #[inline]
536 pub fn len(&self) -> usize {
537 self.count
538 }
539
540 /// Returns true if table has no symbols.
541 #[inline]
542 pub fn is_empty(&self) -> bool {
543 self.count == 0
544 }
545
546 /// Iterate over all symbols.
547 #[inline]
548 pub fn iter(&self) -> SymIterator<'a> {
549 self.into_iter()
550 }
551
552 /// Parse all symbols into a vector.
553 pub fn to_vec(&self) -> Vec<Sym> {
554 self.iter().collect()
555 }
556 }
557
558 impl<'a, 'b> IntoIterator for &'b Symtab<'a> {
559 type Item = <SymIterator<'a> as Iterator>::Item;
560 type IntoIter = SymIterator<'a>;
561
562 #[inline]
563 fn into_iter(self) -> Self::IntoIter {
564 SymIterator {
565 bytes: self.bytes,
566 offset: 0,
567 index: 0,
568 count: self.count,
569 ctx: self.ctx,
570 }
571 }
572 }
573
574 /// An iterator over symbols in an ELF symbol table
575 pub struct SymIterator<'a> {
576 bytes: &'a [u8],
577 offset: usize,
578 index: usize,
579 count: usize,
580 ctx: Ctx,
581 }
582
583 impl<'a> Iterator for SymIterator<'a> {
584 type Item = Sym;
585
586 #[inline]
587 fn next(&mut self) -> Option<Self::Item> {
588 if self.index >= self.count {
589 None
590 } else {
591 self.index += 1;
592 Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap())
593 }
594 }
595 }
596
597 impl<'a> ExactSizeIterator for SymIterator<'a> {
598 #[inline]
599 fn len(&self) -> usize {
600 self.count - self.index
601 }
602 }
603 } // end if_alloc