1pub const STB_LOCAL: u8 = 0;
4pub const STB_GLOBAL: u8 = 1;
6pub const STB_WEAK: u8 = 2;
8pub const STB_NUM: u8 = 3;
10pub const STB_LOOS: u8 = 10;
12pub const STB_GNU_UNIQUE: u8 = 10;
14pub const STB_HIOS: u8 = 12;
16pub const STB_LOPROC: u8 = 13;
18pub const STB_HIPROC: u8 = 15;
20
21pub const STT_NOTYPE: u8 = 0;
24pub const STT_OBJECT: u8 = 1;
26pub const STT_FUNC: u8 = 2;
28pub const STT_SECTION: u8 = 3;
30pub const STT_FILE: u8 = 4;
32pub const STT_COMMON: u8 = 5;
34pub const STT_TLS: u8 = 6;
36pub const STT_NUM: u8 = 7;
38pub const STT_LOOS: u8 = 10;
40pub const STT_GNU_IFUNC: u8 = 10;
42pub const STT_HIOS: u8 = 12;
44pub const STT_LOPROC: u8 = 13;
46pub const STT_HIPROC: u8 = 15;
48
49pub const STV_DEFAULT: u8 = 0;
52pub const STV_INTERNAL: u8 = 1;
54pub const STV_HIDDEN: u8 = 2;
57pub const STV_PROTECTED: u8 = 3;
61pub const STV_EXPORTED: u8 = 4;
64pub const STV_SINGLETON: u8 = 5;
67pub const STV_ELIMINATE: u8 = 6;
70
71#[inline]
75pub fn st_bind(info: u8) -> u8 {
76 info >> 4
77}
78
79#[inline]
83pub fn st_type(info: u8) -> u8 {
84 info & 0xf
85}
86
87#[inline]
91pub fn st_visibility(other: u8) -> u8 {
92 other & 0x7
93}
94
95#[inline]
97pub fn is_import(info: u8, value: u64) -> bool {
98 let bind = st_bind(info);
99 bind == STB_GLOBAL && value == 0
100}
101
102#[inline]
104pub fn get_type(info: u8) -> &'static str {
105 type_to_str(st_type(info))
106}
107
108#[inline]
110pub 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#[inline]
123pub 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#[inline]
140pub 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
153macro_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 #[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 #[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 #[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 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")]
268use scroll::{Pread, Pwrite, SizeWith};
269
270pub 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 pub struct Sym {
278 pub st_name: u32,
280 pub st_value: u32,
282 pub st_size: u32,
284 pub st_info: u8,
286 pub st_other: u8,
288 pub st_shndx: u16,
290 }
291
292 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
300pub 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 pub struct Sym {
308 pub st_name: u32,
310 pub st_info: u8,
312 pub st_other: u8,
314 pub st_shndx: u16,
316 pub st_value: u64,
318 pub st_size: u64,
320 }
321
322 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
330use crate::container::{Container, Ctx};
331#[cfg(feature = "alloc")]
332use crate::error::Result;
333#[cfg(feature = "alloc")]
334use alloc::vec::Vec;
335use core::fmt;
336use scroll::ctx;
337use scroll::ctx::SizeWith;
338
339#[derive(Clone, Copy, PartialEq, Default)]
340pub struct Sym {
342 pub st_name: usize,
343 pub st_info: u8,
344 pub st_other: u8,
345 pub st_shndx: usize,
346 pub st_value: u64,
347 pub st_size: u64,
348}
349
350impl Sym {
351 #[inline]
352 pub fn size(container: Container) -> usize {
353 Self::size_with(&Ctx::from(container))
354 }
355 #[inline]
357 pub fn is_import(&self) -> bool {
358 let bind = self.st_bind();
359 (bind == STB_GLOBAL || bind == STB_WEAK) && self.st_value == 0
360 }
361 #[inline]
363 pub fn is_function(&self) -> bool {
364 st_type(self.st_info) == STT_FUNC
365 }
366 #[inline]
370 pub fn st_bind(&self) -> u8 {
371 self.st_info >> 4
372 }
373 #[inline]
377 pub fn st_type(&self) -> u8 {
378 st_type(self.st_info)
379 }
380 #[inline]
384 pub fn st_visibility(&self) -> u8 {
385 st_visibility(self.st_other)
386 }
387 #[cfg(feature = "endian_fd")]
388 pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> Result<Vec<Sym>> {
390 if count > bytes.len() / Sym::size_with(&ctx) {
391 return Err(crate::error::Error::BufferTooShort(count, "symbols"));
392 }
393 let mut syms = Vec::with_capacity(count);
394 for _ in 0..count {
395 let sym = bytes.gread_with(&mut offset, ctx)?;
396 syms.push(sym);
397 }
398 Ok(syms)
399 }
400}
401
402impl fmt::Debug for Sym {
403 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
404 let bind = self.st_bind();
405 let typ = self.st_type();
406 let vis = self.st_visibility();
407 f.debug_struct("Sym")
408 .field("st_name", &self.st_name)
409 .field(
410 "st_info",
411 &format_args!(
412 "0x{:x} {} {}",
413 self.st_info,
414 bind_to_str(bind),
415 type_to_str(typ)
416 ),
417 )
418 .field(
419 "st_other",
420 &format_args!("{} {}", self.st_other, visibility_to_str(vis)),
421 )
422 .field("st_shndx", &self.st_shndx)
423 .field("st_value", &format_args!("0x{:x}", self.st_value))
424 .field("st_size", &self.st_size)
425 .finish()
426 }
427}
428
429impl ctx::SizeWith<Ctx> for Sym {
430 #[inline]
431 fn size_with(&Ctx { container, .. }: &Ctx) -> usize {
432 match container {
433 Container::Little => sym32::SIZEOF_SYM,
434 Container::Big => sym64::SIZEOF_SYM,
435 }
436 }
437}
438
439if_alloc! {
440 use core::result;
441
442 impl<'a> ctx::TryFromCtx<'a, Ctx> for Sym {
443 type Error = crate::error::Error;
444 #[inline]
445 fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
446 let sym = match container {
447 Container::Little => {
448 (bytes.pread_with::<sym32::Sym>(0, le)?.into(), sym32::SIZEOF_SYM)
449 },
450 Container::Big => {
451 (bytes.pread_with::<sym64::Sym>(0, le)?.into(), sym64::SIZEOF_SYM)
452 }
453 };
454 Ok(sym)
455 }
456 }
457
458 impl ctx::TryIntoCtx<Ctx> for Sym {
459 type Error = crate::error::Error;
460 #[inline]
461 fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
462 match container {
463 Container::Little => {
464 let sym: sym32::Sym = self.into();
465 Ok(bytes.pwrite_with(sym, 0, le)?)
466 },
467 Container::Big => {
468 let sym: sym64::Sym = self.into();
469 Ok(bytes.pwrite_with(sym, 0, le)?)
470 }
471 }
472 }
473 }
474
475 impl ctx::IntoCtx<Ctx> for Sym {
476 #[inline]
477 fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
478 match container {
479 Container::Little => {
480 let sym: sym32::Sym = self.into();
481 bytes.pwrite_with(sym, 0, le).unwrap();
482 },
483 Container::Big => {
484 let sym: sym64::Sym = self.into();
485 bytes.pwrite_with(sym, 0, le).unwrap();
486 }
487 }
488 }
489 }
490}
491
492if_alloc! {
493 #[derive(Default)]
494 pub struct Symtab<'a> {
496 bytes: &'a [u8],
497 count: usize,
498 ctx: Ctx,
499 start: usize,
500 end: usize,
501 }
502
503 impl<'a> fmt::Debug for Symtab<'a> {
504 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
505 let len = self.bytes.len();
506 fmt.debug_struct("Symtab")
507 .field("bytes", &len)
508 .field("range", &format_args!("{:#x}..{:#x}", self.start, self.end))
509 .field("count", &self.count)
510 .field("Symbols", &self.to_vec())
511 .finish()
512 }
513 }
514
515 impl<'a> Symtab<'a> {
516 pub fn parse(bytes: &'a [u8], offset: usize, count: usize, ctx: Ctx) -> Result<Symtab<'a>> {
518 let size = count
519 .checked_mul(Sym::size_with(&ctx))
520 .ok_or_else(|| crate::error::Error::Malformed(
521 format!("Too many ELF symbols (offset {:#x}, count {})", offset, count)
522 ))?;
523 let bytes = bytes.pread_with(offset, size)?;
525 Ok(Symtab { bytes, count, ctx, start: offset, end: offset+size })
526 }
527
528 #[inline]
530 pub fn get(&self, index: usize) -> Option<Sym> {
531 if index >= self.count {
532 None
533 } else {
534 Some(self.bytes.pread_with(index * Sym::size_with(&self.ctx), self.ctx).unwrap())
535 }
536 }
537
538 #[inline]
540 pub fn len(&self) -> usize {
541 self.count
542 }
543
544 #[inline]
546 pub fn offset(&self) -> usize {
547 self.start
548 }
549
550 #[inline]
552 pub fn ctx(&self) -> &Ctx {
553 &self.ctx
554 }
555
556 #[inline]
558 pub fn is_empty(&self) -> bool {
559 self.count == 0
560 }
561
562 #[inline]
564 pub fn iter(&self) -> SymIterator<'a> {
565 self.into_iter()
566 }
567
568 pub fn to_vec(&self) -> Vec<Sym> {
570 self.iter().collect()
571 }
572 }
573
574 impl<'a, 'b> IntoIterator for &'b Symtab<'a> {
575 type Item = <SymIterator<'a> as Iterator>::Item;
576 type IntoIter = SymIterator<'a>;
577
578 #[inline]
579 fn into_iter(self) -> Self::IntoIter {
580 SymIterator {
581 bytes: self.bytes,
582 offset: 0,
583 index: 0,
584 count: self.count,
585 ctx: self.ctx,
586 }
587 }
588 }
589
590 pub struct SymIterator<'a> {
592 bytes: &'a [u8],
593 offset: usize,
594 index: usize,
595 count: usize,
596 ctx: Ctx,
597 }
598
599 impl<'a> Iterator for SymIterator<'a> {
600 type Item = Sym;
601
602 #[inline]
603 fn next(&mut self) -> Option<Self::Item> {
604 if self.index >= self.count {
605 None
606 } else {
607 self.index += 1;
608 Some(self.bytes.gread_with(&mut self.offset, self.ctx).unwrap())
609 }
610 }
611 }
612
613 impl<'a> ExactSizeIterator for SymIterator<'a> {
614 #[inline]
615 fn len(&self) -> usize {
616 self.count - self.index
617 }
618 }
619}