1use std::{fmt, iter, mem, slice};
26
27use crate::{util::CStr};
28use crate::{Error, Result};
29use crate::util::AlignTo;
30
31use super::{Align, Pe, image::*};
32
33#[derive(Copy, Clone)]
39pub struct Debug<'a, P> {
40 pe: P,
41 image: &'a [IMAGE_DEBUG_DIRECTORY],
42}
43impl<'a, P: Pe<'a>> Debug<'a, P> {
44 pub(crate) fn try_from(pe: P) -> Result<Debug<'a, P>> {
45 let datadir = pe.data_directory().get(IMAGE_DIRECTORY_ENTRY_DEBUG).ok_or(Error::Bounds)?;
46 let (len, rem) = (
47 datadir.Size as usize / mem::size_of::<IMAGE_DEBUG_DIRECTORY>(),
48 datadir.Size as usize % mem::size_of::<IMAGE_DEBUG_DIRECTORY>(),
49 );
50 if rem != 0 {
51 return Err(Error::Invalid);
52 }
53 let image = pe.derva_slice(datadir.VirtualAddress, len)?;
54 Ok(Debug { pe, image })
55 }
56 pub fn pe(&self) -> P {
58 self.pe
59 }
60 pub fn image(&self) -> &'a [IMAGE_DEBUG_DIRECTORY] {
62 self.image
63 }
64 pub fn pdb_file_name(&self) -> Option<&'a CStr> {
66 self.into_iter()
67 .filter_map(|dir| dir.entry().ok().and_then(Entry::as_code_view).map(|cv| cv.pdb_file_name()))
68 .next()
69 }
70 pub fn iter(&self) -> Iter<'a, P> {
72 Iter {
73 pe: self.pe,
74 iter: self.image.iter()
75 }
76 }
77}
78impl<'a, P: Pe<'a>> IntoIterator for Debug<'a, P> {
79 type Item = Dir<'a, P>;
80 type IntoIter = Iter<'a, P>;
81 fn into_iter(self) -> Iter<'a, P> {
82 self.iter()
83 }
84}
85impl<'a, P: Pe<'a>> fmt::Debug for Debug<'a, P> {
86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 f.debug_list().entries(*self).finish()
88 }
89}
90
91#[derive(Clone)]
95pub struct Iter<'a, P> {
96 pe: P,
97 iter: slice::Iter<'a, IMAGE_DEBUG_DIRECTORY>,
98}
99impl<'a, P: Pe<'a>> Iter<'a, P> {
100 pub fn image(&self) -> &'a [IMAGE_DEBUG_DIRECTORY] {
101 self.iter.as_slice()
102 }
103}
104impl<'a, P: Pe<'a>> Iterator for Iter<'a, P> {
105 type Item = Dir<'a, P>;
106 fn next(&mut self) -> Option<Dir<'a, P>> {
107 self.iter.next().map(|image| Dir { pe: self.pe, image })
108 }
109 fn size_hint(&self) -> (usize, Option<usize>) {
110 self.iter.size_hint()
111 }
112 fn count(self) -> usize {
113 self.iter.count()
114 }
115 fn nth(&mut self, n: usize) -> Option<Dir<'a, P>> {
116 self.iter.nth(n).map(|image| Dir { pe: self.pe, image })
117 }
118}
119impl<'a, P: Pe<'a>> DoubleEndedIterator for Iter<'a, P> {
120 fn next_back(&mut self) -> Option<Dir<'a, P>> {
121 self.iter.next_back().map(|image| Dir { pe: self.pe, image })
122 }
123}
124impl<'a, P: Pe<'a>> ExactSizeIterator for Iter<'a, P> {}
125impl<'a, P: Pe<'a>> iter::FusedIterator for Iter<'a, P> {}
126
127#[derive(Copy, Clone)]
131pub struct Dir<'a, P> {
132 pe: P,
133 image: &'a IMAGE_DEBUG_DIRECTORY,
134}
135impl<'a, P: Pe<'a>> Dir<'a, P> {
136 pub fn pe(&self) -> P {
138 self.pe
139 }
140 pub fn image(&self) -> &'a IMAGE_DEBUG_DIRECTORY {
142 self.image
143 }
144 pub fn data(&self) -> Option<&'a [u8]> {
146 let image = self.pe.image();
147 let size = self.image.SizeOfData as usize;
148 let offset = match self.pe.align() {
149 Align::File => self.image.PointerToRawData,
150 Align::Section => self.image.AddressOfRawData,
151 } as usize;
152 image.get(offset..offset.wrapping_add(size))
153 }
154 pub fn entry(&self) -> Result<Entry<'a>> {
156 match self.image.Type {
157 IMAGE_DEBUG_TYPE_CODEVIEW => Ok(Entry::CodeView(code_view(&self)?)),
158 IMAGE_DEBUG_TYPE_MISC => Ok(Entry::Dbg(dbg(&self)?)),
159 IMAGE_DEBUG_TYPE_POGO => Ok(Entry::Pgo(pgo(&self)?)),
160 _ => Ok(Entry::Unknown(self.data()))
161 }
162 }
163}
164impl<'a, P: Pe<'a>> fmt::Debug for Dir<'a, P> {
165 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166 f.debug_struct("Dir")
167 .field("type", &crate::stringify::DebugType(self.image.Type).to_str().ok_or(self.image.Type))
168 .field("time_date_stamp", &self.image.TimeDateStamp)
169 .field("version", &self.image.Version)
170 .field("entry", &self.entry())
171 .finish()
172 }
173}
174
175pub use crate::wrap::debug::{Entry, CodeView, Dbg, Pgo, PgoIter, PgoItem};
178
179fn code_view<'a, P: Pe<'a>>(dir: &Dir<'a, P>) -> Result<CodeView<'a>> {
180 let bytes = dir.data().ok_or(Error::Bounds)?;
181 if bytes.len() < 16 {
182 return Err(Error::Bounds);
183 }
184 if !(cfg!(feature = "unsafe_alignment") || bytes.as_ptr().aligned_to(4)) {
185 return Err(Error::Misaligned);
186 }
187 let cv_signature = unsafe { &*(bytes.as_ptr() as *const [u8; 4]) };
188 match cv_signature {
189 b"NB10" => {
190 if bytes.len() < 16 {
191 return Err(Error::Bounds);
192 }
193 let image = unsafe { &*(bytes.as_ptr() as *const IMAGE_DEBUG_CV_INFO_PDB20) };
194 let pdb_file_name = CStr::from_bytes(&bytes[16..]).ok_or(Error::Encoding)?;
195 Ok(CodeView::Cv20 { image, pdb_file_name })
196 },
197 b"RSDS" => {
198 if bytes.len() < 24 {
199 return Err(Error::Bounds);
200 }
201 let image = unsafe { &*(bytes.as_ptr() as *const IMAGE_DEBUG_CV_INFO_PDB70) };
202 let pdb_file_name = CStr::from_bytes(&bytes[24..]).ok_or(Error::Encoding)?;
203 Ok(CodeView::Cv70 { image, pdb_file_name })
204 },
205 _ => Err(Error::BadMagic),
206 }
207}
208
209fn dbg<'a, P: Pe<'a>>(dir: &Dir<'a, P>) -> Result<Dbg<'a>> {
210 let data = dir.data().ok_or(Error::Bounds)?;
211 if data.len() < mem::size_of::<IMAGE_DEBUG_MISC>() {
212 return Err(Error::Bounds);
213 }
214 if !(cfg!(feature = "unsafe_alignment") || data.as_ptr().aligned_to(4)) {
215 return Err(Error::Misaligned);
216 }
217 let image = unsafe { &*(data.as_ptr() as *const IMAGE_DEBUG_MISC) };
218 Ok(Dbg { image })
219}
220
221fn pgo<'a, P: Pe<'a>>(dir: &Dir<'a, P>) -> Result<Pgo<'a>> {
222 let data = dir.data().ok_or(Error::Bounds)?;
223 if data.len() < 4 {
224 return Err(Error::Bounds);
225 }
226 if !(cfg!(feature = "unsafe_alignment") || data.as_ptr().aligned_to(4)) {
227 return Err(Error::Misaligned);
228 }
229 let len = data.len() / 4;
230 let image = unsafe { slice::from_raw_parts(data.as_ptr() as *const u32, len) };
231 Ok(Pgo { image })
232}
233
234#[cfg(feature = "serde")]
252mod serde {
253 use crate::util::serde_helper::*;
254 use super::{Pe, Debug, Dir};
255
256 impl<'a, P: Pe<'a>> Serialize for Debug<'a, P> {
257 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
258 serializer.collect_seq(self.into_iter())
259 }
260 }
261 impl<'a, P: Pe<'a>> Serialize for Dir<'a, P> {
262 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
263 let is_human_readable = serializer.is_human_readable();
264 let mut state = serializer.serialize_struct("Dir", 4)?;
265 if is_human_readable {
266 state.serialize_field("type", &crate::stringify::DebugType(self.image.Type).to_str())?;
267 }
268 else {
269 state.serialize_field("type", &self.image.Type)?;
270 }
271 state.serialize_field("time_date_stamp", &self.image.TimeDateStamp)?;
272 state.serialize_field("version", &self.image.Version)?;
273 state.serialize_field("entry", &self.entry().ok())?;
274 state.end()
275 }
276 }
277}
278
279#[cfg(test)]
282pub(crate) fn test<'a, P: Pe<'a>>(pe: P) -> Result<()> {
283 let debug = pe.debug()?;
284 for dir in debug {
285 let _data = dir.data();
286 match dir.entry() {
287 Ok(Entry::CodeView(cv)) => {
288 let _format = cv.format();
289 let _pdb_file_name = cv.pdb_file_name();
290 },
291 Ok(Entry::Dbg(_dbg)) => (),
292 Ok(Entry::Pgo(pgo)) => {
293 for _sec in pgo {}
294 },
295 Ok(Entry::Unknown(_data)) => (),
296 Err(_) => (),
297 }
298 }
299 Ok(())
300}