-
Notifications
You must be signed in to change notification settings - Fork 156
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
read/macho: support Go's debug section compression (#697)
When using compression, debug sections in Mach-O produced by the go compiler have a __zdebug_ section name prefix, and the section data has the same format as GNU .zdebug_ compression for ELF. Support these section names in `Object::section_by_name`, and support the compressed section data in `ObjectSection::compressed_data`. This commit extracts the GNU-style section compression logic from the read::elf::section to a module underneath read, and then uses it also in read::macho.
- Loading branch information
Showing
9 changed files
with
160 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use crate::read::{self, Error, ReadError as _}; | ||
use crate::{endian, CompressedFileRange, CompressionFormat, ReadRef, U32Bytes}; | ||
|
||
// Attempt to parse the the CompressedFileRange for a section using the GNU-style | ||
// inline compression header format. This is used by the Go compiler in Mach-O files | ||
// as well as by the GNU linker in some ELF files. | ||
pub(super) fn compressed_file_range<'data, R: ReadRef<'data>>( | ||
file_data: R, | ||
section_offset: u64, | ||
section_size: u64, | ||
) -> read::Result<CompressedFileRange> { | ||
let mut offset = section_offset; | ||
// Assume ZLIB-style uncompressed data is no more than 4GB to avoid accidentally | ||
// huge allocations. This also reduces the chance of accidentally matching on a | ||
// .debug_str that happens to start with "ZLIB". | ||
let header = file_data | ||
.read_bytes(&mut offset, 8) | ||
.read_error("GNU compressed section is too short")?; | ||
if header != b"ZLIB\0\0\0\0" { | ||
return Err(Error("Invalid GNU compressed section header")); | ||
} | ||
let uncompressed_size = file_data | ||
.read::<U32Bytes<_>>(&mut offset) | ||
.read_error("GNU compressed section is too short")? | ||
.get(endian::BigEndian) | ||
.into(); | ||
let compressed_size = section_size | ||
.checked_sub(offset - section_offset) | ||
.read_error("GNU compressed section is too short")?; | ||
Ok(CompressedFileRange { | ||
format: CompressionFormat::Zlib, | ||
offset, | ||
compressed_size, | ||
uncompressed_size, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule testfiles
updated
4 files
+ − | macho/go-aarch64 | |
+ − | macho/go-x86_64 | |
+13 −0 | macho/go.go | |
+4 −0 | macho/go.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#[cfg(feature = "std")] | ||
use object::{Object, ObjectSection as _}; | ||
|
||
// Test that we can read compressed sections in Mach-O files as produced | ||
// by the Go compiler. | ||
#[cfg(feature = "std")] | ||
#[test] | ||
fn test_go_macho() { | ||
let macho_testfiles = std::path::Path::new("testfiles/macho"); | ||
|
||
// Section names we expect to find, whether they should be | ||
// compressed, and the actual name of the section in the file. | ||
const EXPECTED: &[(&str, bool, &str)] = &[ | ||
(".debug_abbrev", true, "__zdebug_abbrev"), | ||
(".debug_gdb_scripts", false, "__debug_gdb_scri"), | ||
(".debug_ranges", true, "__zdebug_ranges"), | ||
("__data", false, "__data"), | ||
]; | ||
|
||
for file in &["go-aarch64", "go-x86_64"] { | ||
let path = macho_testfiles.join(file); | ||
let file = std::fs::File::open(path).unwrap(); | ||
let reader = object::read::ReadCache::new(file); | ||
let object = object::read::File::parse(&reader).unwrap(); | ||
for &(name, compressed, actual_name) in EXPECTED { | ||
let section = object.section_by_name(name).unwrap(); | ||
assert_eq!(section.name(), Ok(actual_name)); | ||
let compressed_file_range = section.compressed_file_range().unwrap(); | ||
let size = section.size(); | ||
if compressed { | ||
assert_eq!( | ||
compressed_file_range.format, | ||
object::CompressionFormat::Zlib | ||
); | ||
assert_eq!(compressed_file_range.compressed_size, size - 12); | ||
assert!( | ||
compressed_file_range.uncompressed_size > compressed_file_range.compressed_size, | ||
"decompressed size is greater than compressed size" | ||
); | ||
} else { | ||
assert_eq!( | ||
compressed_file_range.format, | ||
object::CompressionFormat::None | ||
); | ||
assert_eq!(compressed_file_range.compressed_size, size); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
|
||
mod coff; | ||
mod elf; | ||
mod macho; |