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
use super::{Address, Error, Encoding, Index, Entry};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SymbolBinding {
    Local,
    Global,
    Weak,
    OsSpecific(u8),
    ProcessorSpecific(u8),
    Unknown(u8),
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SymbolType {
    Nothing,
    Object,
    Function,
    Section,
    File,
    OsSpecific(u8),
    ProcessorSpecific(u8),
    Unknown(u8),
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SymbolInfo {
    pub binding: SymbolBinding,
    pub ty: SymbolType,
}

impl From<u8> for SymbolInfo {
    fn from(v: u8) -> Self {
        SymbolInfo {
            binding: match (v & 0xf0) / 0x10 {
                0x00 => SymbolBinding::Local,
                0x01 => SymbolBinding::Global,
                0x02 => SymbolBinding::Weak,
                t @ 0x0a..=0x0c => SymbolBinding::OsSpecific(t - 0x0a),
                t @ 0x0d..=0x0f => SymbolBinding::ProcessorSpecific(t - 0x0d),
                t => SymbolBinding::Unknown(t),
            },
            ty: match v & 0x0f {
                0x00 => SymbolType::Nothing,
                0x01 => SymbolType::Object,
                0x02 => SymbolType::Function,
                0x03 => SymbolType::Section,
                0x04 => SymbolType::File,
                t @ 0x0a..=0x0c => SymbolType::OsSpecific(t - 0x0a),
                t @ 0x0d..=0x0f => SymbolType::ProcessorSpecific(t - 0x0d),
                t => SymbolType::Unknown(t),
            },
        }
    }
}

impl From<SymbolInfo> for u8 {
    fn from(v: SymbolInfo) -> Self {
        let SymbolInfo { binding, ty } = v;
        let high = match binding {
            SymbolBinding::Local => 0x00,
            SymbolBinding::Global => 0x01,
            SymbolBinding::Weak => 0x02,
            SymbolBinding::OsSpecific(t) => t + 0x0a,
            SymbolBinding::ProcessorSpecific(t) => t + 0x0d,
            SymbolBinding::Unknown(t) => t,
        };
        let low = match ty {
            SymbolType::Nothing => 0x00,
            SymbolType::Object => 0x01,
            SymbolType::Function => 0x02,
            SymbolType::Section => 0x03,
            SymbolType::File => 0x04,
            SymbolType::OsSpecific(t) => t + 0x0a,
            SymbolType::ProcessorSpecific(t) => t + 0x0d,
            SymbolType::Unknown(t) => t,
        };
        high * 0x10 + low
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SymbolEntry {
    pub name: u32,
    pub info: SymbolInfo,
    pub reserved: u8,
    pub section_index: Index,
    pub value: Address,
    pub size: u64,
}

impl Entry for SymbolEntry {
    type Error = Error;

    const SIZE: usize = 0x18;

    fn new(slice: &[u8], encoding: Encoding) -> Result<Self, Self::Error> {
        if slice.len() < Self::SIZE {
            return Err(Error::SliceTooShort);
        }

        Ok(SymbolEntry {
            name: read_int!(&slice[0x00..], &encoding, u32),
            info: slice[0x04].into(),
            reserved: slice[0x05],
            section_index: read_int!(&slice[0x06..], &encoding, u16).into(),
            value: read_int!(&slice[0x08..], &encoding, u64),
            size: read_int!(&slice[0x10..], &encoding, u64),
        })
    }
}