| 1 | use core::slice; | 
| 2 |  | 
| 3 | use crate::endian::{LittleEndian as LE, U16}; | 
| 4 | use crate::pe; | 
| 5 | use crate::read::{Bytes, Error, ReadError, Result}; | 
| 6 |  | 
| 7 | /// An iterator over the relocation blocks in the `.reloc` section of a PE file. | 
| 8 | /// | 
| 9 | /// Returned by [`DataDirectories::relocation_blocks`](super::DataDirectories::relocation_blocks). | 
| 10 | #[derive (Debug, Default, Clone, Copy)] | 
| 11 | pub struct RelocationBlockIterator<'data> { | 
| 12 |     data: Bytes<'data>, | 
| 13 | } | 
| 14 |  | 
| 15 | impl<'data> RelocationBlockIterator<'data> { | 
| 16 |     /// Construct a new iterator from the data of the `.reloc` section. | 
| 17 |     pub fn new(data: &'data [u8]) -> Self { | 
| 18 |         RelocationBlockIterator { data: Bytes(data) } | 
| 19 |     } | 
| 20 |  | 
| 21 |     /// Read the next relocation page. | 
| 22 |     pub fn next(&mut self) -> Result<Option<RelocationIterator<'data>>> { | 
| 23 |         if self.data.is_empty() { | 
| 24 |             return Ok(None); | 
| 25 |         } | 
| 26 |         let header = self | 
| 27 |             .data | 
| 28 |             .read::<pe::ImageBaseRelocation>() | 
| 29 |             .read_error("Invalid PE reloc section size" )?; | 
| 30 |         let virtual_address = header.virtual_address.get(LE); | 
| 31 |         let size = header.size_of_block.get(LE); | 
| 32 |         if size <= 8 || size & 3 != 0 { | 
| 33 |             return Err(Error("Invalid PE reloc block size" )); | 
| 34 |         } | 
| 35 |         let count = (size - 8) / 2; | 
| 36 |         let relocs = self | 
| 37 |             .data | 
| 38 |             .read_slice::<U16<LE>>(count as usize) | 
| 39 |             .read_error("Invalid PE reloc block size" )? | 
| 40 |             .iter(); | 
| 41 |         Ok(Some(RelocationIterator { | 
| 42 |             virtual_address, | 
| 43 |             size, | 
| 44 |             relocs, | 
| 45 |         })) | 
| 46 |     } | 
| 47 | } | 
| 48 |  | 
| 49 | /// An iterator of the relocations in a block in the `.reloc` section of a PE file. | 
| 50 | #[derive (Debug, Clone)] | 
| 51 | pub struct RelocationIterator<'data> { | 
| 52 |     virtual_address: u32, | 
| 53 |     size: u32, | 
| 54 |     relocs: slice::Iter<'data, U16<LE>>, | 
| 55 | } | 
| 56 |  | 
| 57 | impl<'data> RelocationIterator<'data> { | 
| 58 |     /// Return the virtual address of the page that this block of relocations applies to. | 
| 59 |     pub fn virtual_address(&self) -> u32 { | 
| 60 |         self.virtual_address | 
| 61 |     } | 
| 62 |  | 
| 63 |     /// Return the size in bytes of this block of relocations. | 
| 64 |     pub fn size(&self) -> u32 { | 
| 65 |         self.size | 
| 66 |     } | 
| 67 | } | 
| 68 |  | 
| 69 | impl<'data> Iterator for RelocationIterator<'data> { | 
| 70 |     type Item = Relocation; | 
| 71 |  | 
| 72 |     fn next(&mut self) -> Option<Relocation> { | 
| 73 |         loop { | 
| 74 |             let reloc: u16 = self.relocs.next()?.get(LE); | 
| 75 |             if reloc != 0 { | 
| 76 |                 return Some(Relocation { | 
| 77 |                     virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32), | 
| 78 |                     typ: reloc >> 12, | 
| 79 |                 }); | 
| 80 |             } | 
| 81 |         } | 
| 82 |     } | 
| 83 | } | 
| 84 |  | 
| 85 | /// A relocation in the `.reloc` section of a PE file. | 
| 86 | #[derive (Debug, Default, Clone, Copy)] | 
| 87 | pub struct Relocation { | 
| 88 |     /// The virtual address of the relocation. | 
| 89 |     pub virtual_address: u32, | 
| 90 |     /// One of the `pe::IMAGE_REL_BASED_*` constants. | 
| 91 |     pub typ: u16, | 
| 92 | } | 
| 93 |  |