elb/
symbols.rs

1use alloc::vec::Vec;
2use core::ops::Deref;
3use core::ops::DerefMut;
4
5use crate::BlockRead;
6use crate::BlockWrite;
7use crate::ByteOrder;
8use crate::Class;
9use crate::ElfRead;
10use crate::ElfWrite;
11use crate::EntityIo;
12use crate::Error;
13use crate::SymbolBinding;
14use crate::SymbolKind;
15use crate::SymbolVisibility;
16
17/// A symbol.
18#[derive(Debug)]
19#[cfg_attr(test, derive(PartialEq, Eq))]
20pub struct Symbol {
21    /// Address.
22    pub address: u64,
23    /// Associated size of zero if the size is unknown.
24    pub size: u64,
25    /// The offset of the name in the symbol string table.
26    pub name_offset: u32,
27    /// Relevant section index.
28    pub section_index: u16,
29    /// Binding.
30    pub binding: SymbolBinding,
31    /// Type.
32    pub kind: SymbolKind,
33    /// Visibility.
34    pub visibility: SymbolVisibility,
35}
36
37impl Symbol {
38    const fn info(&self) -> u8 {
39        self.binding.to_info_bits() | self.kind.to_info_bits()
40    }
41}
42
43impl EntityIo for Symbol {
44    fn read<R: ElfRead>(
45        reader: &mut R,
46        class: Class,
47        byte_order: ByteOrder,
48    ) -> Result<Self, Error> {
49        let name_offset = reader.read_u32(byte_order)?;
50        match class {
51            Class::Elf32 => {
52                let address = reader.read_word(class, byte_order)?;
53                let size = reader.read_u32(byte_order)? as u64;
54                let info = reader.read_u8()?;
55                let other = reader.read_u8()?;
56                let section_index = reader.read_u16(byte_order)?;
57                Ok(Self {
58                    name_offset,
59                    address,
60                    size,
61                    section_index,
62                    binding: SymbolBinding::from_info(info),
63                    kind: SymbolKind::from_info(info),
64                    visibility: SymbolVisibility::from_other(other),
65                })
66            }
67            Class::Elf64 => {
68                let info = reader.read_u8()?;
69                let other = reader.read_u8()?;
70                let section_index = reader.read_u16(byte_order)?;
71                let address = reader.read_word(class, byte_order)?;
72                let size = reader.read_u64(byte_order)?;
73                Ok(Self {
74                    name_offset,
75                    address,
76                    size,
77                    section_index,
78                    binding: SymbolBinding::from_info(info),
79                    kind: SymbolKind::from_info(info),
80                    visibility: SymbolVisibility::from_other(other),
81                })
82            }
83        }
84    }
85
86    fn write<W: ElfWrite>(
87        &self,
88        writer: &mut W,
89        class: Class,
90        byte_order: ByteOrder,
91    ) -> Result<(), Error> {
92        writer.write_u32(byte_order, self.name_offset)?;
93        match class {
94            Class::Elf32 => {
95                writer.write_word(class, byte_order, self.address)?;
96                writer.write_u32_as_u64(byte_order, self.size)?;
97                writer.write_u8(self.info())?;
98                writer.write_u8(self.visibility as u8)?;
99                writer.write_u16(byte_order, self.section_index)?;
100            }
101            Class::Elf64 => {
102                writer.write_u8(self.info())?;
103                writer.write_u8(self.visibility as u8)?;
104                writer.write_u16(byte_order, self.section_index)?;
105                writer.write_word(class, byte_order, self.address)?;
106                writer.write_u64(byte_order, self.size)?;
107            }
108        }
109        Ok(())
110    }
111}
112
113/// Symbol table.
114#[derive(Default)]
115#[cfg_attr(test, derive(PartialEq, Eq, Debug))]
116pub struct SymbolTable {
117    entries: Vec<Symbol>,
118}
119
120impl SymbolTable {
121    /// Create empty table.
122    pub fn new() -> Self {
123        Self::default()
124    }
125}
126
127impl BlockRead for SymbolTable {
128    fn read<R: ElfRead>(
129        reader: &mut R,
130        class: Class,
131        byte_order: ByteOrder,
132        len: u64,
133    ) -> Result<Self, Error> {
134        let mut entries = Vec::new();
135        let symbol_len = class.symbol_len();
136        for _ in 0..len / symbol_len as u64 {
137            let symbol = Symbol::read(reader, class, byte_order)?;
138            entries.push(symbol);
139        }
140        Ok(Self { entries })
141    }
142}
143
144impl BlockWrite for SymbolTable {
145    fn write<W: ElfWrite>(
146        &self,
147        writer: &mut W,
148        class: Class,
149        byte_order: ByteOrder,
150    ) -> Result<(), Error> {
151        for symbol in self.entries.iter() {
152            symbol.write(writer, class, byte_order)?;
153        }
154        Ok(())
155    }
156}
157
158impl Deref for SymbolTable {
159    type Target = Vec<Symbol>;
160    fn deref(&self) -> &Self::Target {
161        &self.entries
162    }
163}
164
165impl DerefMut for SymbolTable {
166    fn deref_mut(&mut self) -> &mut Self::Target {
167        &mut self.entries
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    use arbitrary::Unstructured;
176
177    use crate::constants::*;
178    use crate::test::test_block_io;
179    use crate::test::test_entity_io;
180    use crate::test::ArbitraryWithClass;
181
182    #[test]
183    fn symbol_io() {
184        test_entity_io::<Symbol>();
185    }
186
187    #[test]
188    fn symbol_table_io() {
189        test_block_io::<SymbolTable>();
190    }
191
192    impl ArbitraryWithClass<'_> for Symbol {
193        fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
194            let info = u.arbitrary()?;
195            Ok(match class {
196                Class::Elf32 => Self {
197                    address: u.arbitrary::<u32>()?.into(),
198                    size: u.arbitrary::<u32>()?.into(),
199                    name_offset: u.arbitrary()?,
200                    section_index: u.arbitrary()?,
201                    binding: SymbolBinding::from_info(info),
202                    kind: SymbolKind::from_info(info),
203                    visibility: u.arbitrary()?,
204                },
205                Class::Elf64 => Self {
206                    address: u.arbitrary()?,
207                    size: u.arbitrary()?,
208                    name_offset: u.arbitrary()?,
209                    section_index: u.arbitrary()?,
210                    binding: SymbolBinding::from_info(info),
211                    kind: SymbolKind::from_info(info),
212                    visibility: u.arbitrary()?,
213                },
214            })
215        }
216    }
217
218    impl ArbitraryWithClass<'_> for SymbolTable {
219        fn arbitrary(u: &mut Unstructured<'_>, class: Class) -> arbitrary::Result<Self> {
220            let num_entries = u.arbitrary_len::<[u8; SYMBOL_LEN_64]>()?;
221            let mut entries = Vec::with_capacity(num_entries);
222            for _ in 0..num_entries {
223                entries.push(Symbol::arbitrary(u, class)?);
224            }
225            Ok(Self { entries })
226        }
227    }
228}