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 
154 macro_rules! elf_sym_std_impl {
155     ($size:ty) => {
156 
157         #[cfg(test)]
158         mod tests {
159             use super::*;
160             #[test]
161             fn size_of() {
162                 assert_eq!(::std::mem::size_of::<Sym>(), SIZEOF_SYM);
163             }
164         }
165 
166         use crate::elf::sym::Sym as ElfSym;
167 
168         use core::fmt;
169         use core::slice;
170 
171         impl Sym {
172             /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0
173             #[inline]
174             pub fn is_import(&self) -> bool {
175                 let bind = self.st_info >> 4;
176                 (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0
177             }
178             /// Checks whether this `Sym` has type `STT_FUNC`
179             #[inline]
180             pub fn is_function(&self) -> bool {
181                 st_type(self.st_info) == STT_FUNC
182             }
183         }
184 
185         impl From<Sym> for ElfSym {
186             #[inline]
187             fn from(sym: Sym) -> Self {
188                 ElfSym {
189                     st_name:     sym.st_name as usize,
190                     st_info:     sym.st_info,
191                     st_other:    sym.st_other,
192                     st_shndx:    sym.st_shndx as usize,
193                     st_value:    u64::from(sym.st_value),
194                     st_size:     u64::from(sym.st_size),
195                 }
196             }
197         }
198 
199         impl From<ElfSym> for Sym {
200             #[inline]
201             fn from(sym: ElfSym) -> Self {
202                 Sym {
203                     st_name:     sym.st_name as u32,
204                     st_info:     sym.st_info,
205                     st_other:    sym.st_other,
206                     st_shndx:    sym.st_shndx as u16,
207                     st_value:    sym.st_value as $size,
208                     st_size:     sym.st_size as $size,
209                 }
210             }
211         }
212 
213         impl fmt::Debug for Sym {
214             fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215                 let bind = st_bind(self.st_info);
216                 let typ = st_type(self.st_info);
217                 let vis = st_visibility(self.st_other);
218                 f.debug_struct("Sym")
219                     .field("st_name", &self.st_name)
220                     .field("st_value", &format_args!("{:x}", self.st_value))
221                     .field("st_size", &self.st_size)
222                     .field("st_info", &format_args!("{:x} {} {}", self.st_info, bind_to_str(bind), type_to_str(typ)))
223                     .field("st_other", &format_args!("{} {}", self.st_other, visibility_to_str(vis)))
224                     .field("st_shndx", &self.st_shndx)
225                     .finish()
226             }
227         }
228 
229         #[inline]
230         pub unsafe fn from_raw<'a>(symp: *const Sym, count: usize) -> &'a [Sym] {
231             slice::from_raw_parts(symp, count)
232         }
233 
234         if_std! {
235             use crate::error::Result;
236 
237             use std::fs::File;
238             use std::io::{Read, Seek};
239             use std::io::SeekFrom::Start;
240 
241             pub fn from_fd(fd: &mut File, offset: usize, count: usize) -> Result<Vec<Sym>> {
242                 // TODO: AFAIK this shouldn't work, since i pass in a byte size...
243                 let mut syms = vec![Sym::default(); count];
244                 fd.seek(Start(offset as u64))?;
245                 unsafe {
246                     fd.read_exact(plain::as_mut_bytes(&mut *syms))?;
247                 }
248                 syms.dedup();
249                 Ok(syms)
250             }
251         }
252     };
253 }
254 
255 #[cfg(feature = "alloc")]
256 use scroll::{Pread, Pwrite, SizeWith};
257 
258 pub mod sym32 {
259     pub use crate::elf::sym::*;
260 
261     #[repr(C)]
262     #[derive(Clone, Copy, PartialEq, Default)]
263     #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
264     /// 32-bit Sym - used for both static and dynamic symbol information in a binary
265     pub struct Sym {
266         /// Symbol name (string tbl index)
267         pub st_name: u32,
268         /// Symbol value
269         pub st_value: u32,
270         /// Symbol size
271         pub st_size: u32,
272         /// Symbol type and binding
273         pub st_info: u8,
274         /// Symbol visibility
275         pub st_other: u8,
276         /// Section index
277         pub st_shndx: u16,
278     }
279 
280     // Declare that the type is plain.
281     unsafe impl plain::Plain for Sym {}
282 
283     pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 4 + 4;
284 
285     elf_sym_std_impl!(u32);
286 }
287 
288 pub mod sym64 {
289     pub use crate::elf::sym::*;
290 
291     #[repr(C)]
292     #[derive(Clone, Copy, PartialEq, Default)]
293     #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
294     /// 64-bit Sym - used for both static and dynamic symbol information in a binary
295     pub struct Sym {
296         /// Symbol name (string tbl index)
297         pub st_name: u32,
298         /// Symbol type and binding
299         pub st_info: u8,
300         /// Symbol visibility
301         pub st_other: u8,
302         /// Section index
303         pub st_shndx: u16,
304         /// Symbol value
305         pub st_value: u64,
306         /// Symbol size
307         pub st_size: u64,
308     }
309 
310     // Declare that the type is plain.
311     unsafe impl plain::Plain for Sym {}
312 
313     pub const SIZEOF_SYM: usize = 4 + 1 + 1 + 2 + 8 + 8;
314 
315     elf_sym_std_impl!(u64);
316 }
317 
318 use scroll::ctx;
319 use scroll::ctx::SizeWith;
320 use core::fmt::{self, Debug};
321 use core::result;
322 use crate::container::{Ctx, Container};
323 #[cfg(feature = "alloc")]
324 use crate::error::Result;
325 #[cfg(feature = "alloc")]
326 use alloc::vec::Vec;
327 
328 #[derive(Clone, Copy, PartialEq, Default)]
329 /// A unified Sym definition - convertible to and from 32-bit and 64-bit variants
330 pub struct Sym {
331     pub st_name:     usize,
332     pub st_info:     u8,
333     pub st_other:    u8,
334     pub st_shndx:    usize,
335     pub st_value:    u64,
336     pub st_size:     u64,
337 }
338 
339 impl Sym {
340     #[inline]
size(container: Container) -> usize341     pub fn size(container: Container) -> usize {
342         Self::size_with(&Ctx::from(container))
343     }
344     /// Checks whether this `Sym` has `STB_GLOBAL`/`STB_WEAK` bind and a `st_value` of 0
345     #[inline]
is_import(&self) -> bool346     pub fn is_import(&self) -> bool {
347         let bind = self.st_bind();
348         (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0
349     }
350     /// Checks whether this `Sym` has type `STT_FUNC`
351     #[inline]
is_function(&self) -> bool352     pub fn is_function(&self) -> bool {
353         st_type(self.st_info) == STT_FUNC
354     }
355     /// Get the ST bind.
356     ///
357     /// This is the first four bits of the "info" byte.
358     #[inline]
st_bind(&self) -> u8359     pub fn st_bind(&self) -> u8 {
360         self.st_info >> 4
361     }
362     /// Get the ST type.
363     ///
364     /// This is the last four bits of the "info" byte.
365     #[inline]
st_type(&self) -> u8366     pub fn st_type(&self) -> u8 {
367         st_type(self.st_info)
368     }
369     /// Get the ST visibility.
370     ///
371     /// This is the last three bits of the "other" byte.
372     #[inline]
st_visibility(&self) -> u8373     pub fn st_visibility(&self) -> u8 {
374         st_visibility(self.st_other)
375     }
376     #[cfg(feature = "endian_fd")]
377     /// Parse `count` vector of ELF symbols from `offset`
parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>>378     pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>> {
379         let mut syms = Vec::with_capacity(count);
380         for _ in 0..count {
381             let sym = bytes.gread_with(&mut offset, ctx)?;
382             syms.push(sym);
383         }
384         Ok(syms)
385     }
386 }
387 
388 impl fmt::Debug for Sym {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result389     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
390         let bind = self.st_bind();
391         let typ = self.st_type();
392         let vis = self.st_visibility();
393         f.debug_struct("Sym")
394             .field("st_name", &self.st_name)
395             .field("st_info", &format_args!("0x{:x} {} {}", self.st_info, bind_to_str(bind), type_to_str(typ)))
396             .field("st_other", &format_args!("{} {}", self.st_other, visibility_to_str(vis)))
397             .field("st_shndx", &self.st_shndx)
398             .field("st_value", &format_args!("0x{:x}", self.st_value))
399             .field("st_size", &self.st_size)
400             .finish()
401     }
402 }
403 
404 impl ctx::SizeWith<Ctx> for Sym {
405     #[inline]
406     fn size_with(&Ctx {container, .. }: &Ctx) -> usize {
407         match container {
408             Container::Little => {
409                 sym32::SIZEOF_SYM
410             },
411             Container::Big => {
412                 sym64::SIZEOF_SYM
413             },
414         }
415     }
416 }
417 
418 if_alloc! {
419     impl<'a> ctx::TryFromCtx<'a, Ctx> for Sym {
420         type Error = crate::error::Error;
421         #[inline]
422         fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
423             let sym = match container {
424                 Container::Little => {
425                     (bytes.pread_with::<sym32::Sym>(0, le)?.into(), sym32::SIZEOF_SYM)
426                 },
427                 Container::Big => {
428                     (bytes.pread_with::<sym64::Sym>(0, le)?.into(), sym64::SIZEOF_SYM)
429                 }
430             };
431             Ok(sym)
432         }
433     }
434 
435     impl ctx::TryIntoCtx<Ctx> for Sym {
436         type Error = crate::error::Error;
437         #[inline]
438         fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
439             match container {
440                 Container::Little => {
441                     let sym: sym32::Sym = self.into();
442                     Ok(bytes.pwrite_with(sym, 0, le)?)
443                 },
444                 Container::Big => {
445                     let sym: sym64::Sym = self.into();
446                     Ok(bytes.pwrite_with(sym, 0, le)?)
447                 }
448             }
449         }
450     }
451 
452     impl ctx::IntoCtx<Ctx> for Sym {
453         #[inline]
454         fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
455             match container {
456                 Container::Little => {
457                     let sym: sym32::Sym = self.into();
458                     bytes.pwrite_with(sym, 0, le).unwrap();
459                 },
460                 Container::Big => {
461                     let sym: sym64::Sym = self.into();
462                     bytes.pwrite_with(sym, 0, le).unwrap();
463                 }
464             }
465         }
466     }
467 }
468 
469 if_alloc! {
470     #[derive(Default)]
471     /// An ELF symbol table, allowing lazy iteration over symbols
472     pub struct Symtab<'a> {
473         bytes: &'a [u8],
474         count: usize,
475         ctx: Ctx,
476         start: usize,
477         end: usize,
478     }
479 
480     impl<'a> Debug for Symtab<'a> {
481         fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
482             let len = self.bytes.len();
483             fmt.debug_struct("Symtab")
484                 .field("bytes", &len)
485                 .field("range", &format_args!("{:#x}..{:#x}", self.start, self.end))
486                 .field("count", &self.count)
487                 .field("Symbols", &self.to_vec())
488                 .finish()
489         }
490     }
491 
492     impl<'a> Symtab<'a> {
493         /// Parse a table of `count` ELF symbols from `offset`.
494         pub fn parse(bytes: &'a [u8], offset: usize, count: usize, ctx: Ctx) -> Result<Symtab<'a>> {
495             let size = count
496                 .checked_mul(Sym::size_with(&ctx))
497                 .ok_or_else(|| crate::error::Error::Malformed(
498                     format!("Too many ELF symbols (offset {:#x}, count {})", offset, count)
499                 ))?;
500             // TODO: make this a better error message when too large
501             let bytes = bytes.pread_with(offset, size)?;
502             Ok(Symtab { bytes, count, ctx, start: offset, end: offset+size })
503         }
504 
505         /// Try to parse a single symbol from the binary, at `index`.
506         #[inline]
507         pub fn get(&self, index: usize) -> Option<Sym> {
508             if index >= self.count {
509                 None
510             } else {
511                 Some(self.bytes.pread_with(index * Sym::size_with(&self.ctx), self.ctx).unwrap())
512             }
513         }
514 
515         /// The number of symbols in the table.
516         #[inline]
517         pub fn len(&self) -> usize {
518             self.count
519         }
520 
521         /// Returns true if table has no symbols.
522         #[inline]
523         pub fn is_empty(&self) -> bool {
524             self.count == 0
525         }
526 
527         /// Iterate over all symbols.
528         #[inline]
529         pub fn iter(&self) -> SymIterator<'a> {
530             self.into_iter()
531         }
532 
533         /// Parse all symbols into a vector.
534         pub fn to_vec(&self) -> Vec<Sym> {
535             self.iter().collect()
536         }
537     }
538 
539     impl<'a, 'b> IntoIterator for &'b Symtab<'a> {
540         type Item = <SymIterator<'a> as Iterator>::Item;
541         type IntoIter = SymIterator<'a>;
542 
543         #[inline]
544         fn into_iter(self) -> Self::IntoIter {
545             SymIterator {
546                 bytes: self.bytes,
547                 offset: 0,
548                 index: 0,
549                 count: self.count,
550                 ctx: self.ctx,
551             }
552         }
553     }
554 
555     /// An iterator over symbols in an ELF symbol table
556     pub struct SymIterator<'a> {
557         bytes: &'a [u8],
558         offset: usize,
559         index: usize,
560         count: usize,
561         ctx: Ctx,
562     }
563 
564     impl<'a> Iterator for SymIterator<'a> {
565         type Item = Sym;
566 
567         #[inline]
568         fn next(&mut self) -> Option<Self::Item> {
569             if self.index >= self.count {
570                 None
571             } else {
572                 self.index += 1;
573                 Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap())
574             }
575         }
576     }
577 
578     impl<'a> ExactSizeIterator for SymIterator<'a> {
579         #[inline]
580         fn len(&self) -> usize {
581             self.count - self.index
582         }
583     }
584 } // end if_alloc
585