schnauzer/types/
section.rs

1use 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/// Both `section` and `section_64`
18#[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    /// Only for `section_64`
34    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) // sectname
120            + Str16Bytes::size_with(endian) // segname
121            + Hu64::size_with(ctx) // addr
122            + Hu64::size_with(ctx) // size
123            + std::mem::size_of::<u32>() // offset
124            + std::mem::size_of::<u32>() // align
125            + std::mem::size_of::<u32>() // reloff
126            + std::mem::size_of::<u32>() // nreloc
127            + Hu32::size_with(endian) // flags
128            + std::mem::size_of::<u32>() // reserved1
129            + std::mem::size_of::<u32>() // reserved2
130            + u32opt::size_with(ctx) // reserved3
131    }
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}