Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add MachOFile::parse_at_offset #304

Merged
merged 1 commit into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/readobj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3222,14 +3222,14 @@ mod macho {
}

pub(super) fn print_macho32(p: &mut Printer<impl Write>, data: &[u8]) {
if let Ok(header) = MachHeader32::parse(data) {
if let Ok(header) = MachHeader32::parse(data, 0) {
println!("Format: Mach-O 32-bit");
print_macho(p, header, data);
}
}

pub(super) fn print_macho64(p: &mut Printer<impl Write>, data: &[u8]) {
if let Ok(header) = MachHeader64::parse(data) {
if let Ok(header) = MachHeader64::parse(data, 0) {
println!("Format: Mach-O 64-bit");
print_macho(p, header, data);
}
Expand All @@ -3248,7 +3248,7 @@ mod macho {
if let Ok(endian) = header.endian() {
let mut state = MachState::default();
print_mach_header(p, endian, header);
if let Ok(mut commands) = header.load_commands(endian, data) {
if let Ok(mut commands) = header.load_commands(endian, data, 0) {
while let Ok(Some(command)) = commands.next() {
print_load_command(p, endian, data, header, command, &mut state);
}
Expand Down
41 changes: 30 additions & 11 deletions src/read/macho/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ where
{
pub(super) endian: Mach::Endian,
pub(super) data: R,
pub(super) header_offset: u64,
pub(super) header: &'data Mach,
pub(super) sections: Vec<MachOSectionInternal<'data, Mach>>,
pub(super) symbols: SymbolTable<'data, Mach>,
Expand All @@ -45,13 +46,21 @@ where
{
/// Parse the raw Mach-O file data.
pub fn parse(data: R) -> Result<Self> {
let header = Mach::parse(data)?;
Self::parse_at_offset(data, 0)
}

/// Parse the raw Mach-O file data at an arbitrary offset inside the input data.
/// This can be used for parsing Mach-O images inside the dyld shared cache,
/// where multiple images, located at different offsets, share the same address
/// space.
pub fn parse_at_offset(data: R, header_offset: u64) -> Result<Self> {
let header = Mach::parse(data, header_offset)?;
let endian = header.endian()?;

let mut symbols = SymbolTable::default();
// Build a list of sections to make some operations more efficient.
let mut sections = Vec::new();
if let Ok(mut commands) = header.load_commands(endian, data) {
if let Ok(mut commands) = header.load_commands(endian, data, header_offset) {
while let Ok(Some(command)) = commands.next() {
if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
for section in segment.sections(endian, section_data)? {
Expand All @@ -67,6 +76,7 @@ where
Ok(MachOFile {
endian,
header,
header_offset,
sections,
symbols,
data,
Expand Down Expand Up @@ -137,7 +147,7 @@ where
file: self,
commands: self
.header
.load_commands(self.endian, self.data)
.load_commands(self.endian, self.data, self.header_offset)
.ok()
.unwrap_or_else(Default::default),
}
Expand Down Expand Up @@ -240,7 +250,9 @@ where
if twolevel {
libraries.push(&[][..]);
}
let mut commands = self.header.load_commands(self.endian, self.data)?;
let mut commands = self
.header
.load_commands(self.endian, self.data, self.header_offset)?;
while let Some(command) = commands.next()? {
if let Some(command) = command.dysymtab()? {
dysymtab = Some(command);
Expand Down Expand Up @@ -278,7 +290,9 @@ where

fn exports(&self) -> Result<Vec<Export<'data>>> {
let mut dysymtab = None;
let mut commands = self.header.load_commands(self.endian, self.data)?;
let mut commands = self
.header
.load_commands(self.endian, self.data, self.header_offset)?;
while let Some(command) = commands.next()? {
if let Some(command) = command.dysymtab()? {
dysymtab = Some(command);
Expand Down Expand Up @@ -313,11 +327,14 @@ where
}

fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
self.header.uuid(self.endian, self.data)
self.header.uuid(self.endian, self.data, self.header_offset)
}

fn entry(&self) -> u64 {
if let Ok(mut commands) = self.header.load_commands(self.endian, self.data) {
if let Ok(mut commands) =
self.header
.load_commands(self.endian, self.data, self.header_offset)
{
while let Ok(Some(command)) = commands.next() {
if let Ok(Some(command)) = command.entry_point() {
return command.entryoff.get(self.endian);
Expand Down Expand Up @@ -480,9 +497,9 @@ pub trait MachHeader: Debug + Pod {
/// Read the file header.
///
/// Also checks that the magic field in the file header is a supported format.
fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
fn parse<'data, R: ReadRef<'data>>(data: R, offset: u64) -> read::Result<&'data Self> {
let header = data
.read_at::<Self>(0)
.read_at::<Self>(offset)
.read_error("Invalid Mach-O header size or alignment")?;
if !header.is_supported() {
return Err(Error("Unsupported Mach-O header"));
Expand All @@ -502,10 +519,11 @@ pub trait MachHeader: Debug + Pod {
&self,
endian: Self::Endian,
data: R,
header_offset: u64,
) -> Result<LoadCommandIterator<'data, Self::Endian>> {
let data = data
.read_bytes_at(
mem::size_of::<Self>() as u64,
header_offset + mem::size_of::<Self>() as u64,
self.sizeofcmds(endian).into(),
)
.read_error("Invalid Mach-O load command table size")?;
Expand All @@ -517,8 +535,9 @@ pub trait MachHeader: Debug + Pod {
&self,
endian: Self::Endian,
data: R,
header_offset: u64,
) -> Result<Option<[u8; 16]>> {
let mut commands = self.load_commands(endian, data)?;
let mut commands = self.load_commands(endian, data, header_offset)?;
while let Some(command) = commands.next()? {
if let Ok(Some(uuid)) = command.uuid() {
return Ok(Some(uuid.uuid));
Expand Down
4 changes: 2 additions & 2 deletions tests/round_trip/macho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ fn issue_286_segment_file_size() {
object.append_section_data(text, &[1; 30], 0x1000);

let bytes = &*object.write().unwrap();
let header = macho::MachHeader64::parse(bytes).unwrap();
let header = macho::MachHeader64::parse(bytes, 0).unwrap();
let endian: Endianness = header.endian().unwrap();
let mut commands = header.load_commands(endian, bytes).unwrap();
let mut commands = header.load_commands(endian, bytes, 0).unwrap();
let command = commands.next().unwrap().unwrap();
let (segment, _) = command.segment_64().unwrap().unwrap();
assert_eq!(segment.vmsize.get(endian), 30);
Expand Down