1use core::convert::TryInto;
2use core::fmt::Debug;
3use core::slice;
4
5use crate::elf;
6use crate::endian;
7use crate::pod::Pod;
8use crate::read::{ReadError, ReadRef, Result, SectionIndex, StringTable};
9
10use super::{FileHeader, SectionHeader, SectionTable};
11
12#[derive(Debug, Clone, Copy)]
18pub struct DynamicTable<'data, Elf: FileHeader, R = &'data [u8]>
19where
20 R: ReadRef<'data>,
21{
22 endian: Elf::Endian,
23 dynamics: &'data [Elf::Dyn],
24 strings: StringTable<'data, R>,
25}
26
27impl<'data, Elf: FileHeader, R: ReadRef<'data>> Default for DynamicTable<'data, Elf, R> {
28 fn default() -> Self {
29 DynamicTable {
30 endian: Default::default(),
31 dynamics: &[],
32 strings: Default::default(),
33 }
34 }
35}
36
37impl<'data, Elf: FileHeader, R: ReadRef<'data>> DynamicTable<'data, Elf, R> {
38 pub(crate) fn parse(
40 endian: Elf::Endian,
41 data: R,
42 sections: &SectionTable<'data, Elf, R>,
43 section: &Elf::SectionHeader,
44 ) -> Result<DynamicTable<'data, Elf, R>> {
45 debug_assert!(section.sh_type(endian) == elf::SHT_DYNAMIC);
46
47 let dynamics = section
48 .data_as_array(endian, data)
49 .read_error("Invalid ELF dynamic table data")?;
50
51 let link = SectionIndex(section.sh_link(endian) as usize);
52 let strings = sections.strings(endian, data, link)?;
53
54 Ok(DynamicTable {
55 endian,
56 dynamics,
57 strings,
58 })
59 }
60
61 #[inline]
63 pub fn strings(&self) -> &StringTable<'data, R> {
64 &self.strings
65 }
66
67 #[inline]
72 pub fn dynamics(&self) -> &'data [Elf::Dyn] {
73 self.dynamics
74 }
75
76 #[inline]
80 pub fn iter(&self) -> DynamicIterator<'data, Elf> {
81 DynamicIterator::new(self.endian, self.dynamics)
82 }
83
84 #[inline]
86 pub fn is_empty(&self) -> bool {
87 self.dynamics.is_empty()
88 }
89
90 #[inline]
94 pub fn len(&self) -> usize {
95 self.dynamics.len()
96 }
97
98 pub fn string(&self, d: Dynamic) -> Result<&'data [u8]> {
102 d.string(&self.strings)
103 }
104}
105
106impl<'a, 'data, Elf: FileHeader, R: ReadRef<'data>> IntoIterator
107 for &'a DynamicTable<'data, Elf, R>
108{
109 type Item = Dynamic;
110 type IntoIter = DynamicIterator<'data, Elf>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.iter()
114 }
115}
116
117#[derive(Debug)]
119pub struct DynamicIterator<'data, Elf: FileHeader> {
120 endian: Elf::Endian,
121 dynamics: slice::Iter<'data, Elf::Dyn>,
122}
123
124impl<'data, Elf> DynamicIterator<'data, Elf>
125where
126 Elf: FileHeader,
127{
128 fn new(endian: Elf::Endian, dynamics: &'data [Elf::Dyn]) -> Self {
129 DynamicIterator {
130 endian,
131 dynamics: dynamics.iter(),
132 }
133 }
134}
135
136impl<'data, Elf: FileHeader> Iterator for DynamicIterator<'data, Elf> {
137 type Item = Dynamic;
138
139 fn next(&mut self) -> Option<Self::Item> {
140 let d = self.dynamics.next()?;
141 let tag = d.d_tag(self.endian).into();
142 if tag == elf::DT_NULL {
143 self.dynamics = [].iter();
144 return None;
145 }
146 let val = d.d_val(self.endian).into();
147 Some(Dynamic { tag, val })
148 }
149}
150
151#[derive(Debug, Clone, Copy)]
153pub struct Dynamic {
154 pub tag: i64,
158
159 pub val: u64,
163}
164
165impl Dynamic {
166 pub fn is_address(&self) -> bool {
168 tag_is_address(self.tag)
169 }
170
171 pub fn is_string(&self) -> bool {
173 tag_is_string(self.tag)
174 }
175
176 pub fn string<'data, R: ReadRef<'data>>(
180 &self,
181 strings: &StringTable<'data, R>,
182 ) -> Result<&'data [u8]> {
183 self.val
184 .try_into()
185 .ok()
186 .and_then(|val| strings.get(val).ok())
187 .read_error("Invalid ELF dyn string")
188 }
189}
190
191#[allow(missing_docs)]
193pub trait Dyn: Debug + Pod {
194 type Word: Into<u64>;
195 type Sword: Into<i64>;
196 type Endian: endian::Endian;
197
198 fn d_tag(&self, endian: Self::Endian) -> Self::Sword;
199 fn d_val(&self, endian: Self::Endian) -> Self::Word;
200
201 fn tag(&self, endian: Self::Endian) -> i64 {
205 self.d_tag(endian).into()
206 }
207
208 fn val(&self, endian: Self::Endian) -> u64 {
212 self.d_val(endian).into()
213 }
214
215 fn tag32(&self, endian: Self::Endian) -> Option<i32> {
217 self.d_tag(endian).into().try_into().ok()
218 }
219
220 fn val32(&self, endian: Self::Endian) -> Option<u32> {
222 self.d_val(endian).into().try_into().ok()
223 }
224
225 fn is_string(&self, endian: Self::Endian) -> bool {
227 tag_is_string(self.tag(endian))
228 }
229
230 fn string<'data, R: ReadRef<'data>>(
234 &self,
235 endian: Self::Endian,
236 strings: StringTable<'data, R>,
237 ) -> Result<&'data [u8]> {
238 self.val32(endian)
239 .and_then(|val| strings.get(val).ok())
240 .read_error("Invalid ELF dyn string")
241 }
242
243 fn is_address(&self, endian: Self::Endian) -> bool {
245 tag_is_address(self.tag(endian))
246 }
247}
248
249impl<Endian: endian::Endian> Dyn for elf::Dyn32<Endian> {
250 type Word = u32;
251 type Sword = i32;
252 type Endian = Endian;
253
254 #[inline]
255 fn d_tag(&self, endian: Self::Endian) -> Self::Sword {
256 self.d_tag.get(endian)
257 }
258
259 #[inline]
260 fn d_val(&self, endian: Self::Endian) -> Self::Word {
261 self.d_val.get(endian)
262 }
263}
264
265impl<Endian: endian::Endian> Dyn for elf::Dyn64<Endian> {
266 type Word = u64;
267 type Sword = i64;
268 type Endian = Endian;
269
270 #[inline]
271 fn d_tag(&self, endian: Self::Endian) -> Self::Sword {
272 self.d_tag.get(endian)
273 }
274
275 #[inline]
276 fn d_val(&self, endian: Self::Endian) -> Self::Word {
277 self.d_val.get(endian)
278 }
279}
280
281fn tag_is_string(tag: i64) -> bool {
282 match tag {
283 elf::DT_NEEDED
284 | elf::DT_SONAME
285 | elf::DT_RPATH
286 | elf::DT_RUNPATH
287 | elf::DT_AUXILIARY
288 | elf::DT_FILTER => true,
289 _ => false,
290 }
291}
292
293fn tag_is_address(tag: i64) -> bool {
294 match tag {
296 elf::DT_PLTGOT
297 | elf::DT_HASH
298 | elf::DT_STRTAB
299 | elf::DT_SYMTAB
300 | elf::DT_RELA
301 | elf::DT_INIT
302 | elf::DT_FINI
303 | elf::DT_REL
304 | elf::DT_DEBUG
305 | elf::DT_JMPREL
306 | elf::DT_FINI_ARRAY
307 | elf::DT_INIT_ARRAY
308 | elf::DT_PREINIT_ARRAY
309 | elf::DT_SYMTAB_SHNDX
310 | elf::DT_VERDEF
311 | elf::DT_VERNEED
312 | elf::DT_VERSYM
313 | elf::DT_ADDRRNGLO..=elf::DT_ADDRRNGHI => true,
314 _ => false,
315 }
316}