1use core::borrow::Borrow;
6use core::fmt;
7
8use elf::ElfBytes;
9use elf::endian::EndianParse;
10
11use crate::instruction::{Instruction, base, decode, info};
12
13use super::{Binary, error};
14
15#[derive(Copy, Clone)]
21pub struct Elf<'d, E, P, D = base::Set>
22where
23 E: Borrow<ElfBytes<'d, P>>,
24 P: EndianParse,
25{
26 elf: E,
27 last_segment: (u64, &'d [u8]),
28 base: D,
29 phantom: core::marker::PhantomData<P>,
30}
31
32impl<'d, E, P, D> Elf<'d, E, P, D>
33where
34 E: Borrow<ElfBytes<'d, P>>,
35 P: EndianParse,
36 D: decode::MakeDecode,
37{
38 pub fn new(elf: E) -> Result<Self, Error> {
40 use elf::abi;
41
42 let hdr = &elf.borrow().ehdr;
43 if hdr.e_machine != abi::EM_RISCV {
44 Err(Error::UnsupportedArchitecture)
45 } else if !hdr.endianness.is_little() {
46 Err(Error::UnsupportedEndianess)
47 } else {
48 let base = match hdr.class {
49 elf::file::Class::ELF32 => decode::MakeDecode::rv32i_full(),
50 elf::file::Class::ELF64 => decode::MakeDecode::rv64i_full(),
51 };
52
53 Ok(Self {
54 elf,
55 last_segment: (u64::MAX, &[]),
56 base,
57 phantom: Default::default(),
58 })
59 }
60 }
61
62 pub fn inner(&self) -> &ElfBytes<'d, P> {
64 self.elf.borrow()
65 }
66
67 pub fn base_set(&self) -> &D {
69 &self.base
70 }
71}
72
73impl<'d, E, P, D, I> Binary<I> for Elf<'d, E, P, D>
74where
75 E: Borrow<ElfBytes<'d, P>>,
76 P: EndianParse,
77 I: info::Info,
78 D: decode::Decode<I>,
79{
80 type Error = Error;
81
82 fn get_insn(&mut self, address: u64) -> Result<Instruction<I>, Self::Error> {
83 let segments = self
85 .elf
86 .borrow()
87 .segments()
88 .into_iter()
89 .flat_map(|s| s.iter())
90 .filter(|s| s.p_type == elf::abi::PT_LOAD && s.p_flags & elf::abi::PF_X != 0)
91 .map(|s| {
92 self.elf
93 .borrow()
94 .segment_data(&s)
95 .map(|d| (s.p_vaddr, d))
96 .map_err(Error::CouldNotRetrieveData)
97 });
98
99 let (insn_data, segment) = core::iter::once(Ok(self.last_segment))
104 .chain(segments)
105 .map(|s| {
106 let (base, data) = s?;
107 let Some(offset) = address.checked_sub(base) else {
108 return Ok(None);
110 };
111 let offset = offset.try_into().map_err(Error::ExceededHostUSize)?;
112 let res = data
113 .split_at_checked(offset)
114 .filter(|(_, insn_data)| !insn_data.is_empty())
115 .map(|(_, insn_data)| (insn_data, (base, data)));
116 Ok(res)
117 })
118 .find_map(Result::transpose)
119 .ok_or(Error::NoSegmentFound)??;
120
121 self.last_segment = segment;
122 Instruction::extract(insn_data, &self.base)
123 .map(|(i, _)| i)
124 .ok_or(Error::InvalidInstruction)
125 }
126}
127
128#[derive(Debug)]
130pub enum Error {
131 NoSegmentFound,
133 CouldNotRetrieveData(elf::parse::ParseError),
135 ExceededHostUSize(core::num::TryFromIntError),
137 InvalidInstruction,
139 UnsupportedArchitecture,
141 UnsupportedEndianess,
143}
144
145impl error::Miss for Error {
146 fn miss(_: u64) -> Self {
147 Self::NoSegmentFound
148 }
149}
150
151impl error::MaybeMiss for Error {
152 fn is_miss(&self) -> bool {
153 matches!(self, Self::NoSegmentFound)
154 }
155}
156
157impl core::error::Error for Error {
158 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
159 match self {
160 Self::CouldNotRetrieveData(e) => Some(e),
161 Self::ExceededHostUSize(e) => Some(e),
162 _ => None,
163 }
164 }
165}
166
167impl fmt::Display for Error {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 Self::NoSegmentFound => write!(f, "Could not find segment for address"),
171 Self::CouldNotRetrieveData(_) => write!(f, "Could not retrieve data for segment"),
172 Self::ExceededHostUSize(_) => write!(
173 f,
174 "An offset exceeds what can be represented with host native addresses"
175 ),
176 Self::InvalidInstruction => write!(f, "No valid instruction at address"),
177 Self::UnsupportedArchitecture => write!(f, "The target architecture is not supported"),
178 Self::UnsupportedEndianess => write!(f, "The target is not little endian"),
179 }
180 }
181}
182
183impl PartialEq for Error {
184 fn eq(&self, other: &Self) -> bool {
185 match (self, other) {
186 (Self::NoSegmentFound, Self::NoSegmentFound) => true,
187 (Self::CouldNotRetrieveData(_), Self::CouldNotRetrieveData(_)) => true,
188 (Self::ExceededHostUSize(l), Self::ExceededHostUSize(r)) => l == r,
189 (Self::InvalidInstruction, Self::InvalidInstruction) => true,
190 (Self::UnsupportedArchitecture, Self::UnsupportedArchitecture) => true,
191 (Self::UnsupportedEndianess, Self::UnsupportedEndianess) => true,
192 _ => false,
193 }
194 }
195}