1 macro_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.
20 pub const ELFCOMPRESS_ZLIB: u32 = 1;
21 /// Start of OS-specific.
22 pub const ELFCOMPRESS_LOOS: u32 = 0x6000_0000;
23 /// End of OS-specific.
24 pub const ELFCOMPRESS_HIOS: u32 = 0x6fff_ffff;
25 /// Start of processor-specific.
26 pub const ELFCOMPRESS_LOPROC: u32 = 0x7000_0000;
27 /// End of processor-specific.
28 pub const ELFCOMPRESS_HIPROC: u32 = 0x7fff_ffff;
29 
30 macro_rules! elf_compression_header_std_impl { ($size:ty) => {
31 
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 #[cfg(feature = "alloc")]
85 use scroll::{Pread, Pwrite, SizeWith};
86 
87 pub mod compression_header32 {
88     pub use crate::elf::compression_header::*;
89 
90     #[repr(C)]
91     #[derive(Copy, Clone, Eq, PartialEq, Default)]
92     #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
93     /// The compression header is used at the start of SHF_COMPRESSED sections
94     pub struct CompressionHeader {
95         /// Compression format
96         pub ch_type: u32,
97         /// Uncompressed data size
98         pub ch_size: u32,
99         /// Uncompressed data alignment
100         pub ch_addralign: u32,
101     }
102 
103     elf_compression_header!();
104 
105     pub const SIZEOF_CHDR: usize = 12;
106 
107     elf_compression_header_std_impl!(u32);
108 
109     if_alloc! {
110         impl From<ElfCompressionHeader> for CompressionHeader {
111             fn from(ch: ElfCompressionHeader) -> Self {
112                 CompressionHeader {
113                     ch_type: ch.ch_type,
114                     ch_size: ch.ch_size as u32,
115                     ch_addralign: ch.ch_addralign as u32,
116                 }
117             }
118         }
119     }
120 }
121 
122 
123 pub 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 
164 if_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
276