1use crate::unix::error::ElfError;
2use crate::unix::symbol::Symbol;
3use elf::endian::AnyEndian;
4use elf::relocation::{RelIterator, RelaIterator};
5use elf::{abi, ElfBytes};
6use std::collections::HashMap;
7use elf::section::SectionHeader;
8
9
10 fn find_plt_rel_data<'a>(
11 file: &'a ElfBytes<AnyEndian>,
12 ) -> Result<Option<(&'a [u8], bool)>, ElfError> {
13 let (dynamic_table, segment_table) = match (file.dynamic()?, file.segments()) {
14 (Some(dynamic_table), Some(segment_table)) => (dynamic_table, segment_table),
15 _ => return Ok(None),
16 };
17
18 let jmp_rel = match dynamic_table.iter().find(|t| t.d_tag == abi::DT_JMPREL) {
19 Some(jmp_rel) => jmp_rel,
20 None => return Ok(None),
21 };
22
23 let plt_rel = match dynamic_table.iter().find(|t| t.d_tag == abi::DT_PLTREL) {
24 Some(plt_rel) => plt_rel,
25 None => return Ok(None),
26 };
27
28 let plt_rel_sz = match dynamic_table.iter().find(|t| t.d_tag == abi::DT_PLTRELSZ) {
29 Some(plt_rel_sz) => plt_rel_sz,
30 None => return Ok(None),
31 };
32
33 let jmp_rel_addr = jmp_rel.d_val();
34
35 let jmp_rel_header = segment_table
36 .iter()
37 .filter(|s| s.p_type == abi::PT_LOAD)
38 .find(|s| jmp_rel_addr >= s.p_vaddr && (jmp_rel_addr - s.p_vaddr) < s.p_memsz);
39
40 let jmp_rel_header = match jmp_rel_header {
41 Some(jmp_rel_header) => jmp_rel_header,
42 None => return Ok(None),
43 };
44
45 let data = file.segment_data(&jmp_rel_header)?;
46 let data = &data[(jmp_rel_addr - jmp_rel_header.p_vaddr) as usize..];
47 let data = &data[..plt_rel_sz.d_val() as usize];
48
49 let is_rela = (plt_rel.d_val() as usize) == (abi::DT_RELA as usize);
50
51 Ok(Some((data, is_rela)))
52 }
53
54 pub fn parse_plt_from_elf(
55 file: &ElfBytes<AnyEndian>,
56 dynamic_symbols: &[Symbol],
57 ) -> Result<HashMap<String, u64>, ElfError> {
58 let mut result = HashMap::new();
59 let (rel_data, is_rela) = match find_plt_rel_data(file)? {
60 Some((rela_data, is_rela)) => (rela_data, is_rela),
61 None => return Ok(result),
62 };
63
64 let plt_section = match file.section_header_by_name(".plt")?
65 {
66 Some(plt_section) => plt_section,
67 None => return Ok(result),
68 };
69
70 match is_rela {
71 false => parse_rel_iterator(
72 &plt_section,
73 RelIterator::new(file.ehdr.endianness, file.ehdr.class, rel_data),
74 &dynamic_symbols,
75 &mut result,
76 ),
77 true => parse_rela_iterator(
78 &plt_section,
79 RelaIterator::new(file.ehdr.endianness, file.ehdr.class, rel_data),
80 &dynamic_symbols,
81 &mut result,
82 ),
83 }
84
85 Ok(result)
86 }
87
88 fn parse_rela_iterator(
89 plt_section: &SectionHeader,
90 iter: RelaIterator<AnyEndian>,
91 dynamic_symbols: &[Symbol],
92 buf: &mut HashMap<String, u64>,
93 ) {
94 parse_plt(plt_section, iter.map(|r| r.r_sym) , dynamic_symbols, buf)
95 }
96
97 fn parse_rel_iterator(
98 plt_section: &SectionHeader,
99 iter: RelIterator<AnyEndian>,
100 dynamic_symbols: &[Symbol],
101 buf: &mut HashMap<String, u64>,
102 ) {
103 parse_plt(plt_section, iter.map(|r| r.r_sym), dynamic_symbols, buf)
104 }
105
106 fn parse_plt(
107 plt_section: &SectionHeader,
108 iter: impl Iterator<Item = u32>,
109 dynamic_symbols: &[Symbol],
110 buf: &mut HashMap<String, u64>,
111 ) {
112 for (i, r_sym) in iter.enumerate() {
113 match dynamic_symbols.get(r_sym as usize) {
114 Some(sym) =>{
115 buf.insert(sym.name.to_string(), plt_section.sh_addr + (plt_section.sh_entsize * (i + 1) as u64))
116 },
117 _ => continue,
118 };
119 }
120 }
121