| 1 | use crate::read::{self, Error, ReadError as _}; |
| 2 | use crate::{endian, CompressedFileRange, CompressionFormat, ReadRef, U32Bytes}; |
| 3 | |
| 4 | // Attempt to parse the the CompressedFileRange for a section using the GNU-style |
| 5 | // inline compression header format. This is used by the Go compiler in Mach-O files |
| 6 | // as well as by the GNU linker in some ELF files. |
| 7 | pub(super) fn compressed_file_range<'data, R: ReadRef<'data>>( |
| 8 | file_data: R, |
| 9 | section_offset: u64, |
| 10 | section_size: u64, |
| 11 | ) -> read::Result<CompressedFileRange> { |
| 12 | let mut offset = section_offset; |
| 13 | // Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally |
| 14 | // huge allocations. This also reduces the chance of accidentally matching on a |
| 15 | // .debug_str that happens to start with "ZLIB". |
| 16 | let header = file_data |
| 17 | .read_bytes(&mut offset, 8) |
| 18 | .read_error("GNU compressed section is too short" )?; |
| 19 | if header != b"ZLIB \0\0\0\0" { |
| 20 | return Err(Error("Invalid GNU compressed section header" )); |
| 21 | } |
| 22 | let uncompressed_size = file_data |
| 23 | .read::<U32Bytes<_>>(&mut offset) |
| 24 | .read_error("GNU compressed section is too short" )? |
| 25 | .get(endian::BigEndian) |
| 26 | .into(); |
| 27 | let compressed_size = section_size |
| 28 | .checked_sub(offset - section_offset) |
| 29 | .read_error("GNU compressed section is too short" )?; |
| 30 | Ok(CompressedFileRange { |
| 31 | format: CompressionFormat::Zlib, |
| 32 | offset, |
| 33 | compressed_size, |
| 34 | uncompressed_size, |
| 35 | }) |
| 36 | } |
| 37 | |