1use std::{fmt, iter, mem, slice};
6use std::cmp::Ordering;
7
8use crate::{Error, Result};
9
10use super::image::*;
11use super::Pe;
12
13#[derive(Copy, Clone)]
19pub struct Exception<'a, P> {
20 pe: P,
21 image: &'a [RUNTIME_FUNCTION],
22}
23impl<'a, P: Pe<'a>> Exception<'a, P> {
24 pub(crate) fn try_from(pe: P) -> Result<Exception<'a, P>> {
25 let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_EXCEPTION).ok_or(Error::Bounds)?;
26 let (len, rem) = (
27 datadir.Size as usize / mem::size_of::<RUNTIME_FUNCTION>(),
28 datadir.Size as usize % mem::size_of::<RUNTIME_FUNCTION>(),
29 );
30 if rem != 0 {
31 return Err(Error::Invalid);
32 }
33 let image = pe.derva_slice(datadir.VirtualAddress, len)?;
34 Ok(Exception { pe, image })
35 }
36 pub fn pe(&self) -> P {
38 self.pe
39 }
40 pub fn image(&self) -> &'a [RUNTIME_FUNCTION] {
42 self.image
43 }
44 pub fn check_sorted(&self) -> bool {
49 self.image.windows(2).all(|window|
50 window[0].BeginAddress <= window[0].EndAddress &&
51 window[0].EndAddress <= window[1].BeginAddress &&
52 window[1].BeginAddress <= window[1].EndAddress
53 )
54 }
55 pub fn functions(&self)
57 -> iter::Map<slice::Iter<'a, RUNTIME_FUNCTION>, impl Clone + FnMut(&'a RUNTIME_FUNCTION) -> Function<'a, P>>
58 {
59 let pe = self.pe;
60 self.image.iter()
61 .map(move |image| Function { pe, image })
62 }
63 pub fn index_of(&self, pc: Rva) -> std::result::Result<usize, usize> {
65 self.image.binary_search_by(|rf| {
66 if pc < rf.BeginAddress {
67 Ordering::Less
68 }
69 else if pc > rf.EndAddress {
70 Ordering::Greater
71 }
72 else {
73 Ordering::Equal
74 }
75 })
76 }
77 pub fn lookup_function_entry(&self, pc: Rva) -> Option<Function<'a, P>> {
81 self.index_of(pc).map(|index| Function {
82 pe: self.pe,
83 image: &self.image[index]
84 }).ok()
85 }
86}
87impl<'a, P: Pe<'a>> fmt::Debug for Exception<'a, P> {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89 f.debug_struct("Exception")
90 .field("functions.len", &self.image.len())
91 .finish()
92 }
93}
94
95#[derive(Copy, Clone)]
99pub struct Function<'a, P> {
100 pe: P,
101 image: &'a RUNTIME_FUNCTION,
102}
103impl<'a, P: Pe<'a>> Function<'a, P> {
104 pub fn pe(&self) -> P {
106 self.pe
107 }
108 pub fn image(&self) -> &'a RUNTIME_FUNCTION {
110 self.image
111 }
112 pub fn bytes(&self) -> Result<&'a [u8]> {
114 let len = if self.image.BeginAddress > self.image.EndAddress { return Err(Error::Overflow); }
115 else { (self.image.EndAddress - self.image.BeginAddress) as usize };
116 self.pe.derva_slice(self.image.BeginAddress, len)
117 }
118 pub fn unwind_info(&self) -> Result<UnwindInfo<'a, P>> {
120 let bytes = self.pe.slice(
122 self.image.UnwindData,
123 mem::size_of::<UNWIND_INFO>(),
124 if cfg!(feature = "unsafe_alignment") { 1 } else { mem::align_of::<UNWIND_INFO>() }
125 )?;
126 let image = unsafe { &*(bytes.as_ptr() as *const UNWIND_INFO) };
127 let min_size_of = mem::size_of::<UNWIND_INFO>() +
129 mem::size_of::<UNWIND_CODE>() * image.CountOfCodes as usize;
130 if bytes.len() < min_size_of {
131 return Err(Error::Bounds);
132 }
133 Ok(UnwindInfo { pe: self.pe, image })
135 }
136}
137impl<'a, P: Pe<'a>> fmt::Debug for Function<'a, P> {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 f.debug_struct("Function")
140 .field("bytes.len", &self.bytes().map(<[_]>::len))
141 .finish()
142 }
143}
144
145#[derive(Copy, Clone)]
149pub struct UnwindInfo<'a, P> {
150 pe: P,
151 image: &'a UNWIND_INFO,
152}
153impl<'a, P: Pe<'a>> UnwindInfo<'a, P> {
154 pub fn pe(&self) -> P {
156 self.pe
157 }
158 pub fn image(&self) -> &'a UNWIND_INFO {
160 self.image
161 }
162 pub fn version(&self) -> u8 {
163 self.image.VersionFlags & 0b00000111
164 }
165 pub fn flags(&self) -> u8 {
166 self.image.VersionFlags >> 3
167 }
168 pub fn size_of_prolog(&self) -> usize {
169 self.image.SizeOfProlog as usize
170 }
171 pub fn frame_register(&self) -> u8 {
172 self.image.FrameRegisterOffset & 0b00001111
173 }
174 pub fn frame_offset(&self) -> u8 {
175 self.image.FrameRegisterOffset >> 4
176 }
177 pub fn unwind_codes(&self) -> &'a [UNWIND_CODE] {
178 let len = self.image.CountOfCodes as usize;
179 unsafe {
180 slice::from_raw_parts(self.image.UnwindCode.as_ptr(), len)
181 }
182 }
183}
184impl<'a, P: Pe<'a>> fmt::Debug for UnwindInfo<'a, P> {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 f.debug_struct("UnwindInfo")
187 .field("version", &self.version())
188 .field("flags", &self.flags())
189 .field("size_of_prolog", &self.size_of_prolog())
190 .field("frame_register", &self.frame_register())
191 .field("frame_offset", &self.frame_offset())
192 .field("unwind_codes.len", &self.unwind_codes().len())
193 .finish()
194 }
195}
196
197#[cfg(test)]
200pub(crate) fn test<'a, P: Pe<'a>>(pe: P) -> Result<()> {
201 let exception = pe.exception()?;
202 let _ = format!("{:?}", exception);
203
204 let sorted = exception.check_sorted();
205
206 for (index, function) in exception.functions().enumerate() {
207 let _ = format!("{:?}", function);
208 let _bytes = function.bytes();
209
210 if sorted {
211 for pc in function.image().BeginAddress..function.image().EndAddress {
212 assert_eq!(exception.index_of(pc), Ok(index));
213 }
214 }
215
216 if let Ok(unwind_info) = function.unwind_info() {
217 let _ = format!("{:?}", unwind_info);
218 let _version = unwind_info.version();
219 let _flags = unwind_info.flags();
220 let _size_of_prolog = unwind_info.size_of_prolog();
221 let _frame_register = unwind_info.frame_register();
222 let _frame_offset = unwind_info.frame_offset();
223 let _unwind_codes = unwind_info.unwind_codes();
224 }
225 }
226
227 Ok(())
228}