1use crate::abi;
3use crate::endian::EndianParse;
4use crate::file::Class;
5use crate::parse::{ParseAt, ParseError, ParsingTable};
6
7pub type SymbolTable<'data, E> = ParsingTable<'data, E, Symbol>;
8
9#[derive(Debug)]
13#[repr(C)]
14pub struct Elf32_Sym {
15 pub st_name: u32,
16 pub st_value: u32,
17 pub st_size: u32,
18 pub st_info: u8,
19 pub st_other: u8,
20 pub st_shndx: u32,
21}
22
23#[derive(Debug)]
27#[repr(C)]
28pub struct Elf64_Sym {
29 pub st_name: u32,
30 pub st_info: u8,
31 pub st_other: u8,
32 pub st_shndx: u16,
33 pub st_value: u64,
34 pub st_size: u64,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Symbol {
39 pub st_name: u32,
44
45 pub st_shndx: u16,
54
55 pub(super) st_info: u8,
57
58 pub(super) st_other: u8,
60
61 pub st_value: u64,
75
76 pub st_size: u64,
81}
82
83impl Symbol {
84 pub fn is_undefined(&self) -> bool {
89 self.st_shndx == abi::SHN_UNDEF
90 }
91
92 pub fn st_symtype(&self) -> u8 {
93 self.st_info & 0xf
94 }
95
96 pub fn st_bind(&self) -> u8 {
97 self.st_info >> 4
98 }
99
100 pub fn st_vis(&self) -> u8 {
101 self.st_other & 0x3
102 }
103}
104
105impl ParseAt for Symbol {
106 fn parse_at<E: EndianParse>(
107 endian: E,
108 class: Class,
109 offset: &mut usize,
110 data: &[u8],
111 ) -> Result<Self, ParseError> {
112 let st_name: u32;
113 let st_value: u64;
114 let st_size: u64;
115 let st_shndx: u16;
116 let st_info: u8;
117 let st_other: u8;
118
119 if class == Class::ELF32 {
120 st_name = endian.parse_u32_at(offset, data)?;
121 st_value = endian.parse_u32_at(offset, data)? as u64;
122 st_size = endian.parse_u32_at(offset, data)? as u64;
123 st_info = endian.parse_u8_at(offset, data)?;
124 st_other = endian.parse_u8_at(offset, data)?;
125 st_shndx = endian.parse_u16_at(offset, data)?;
126 } else {
127 st_name = endian.parse_u32_at(offset, data)?;
128 st_info = endian.parse_u8_at(offset, data)?;
129 st_other = endian.parse_u8_at(offset, data)?;
130 st_shndx = endian.parse_u16_at(offset, data)?;
131 st_value = endian.parse_u64_at(offset, data)?;
132 st_size = endian.parse_u64_at(offset, data)?;
133 }
134
135 Ok(Symbol {
136 st_name,
137 st_value,
138 st_size,
139 st_shndx,
140 st_info,
141 st_other,
142 })
143 }
144
145 #[inline]
146 fn size_for(class: Class) -> usize {
147 match class {
148 Class::ELF32 => 16,
149 Class::ELF64 => 24,
150 }
151 }
152}
153
154#[cfg(test)]
155mod symbol_tests {
156 use super::*;
157
158 #[test]
159 fn symbol_undefined() {
160 let undef_sym = Symbol {
161 st_name: 0,
162 st_value: 0,
163 st_size: 0,
164 st_shndx: 0,
165 st_info: 0,
166 st_other: 0,
167 };
168 assert!(undef_sym.is_undefined());
169
170 let def_sym = Symbol {
171 st_name: 0,
172 st_value: 0,
173 st_size: 0,
174 st_shndx: 42,
175 st_info: 0,
176 st_other: 0,
177 };
178 assert!(!def_sym.is_undefined());
179 }
180}
181
182#[cfg(test)]
183mod parse_tests {
184 use super::*;
185 use crate::endian::{BigEndian, LittleEndian};
186 use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
187
188 #[test]
189 fn parse_sym32_lsb() {
190 test_parse_for(
191 LittleEndian,
192 Class::ELF32,
193 Symbol {
194 st_name: 0x03020100,
195 st_value: 0x07060504,
196 st_size: 0x0B0A0908,
197 st_shndx: 0x0F0E,
198 st_info: 0x0C,
199 st_other: 0x0D,
200 },
201 );
202 }
203
204 #[test]
205 fn parse_sym32_msb() {
206 test_parse_for(
207 BigEndian,
208 Class::ELF32,
209 Symbol {
210 st_name: 0x00010203,
211 st_value: 0x04050607,
212 st_size: 0x08090A0B,
213 st_shndx: 0x0E0F,
214 st_info: 0x0C,
215 st_other: 0x0D,
216 },
217 );
218 }
219
220 #[test]
221 fn parse_sym64_lsb() {
222 test_parse_for(
223 LittleEndian,
224 Class::ELF64,
225 Symbol {
226 st_name: 0x03020100,
227 st_value: 0x0F0E0D0C0B0A0908,
228 st_size: 0x1716151413121110,
229 st_shndx: 0x0706,
230 st_info: 0x04,
231 st_other: 0x05,
232 },
233 );
234 }
235
236 #[test]
237 fn parse_sym64_msb() {
238 test_parse_for(
239 BigEndian,
240 Class::ELF64,
241 Symbol {
242 st_name: 0x00010203,
243 st_value: 0x08090A0B0C0D0E0F,
244 st_size: 0x1011121314151617,
245 st_shndx: 0x0607,
246 st_info: 0x04,
247 st_other: 0x05,
248 },
249 );
250 }
251
252 #[test]
253 fn parse_sym32_lsb_fuzz_too_short() {
254 test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF32);
255 }
256
257 #[test]
258 fn parse_sym32_msb_fuzz_too_short() {
259 test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF32);
260 }
261
262 #[test]
263 fn parse_sym64_lsb_fuzz_too_short() {
264 test_parse_fuzz_too_short::<_, Symbol>(LittleEndian, Class::ELF64);
265 }
266
267 #[test]
268 fn parse_sym64_msb_fuzz_too_short() {
269 test_parse_fuzz_too_short::<_, Symbol>(BigEndian, Class::ELF64);
270 }
271}