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]
st_bind(info: u8) -> u875 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]
st_type(info: u8) -> u883 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]
st_visibility(other: u8) -> u891 pub fn st_visibility(other: u8) -> u8 {
92     other & 0x7
93 }
94 
95 /// Is this information defining an import?
96 #[inline]
is_import(info: u8, value: u64) -> bool97 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]
get_type(info: u8) -> &'static str104 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]
bind_to_str(typ: u8) -> &'static str110 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]
type_to_str(typ: u8) -> &'static str123 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]
visibility_to_str(typ: u8) -> &'static str140 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]
size(container: Container) -> usize353     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]
is_import(&self) -> bool358     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]
is_function(&self) -> bool364     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]
st_bind(&self) -> u8371     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]
st_type(&self) -> u8378     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]
st_visibility(&self) -> u8385     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`
parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>>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 {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result401     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
604