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