goblin/elf/
compression_header.rs

1macro_rules! elf_compression_header {
2    () => {
3        use plain;
4        // Declare that this is a plain type.
5        unsafe impl plain::Plain for CompressionHeader {}
6
7        impl ::core::fmt::Debug for CompressionHeader {
8            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
9                f.debug_struct("CompressionHeader")
10                    .field("ch_type", &self.ch_type)
11                    .field("ch_size", &format_args!("0x{:x}", self.ch_size))
12                    .field("ch_addralign", &format_args!("0x{:x}", self.ch_addralign))
13                    .finish()
14            }
15        }
16    };
17}
18
19/// ZLIB/DEFLATE algorithm.
20pub const ELFCOMPRESS_ZLIB: u32 = 1;
21/// Start of OS-specific.
22pub const ELFCOMPRESS_LOOS: u32 = 0x6000_0000;
23/// End of OS-specific.
24pub const ELFCOMPRESS_HIOS: u32 = 0x6fff_ffff;
25/// Start of processor-specific.
26pub const ELFCOMPRESS_LOPROC: u32 = 0x7000_0000;
27/// End of processor-specific.
28pub const ELFCOMPRESS_HIPROC: u32 = 0x7fff_ffff;
29
30macro_rules! elf_compression_header_std_impl {
31    ($size:ty) => {
32        #[cfg(test)]
33        mod tests {
34            use super::*;
35            #[test]
36            fn size_of() {
37                assert_eq!(::std::mem::size_of::<CompressionHeader>(), SIZEOF_CHDR);
38            }
39        }
40
41        if_alloc! {
42            use crate::elf::compression_header::CompressionHeader as ElfCompressionHeader;
43
44            use plain::Plain;
45
46            if_std! {
47                use crate::error::Result;
48
49                use std::fs::File;
50                use std::io::{Read, Seek};
51                use std::io::SeekFrom::Start;
52            }
53
54            impl From<CompressionHeader> for ElfCompressionHeader {
55                fn from(ch: CompressionHeader) -> Self {
56                    ElfCompressionHeader {
57                        ch_type: ch.ch_type,
58                        ch_size: u64::from(ch.ch_size),
59                        ch_addralign: u64::from(ch.ch_addralign),
60                    }
61                }
62            }
63
64            impl CompressionHeader {
65                pub fn from_bytes(bytes: &[u8]) -> CompressionHeader {
66                    let mut chdr = CompressionHeader::default();
67                    chdr.copy_from_bytes(bytes).expect("buffer is too short for header");
68                    chdr
69                }
70
71                #[cfg(feature = "std")]
72                pub fn from_fd(fd: &mut File, offset: u64) -> Result<CompressionHeader> {
73                    let mut chdr = CompressionHeader::default();
74                    fd.seek(Start(offset))?;
75                    unsafe {
76                        fd.read_exact(plain::as_mut_bytes(&mut chdr))?;
77                    }
78                    Ok(chdr)
79                }
80            }
81        } // end if_alloc
82    };
83}
84
85#[cfg(feature = "alloc")]
86use scroll::{Pread, Pwrite, SizeWith};
87
88pub mod compression_header32 {
89    pub use crate::elf::compression_header::*;
90
91    #[repr(C)]
92    #[derive(Copy, Clone, Eq, PartialEq, Default)]
93    #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
94    /// The compression header is used at the start of SHF_COMPRESSED sections
95    pub struct CompressionHeader {
96        /// Compression format
97        pub ch_type: u32,
98        /// Uncompressed data size
99        pub ch_size: u32,
100        /// Uncompressed data alignment
101        pub ch_addralign: u32,
102    }
103
104    elf_compression_header!();
105
106    pub const SIZEOF_CHDR: usize = 12;
107
108    elf_compression_header_std_impl!(u32);
109
110    if_alloc! {
111        impl From<ElfCompressionHeader> for CompressionHeader {
112            fn from(ch: ElfCompressionHeader) -> Self {
113                CompressionHeader {
114                    ch_type: ch.ch_type,
115                    ch_size: ch.ch_size as u32,
116                    ch_addralign: ch.ch_addralign as u32,
117                }
118            }
119        }
120    }
121}
122
123pub mod compression_header64 {
124    pub use crate::elf::compression_header::*;
125
126    #[repr(C)]
127    #[derive(Copy, Clone, Eq, PartialEq, Default)]
128    #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
129    /// The compression header is used at the start of SHF_COMPRESSED sections
130    pub struct CompressionHeader {
131        /// Compression format
132        pub ch_type: u32,
133        pub ch_reserved: u32,
134        /// Uncompressed data size
135        pub ch_size: u64,
136        /// Uncompressed data alignment
137        pub ch_addralign: u64,
138    }
139
140    elf_compression_header!();
141
142    pub const SIZEOF_CHDR: usize = 24;
143
144    elf_compression_header_std_impl!(u64);
145
146    if_alloc! {
147        impl From<ElfCompressionHeader> for CompressionHeader {
148            fn from(ch: ElfCompressionHeader) -> Self {
149                CompressionHeader {
150                    ch_type: ch.ch_type,
151                    ch_reserved: 0,
152                    ch_size: ch.ch_size as u64,
153                    ch_addralign: ch.ch_addralign as u64,
154                }
155            }
156        }
157    }
158}
159
160///////////////////////////////
161// Std/analysis/Unified Structs
162///////////////////////////////
163
164if_alloc! {
165    #[cfg(feature = "endian_fd")]
166    use crate::error;
167    use core::fmt;
168    use core::result;
169    use scroll::ctx;
170    use crate::container::{Container, Ctx};
171
172    #[derive(Default, PartialEq, Clone)]
173    /// A unified CompressionHeader - convertable to and from 32-bit and 64-bit variants
174    pub struct CompressionHeader {
175        /// Compression format
176        pub ch_type: u32,
177        /// Uncompressed data size
178        pub ch_size: u64,
179        /// Uncompressed data alignment
180        pub ch_addralign: u64,
181    }
182
183    impl CompressionHeader {
184        /// Return the size of the underlying compression header, given a `container`
185        #[inline]
186        pub fn size(ctx: Ctx) -> usize {
187            use scroll::ctx::SizeWith;
188            Self::size_with(&ctx)
189        }
190        pub fn new() -> Self {
191            CompressionHeader {
192                ch_type: 0,
193                ch_size: 0,
194                ch_addralign: 2 << 8,
195            }
196        }
197        /// Parse a compression header from `bytes` at `offset`, using the given `ctx`
198        #[cfg(feature = "endian_fd")]
199        pub fn parse(bytes: &[u8], mut offset: usize, ctx: Ctx) -> error::Result<CompressionHeader> {
200            use scroll::Pread;
201            bytes.gread_with(&mut offset, ctx)
202        }
203    }
204
205    impl fmt::Debug for CompressionHeader {
206        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207            f.debug_struct("CompressionHeader")
208                .field("ch_type", &self.ch_type)
209                .field("ch_size", &format_args!("0x{:x}", self.ch_size))
210                .field("ch_addralign", &format_args!("0x{:x}", self.ch_addralign))
211                .finish()
212        }
213    }
214
215    impl ctx::SizeWith<Ctx> for CompressionHeader {
216        fn size_with( &Ctx { container, .. }: &Ctx) -> usize {
217            match container {
218                Container::Little => {
219                    compression_header32::SIZEOF_CHDR
220                },
221                Container::Big => {
222                    compression_header64::SIZEOF_CHDR
223                },
224            }
225        }
226    }
227
228    impl<'a> ctx::TryFromCtx<'a, Ctx> for CompressionHeader {
229        type Error = crate::error::Error;
230        fn try_from_ctx(bytes: &'a [u8], Ctx {container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
231            use scroll::Pread;
232            let res = match container {
233                Container::Little => {
234                    (bytes.pread_with::<compression_header32::CompressionHeader>(0, le)?.into(), compression_header32::SIZEOF_CHDR)
235                },
236                Container::Big => {
237                    (bytes.pread_with::<compression_header64::CompressionHeader>(0, le)?.into(), compression_header64::SIZEOF_CHDR)
238                }
239            };
240            Ok(res)
241        }
242    }
243
244    impl ctx::TryIntoCtx<Ctx> for CompressionHeader {
245        type Error = crate::error::Error;
246        fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
247            use scroll::Pwrite;
248            match container {
249                Container::Little => {
250                    let chdr: compression_header32::CompressionHeader = self.into();
251                    Ok(bytes.pwrite_with(chdr, 0, le)?)
252                },
253                Container::Big => {
254                    let chdr: compression_header64::CompressionHeader = self.into();
255                    Ok(bytes.pwrite_with(chdr, 0, le)?)
256                }
257            }
258        }
259    }
260    impl ctx::IntoCtx<Ctx> for CompressionHeader {
261        fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
262            use scroll::Pwrite;
263            match container {
264                Container::Little => {
265                    let chdr: compression_header32::CompressionHeader = self.into();
266                    bytes.pwrite_with(chdr, 0, le).unwrap();
267                },
268                Container::Big => {
269                    let chdr: compression_header64::CompressionHeader = self.into();
270                    bytes.pwrite_with(chdr, 0, le).unwrap();
271                }
272            }
273        }
274    }
275} // end if_alloc