schnauzer/types/
section.rs1use super::primitives::*;
2
3use super::auto_enum_fields::*;
4use super::reloc::*;
5use super::RcReader;
6use super::Result;
7use schnauzer_derive::AutoEnumFields;
8use scroll::ctx::SizeWith;
9use scroll::Endian;
10use scroll::IOread;
11use std::fmt::Debug;
12use std::io::Read;
13use std::io::Seek;
14use std::io::SeekFrom;
15use std::io::Write;
16
17#[derive(Debug, AutoEnumFields)]
19pub struct Section {
20 object_file_offset: u64,
21
22 pub sectname: Str16Bytes,
23 pub segname: Str16Bytes,
24 pub addr: Hu64,
25 pub size: Hu64,
26 pub offset: u32,
27 pub align: u32,
28 pub reloff: u32,
29 pub nreloc: u32,
30 pub flags: Hu32,
31 pub reserved1: u32,
32 pub reserved2: u32,
33 pub reserved3: u32opt,
35
36 reader: RcReader,
37 pub endian: Endian,
38}
39
40impl Section {
41 pub(super) fn parse(
42 reader: RcReader,
43 ctx: X64Context,
44 object_file_offset: u64,
45 ) -> Result<Self> {
46 let endian = ctx.endian().clone();
47 let mut reader_mut = reader.borrow_mut();
48
49 let sectname: Str16Bytes = reader_mut.ioread_with(endian)?;
50 let segname: Str16Bytes = reader_mut.ioread_with(endian)?;
51 let addr: Hu64 = reader_mut.ioread_with(ctx)?;
52 let size: Hu64 = reader_mut.ioread_with(ctx)?;
53 let offset: u32 = reader_mut.ioread_with(endian)?;
54 let align: u32 = reader_mut.ioread_with(endian)?;
55 let reloff: u32 = reader_mut.ioread_with(endian)?;
56 let nreloc: u32 = reader_mut.ioread_with(endian)?;
57 let flags: Hu32 = reader_mut.ioread_with(endian)?;
58 let reserved1: u32 = reader_mut.ioread_with(endian)?;
59 let reserved2: u32 = reader_mut.ioread_with(endian)?;
60 let reserved3: u32opt = reader_mut.ioread_with(ctx)?;
61
62 std::mem::drop(reader_mut);
63 let reader = reader.clone();
64
65 Ok(Self {
66 object_file_offset,
67 sectname,
68 segname,
69 addr,
70 size,
71 offset,
72 align,
73 reloff,
74 nreloc,
75 flags,
76 reserved1,
77 reserved2,
78 reserved3,
79 reader,
80 endian,
81 })
82 }
83}
84
85impl Section {
86 pub fn read_data_to(&self, out: &mut dyn Write) -> Result<()> {
87 use std::cmp::min;
88 const BUFFER_SIZE: usize = 4096;
89
90 let mut reader = self.reader.borrow_mut();
91 reader.seek(SeekFrom::Start(self.object_file_offset + self.offset as u64))?;
92
93 let mut remainig = self.size.0 as usize;
94
95 let mut tmp = [0u8; BUFFER_SIZE];
96
97 while remainig > 0 {
98 let to_read = min(remainig, BUFFER_SIZE);
99
100 match reader.read_exact(&mut tmp[..to_read]) {
101 Ok(_) => match out.write_all(&mut tmp[..to_read]) {
102 Ok(_) => (),
103 Err(e) => {return Err(crate::result::Error::Other(Box::new(e)));},
104 },
105 Err(e) => {return Err(crate::result::Error::Other(Box::new(e)));},
106 }
107
108 remainig -= to_read;
109 }
110
111 Ok(())
112 }
113}
114
115impl SizeWith<X64Context> for Section {
116 fn size_with(ctx: &X64Context) -> usize {
117 let endian = ctx.endian();
118
119 Str16Bytes::size_with(endian) + Str16Bytes::size_with(endian) + Hu64::size_with(ctx) + Hu64::size_with(ctx) + std::mem::size_of::<u32>() + std::mem::size_of::<u32>() + std::mem::size_of::<u32>() + std::mem::size_of::<u32>() + Hu32::size_with(endian) + std::mem::size_of::<u32>() + std::mem::size_of::<u32>() + u32opt::size_with(ctx) }
132}
133
134impl Section {
135 pub fn relocations_iterator(&self) -> RelocationIterator {
136 RelocationIterator::new(
137 self.reader.clone(),
138 self.nreloc,
139 self.object_file_offset + self.reloff as u64,
140 self.endian,
141 )
142 }
143}
144
145pub struct RelocationIterator {
146 reader: RcReader,
147
148 count: u32,
149 base_offset: u64,
150 endian: Endian,
151
152 current: u32,
153}
154
155impl RelocationIterator {
156 fn new(reader: RcReader, count: u32, base_offset: u64, endian: Endian) -> Self {
157 RelocationIterator {
158 reader: reader,
159 count: count,
160 base_offset: base_offset,
161 endian: endian,
162 current: 0,
163 }
164 }
165}
166
167impl Iterator for RelocationIterator {
168 type Item = RelocationInfo;
169
170 fn next(&mut self) -> Option<Self::Item> {
171 if self.current >= self.count {
172 return None;
173 }
174
175 let offset =
176 self.base_offset + RelocationInfo::size_with(&self.endian) as u64 * self.current as u64;
177 self.current += 1;
178
179 let mut reader_mut = self.reader.borrow_mut();
180 if let Err(_) = reader_mut.seek(SeekFrom::Start(offset as u64)) {
181 return None;
182 }
183
184 match reader_mut.ioread_with::<RelocationInfo>(self.endian) {
185 Ok(info) => Some(info),
186 Err(_) => None,
187 }
188 }
189}