object/read/
gnu_compression.rs

1use crate::read::{self, Error, ReadError as _};
2use 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.
7pub(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}