1use crate::endian::EndianParse;
3use crate::file::Class;
4use crate::parse::{ParseAt, ParseError, ParsingIterator};
5
6pub type RelIterator<'data, E> = ParsingIterator<'data, E, Rel>;
7pub type RelaIterator<'data, E> = ParsingIterator<'data, E, Rela>;
8
9#[derive(Debug)]
13#[repr(C)]
14pub struct Elf32_Rel {
15 pub r_offset: u32,
16 pub r_info: u32,
17}
18
19#[derive(Debug)]
23#[repr(C)]
24pub struct Elf64_Rel {
25 pub r_offset: u64,
26 pub r_info: u64,
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30pub struct Rel {
31 pub r_offset: u64,
32 pub r_sym: u32,
33 pub r_type: u32,
34}
35
36impl ParseAt for Rel {
37 fn parse_at<E: EndianParse>(
38 endian: E,
39 class: Class,
40 offset: &mut usize,
41 data: &[u8],
42 ) -> Result<Self, ParseError> {
43 match class {
44 Class::ELF32 => {
45 let r_offset = endian.parse_u32_at(offset, data)? as u64;
46 let r_info = endian.parse_u32_at(offset, data)?;
47 Ok(Rel {
48 r_offset,
49 r_sym: r_info >> 8,
50 r_type: r_info & 0xFF,
51 })
52 }
53 Class::ELF64 => {
54 let r_offset = endian.parse_u64_at(offset, data)?;
55 let r_info = endian.parse_u64_at(offset, data)?;
56 Ok(Rel {
57 r_offset,
58 r_sym: (r_info >> 32) as u32,
59 r_type: (r_info & 0xFFFFFFFF) as u32,
60 })
61 }
62 }
63 }
64
65 #[inline]
66 fn size_for(class: Class) -> usize {
67 match class {
68 Class::ELF32 => 8,
69 Class::ELF64 => 16,
70 }
71 }
72}
73
74#[derive(Debug)]
78#[repr(C)]
79pub struct Elf32_Rela {
80 pub r_offset: u32,
81 pub r_info: u32,
82 pub r_addend: i32,
83}
84
85#[derive(Debug)]
89#[repr(C)]
90pub struct Elf64_Rela {
91 pub r_offset: u64,
92 pub r_info: u64,
93 pub r_addend: i64,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97pub struct Rela {
98 pub r_offset: u64,
99 pub r_sym: u32,
100 pub r_type: u32,
101 pub r_addend: i64,
102}
103
104impl ParseAt for Rela {
105 fn parse_at<E: EndianParse>(
106 endian: E,
107 class: Class,
108 offset: &mut usize,
109 data: &[u8],
110 ) -> Result<Self, ParseError> {
111 match class {
112 Class::ELF32 => {
113 let r_offset = endian.parse_u32_at(offset, data)? as u64;
114 let r_info = endian.parse_u32_at(offset, data)?;
115 let r_addend = endian.parse_i32_at(offset, data)? as i64;
116 Ok(Rela {
117 r_offset,
118 r_sym: r_info >> 8,
119 r_type: r_info & 0xFF,
120 r_addend,
121 })
122 }
123 Class::ELF64 => {
124 let r_offset = endian.parse_u64_at(offset, data)?;
125 let r_info = endian.parse_u64_at(offset, data)?;
126 let r_addend = endian.parse_i64_at(offset, data)?;
127 Ok(Rela {
128 r_offset,
129 r_sym: (r_info >> 32) as u32,
130 r_type: (r_info & 0xFFFFFFFF) as u32,
131 r_addend,
132 })
133 }
134 }
135 }
136
137 #[inline]
138 fn size_for(class: Class) -> usize {
139 match class {
140 Class::ELF32 => 12,
141 Class::ELF64 => 24,
142 }
143 }
144}
145
146#[cfg(test)]
147mod parse_tests {
148 use super::*;
149 use crate::endian::{BigEndian, LittleEndian};
150 use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
151
152 #[test]
153 fn parse_rel32_lsb() {
154 test_parse_for(
155 LittleEndian,
156 Class::ELF32,
157 Rel {
158 r_offset: 0x03020100,
159 r_sym: 0x00070605,
160 r_type: 0x00000004,
161 },
162 );
163 }
164
165 #[test]
166 fn parse_rel32_msb() {
167 test_parse_for(
168 BigEndian,
169 Class::ELF32,
170 Rel {
171 r_offset: 0x00010203,
172 r_sym: 0x00040506,
173 r_type: 0x00000007,
174 },
175 );
176 }
177
178 #[test]
179 fn parse_rel64_lsb() {
180 test_parse_for(
181 LittleEndian,
182 Class::ELF64,
183 Rel {
184 r_offset: 0x0706050403020100,
185 r_sym: 0x0F0E0D0C,
186 r_type: 0x0B0A0908,
187 },
188 );
189 }
190
191 #[test]
192 fn parse_rel64_msb() {
193 test_parse_for(
194 BigEndian,
195 Class::ELF64,
196 Rel {
197 r_offset: 0x0001020304050607,
198 r_sym: 0x08090A0B,
199 r_type: 0x0C0D0E0F,
200 },
201 );
202 }
203
204 #[test]
205 fn parse_rel32_lsb_fuzz_too_short() {
206 test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF32);
207 }
208
209 #[test]
210 fn parse_rel32_msb_fuzz_too_short() {
211 test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF32);
212 }
213
214 #[test]
215 fn parse_rel64_lsb_fuzz_too_short() {
216 test_parse_fuzz_too_short::<_, Rel>(LittleEndian, Class::ELF64);
217 }
218
219 #[test]
220 fn parse_rel64_msb_fuzz_too_short() {
221 test_parse_fuzz_too_short::<_, Rel>(BigEndian, Class::ELF64);
222 }
223
224 #[test]
225 fn parse_rela32_lsb() {
226 test_parse_for(
227 LittleEndian,
228 Class::ELF32,
229 Rela {
230 r_offset: 0x03020100,
231 r_sym: 0x00070605,
232 r_type: 0x00000004,
233 r_addend: 0x0B0A0908,
234 },
235 );
236 }
237
238 #[test]
239 fn parse_rela32_msb() {
240 test_parse_for(
241 BigEndian,
242 Class::ELF32,
243 Rela {
244 r_offset: 0x00010203,
245 r_sym: 0x00040506,
246 r_type: 0x00000007,
247 r_addend: 0x08090A0B,
248 },
249 );
250 }
251
252 #[test]
253 fn parse_rela64_lsb() {
254 test_parse_for(
255 LittleEndian,
256 Class::ELF64,
257 Rela {
258 r_offset: 0x0706050403020100,
259 r_sym: 0x0F0E0D0C,
260 r_type: 0x0B0A0908,
261 r_addend: 0x1716151413121110,
262 },
263 );
264 }
265
266 #[test]
267 fn parse_rela64_msb() {
268 test_parse_for(
269 BigEndian,
270 Class::ELF64,
271 Rela {
272 r_offset: 0x0001020304050607,
273 r_sym: 0x08090A0B,
274 r_type: 0x0C0D0E0F,
275 r_addend: 0x1011121314151617,
276 },
277 );
278 }
279
280 #[test]
281 fn parse_rela32_lsb_fuzz_too_short() {
282 test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF32);
283 }
284
285 #[test]
286 fn parse_rela32_msb_fuzz_too_short() {
287 test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF32);
288 }
289
290 #[test]
291 fn parse_rela64_lsb_fuzz_too_short() {
292 test_parse_fuzz_too_short::<_, Rela>(LittleEndian, Class::ELF64);
293 }
294
295 #[test]
296 fn parse_rela64_msb_fuzz_too_short() {
297 test_parse_fuzz_too_short::<_, Rela>(BigEndian, Class::ELF64);
298 }
299}