1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Type definitions for 32-bit ELF binaries.

use crate::*;
use serde::{Deserialize, Serialize};

/// Symbol32 is a entry of symbol table section.
///
/// Symbol32 はシンボルテーブルセクションのエントリである.
/// ELF32で用いることを想定している.
///
///
/// Defaultトレイトを実装しているので,
/// `Default::default()` を呼び出すことで簡単にNULLシンボルを作成できる.
///
/// # Examples
///
/// ```
/// use elf_utilities::symbol::Symbol32;
/// let null_sym : Symbol32 = Default::default();
///
/// // Symbol32::new_null_symbol() のエイリアスでも作成可能.
/// let null_sym2 : Symbol32 = Symbol32::new_null_symbol();
///
/// assert_eq!(null_sym, null_sym2);
///
/// ```
///
/// ELFファイルを生成する用途でこのライブラリを使用できるように,
/// バイト列への変換もサポートしている.
///
/// # Examples
///
/// ```
/// use elf_utilities::symbol::Symbol32;
/// let null_sym : Symbol32 = Default::default();
///
/// // to_le_bytes() を利用してバイト列に変換できる.
/// let sym_bytes = null_sym.to_le_bytes();
/// assert_eq!(Symbol32::size() as usize, sym_bytes.len())
/// ```
#[derive(Default, Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
#[repr(C)]
pub struct Symbol32 {
    /// Symbol name index.
    pub st_name: Elf32Word,

    /// Symbol's value.
    pub st_value: Elf32Addr,

    /// Symbol's size.
    pub st_size: Elf32Word,

    /// Information that includes [symbol binds and symbol types](https://docs.rs/elf-utilities/latest/elf_utilities/symbol/elf32/index.html#constants).
    pub st_info: u8,

    /// Symbol's visibility.
    /// See [symbol::VISIBILITY](https://docs.rs/elf-utilities/latest/elf_utilities/symbol/symbol_visibility/enum.VISIBILITY.html).
    pub st_other: u8,

    /// A section table index that includes the symbol.
    pub st_shndx: Elf32Section,

    /// option member for utilities.
    #[serde(skip_serializing)]
    #[serde(skip_deserializing)]
    pub symbol_name: Option<String>,
}

#[allow(dead_code)]
impl Symbol32 {
    pub fn new_null_symbol() -> Self {
        Default::default()
    }
    /// size() provides Symbol32's size used by Shdr32.sh_entsize or else.
    pub fn size() -> Elf32Xword {
        0x10
    }

    /// for utilities
    pub fn compare_by<P>(&self, predicate: P) -> bool
    where
        P: Fn(&Self) -> bool,
    {
        predicate(self)
    }

    pub fn get_type(&self) -> symbol::Type {
        symbol::Type::from(self.st_info & 0x0f)
    }

    pub fn get_bind(&self) -> symbol::Bind {
        symbol::Bind::from(self.st_info >> 4)
    }
    pub fn get_visibility(&self) -> symbol::Visibility {
        symbol::Visibility::from(self.st_other & 0x03)
    }

    /// Set symbol's information to Symbol32
    /// # Examples
    ///
    /// ```
    /// use elf_utilities::symbol;
    /// let mut null_sym = symbol::Symbol32::new_null_symbol();
    ///
    /// null_sym.set_info(symbol::Type::Func, symbol::Bind::Global);
    ///
    /// assert_eq!((1 << 4) | 2, null_sym.st_info);
    /// ```
    pub fn set_info(&mut self, sym_type: symbol::Type, bind: symbol::Bind) {
        self.st_info = bind.to_byte() << 4 | sym_type.to_byte();
    }

    /// Create Vec<u8> from Symbol32's each fields.
    ///
    /// # Examples
    ///
    /// ```
    /// use elf_utilities::symbol::Symbol32;
    /// let null_sym : Symbol32 = Default::default();
    ///
    /// assert_eq!([0].repeat(Symbol32::size() as usize), null_sym.to_le_bytes());
    /// ```
    pub fn to_le_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    pub fn deserialize(buf: &[u8], start: usize) -> Result<Self, Box<dyn std::error::Error>> {
        // bincode::ErrorKindをトレイトオブジェクトとするため,この冗長な書き方が必要
        match bincode::deserialize(&buf[start..]) {
            Ok(header) => Ok(header),
            Err(e) => Err(e),
        }
    }
}