Skip to content

Commit ba60aa4

Browse files
authored
Merge pull request #304 from mstange/macho-header-offset
Add MachOFile::parse_at_offset
2 parents 0ec88f3 + 5be7f0e commit ba60aa4

File tree

3 files changed

+35
-16
lines changed

3 files changed

+35
-16
lines changed

examples/readobj.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -3222,14 +3222,14 @@ mod macho {
32223222
}
32233223

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

32313231
pub(super) fn print_macho64(p: &mut Printer<impl Write>, data: &[u8]) {
3232-
if let Ok(header) = MachHeader64::parse(data) {
3232+
if let Ok(header) = MachHeader64::parse(data, 0) {
32333233
println!("Format: Mach-O 64-bit");
32343234
print_macho(p, header, data);
32353235
}
@@ -3248,7 +3248,7 @@ mod macho {
32483248
if let Ok(endian) = header.endian() {
32493249
let mut state = MachState::default();
32503250
print_mach_header(p, endian, header);
3251-
if let Ok(mut commands) = header.load_commands(endian, data) {
3251+
if let Ok(mut commands) = header.load_commands(endian, data, 0) {
32523252
while let Ok(Some(command)) = commands.next() {
32533253
print_load_command(p, endian, data, header, command, &mut state);
32543254
}

src/read/macho/file.rs

+30-11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ where
3333
{
3434
pub(super) endian: Mach::Endian,
3535
pub(super) data: R,
36+
pub(super) header_offset: u64,
3637
pub(super) header: &'data Mach,
3738
pub(super) sections: Vec<MachOSectionInternal<'data, Mach>>,
3839
pub(super) symbols: SymbolTable<'data, Mach>,
@@ -45,13 +46,21 @@ where
4546
{
4647
/// Parse the raw Mach-O file data.
4748
pub fn parse(data: R) -> Result<Self> {
48-
let header = Mach::parse(data)?;
49+
Self::parse_at_offset(data, 0)
50+
}
51+
52+
/// Parse the raw Mach-O file data at an arbitrary offset inside the input data.
53+
/// This can be used for parsing Mach-O images inside the dyld shared cache,
54+
/// where multiple images, located at different offsets, share the same address
55+
/// space.
56+
pub fn parse_at_offset(data: R, header_offset: u64) -> Result<Self> {
57+
let header = Mach::parse(data, header_offset)?;
4958
let endian = header.endian()?;
5059

5160
let mut symbols = SymbolTable::default();
5261
// Build a list of sections to make some operations more efficient.
5362
let mut sections = Vec::new();
54-
if let Ok(mut commands) = header.load_commands(endian, data) {
63+
if let Ok(mut commands) = header.load_commands(endian, data, header_offset) {
5564
while let Ok(Some(command)) = commands.next() {
5665
if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
5766
for section in segment.sections(endian, section_data)? {
@@ -67,6 +76,7 @@ where
6776
Ok(MachOFile {
6877
endian,
6978
header,
79+
header_offset,
7080
sections,
7181
symbols,
7282
data,
@@ -137,7 +147,7 @@ where
137147
file: self,
138148
commands: self
139149
.header
140-
.load_commands(self.endian, self.data)
150+
.load_commands(self.endian, self.data, self.header_offset)
141151
.ok()
142152
.unwrap_or_else(Default::default),
143153
}
@@ -240,7 +250,9 @@ where
240250
if twolevel {
241251
libraries.push(&[][..]);
242252
}
243-
let mut commands = self.header.load_commands(self.endian, self.data)?;
253+
let mut commands = self
254+
.header
255+
.load_commands(self.endian, self.data, self.header_offset)?;
244256
while let Some(command) = commands.next()? {
245257
if let Some(command) = command.dysymtab()? {
246258
dysymtab = Some(command);
@@ -278,7 +290,9 @@ where
278290

279291
fn exports(&self) -> Result<Vec<Export<'data>>> {
280292
let mut dysymtab = None;
281-
let mut commands = self.header.load_commands(self.endian, self.data)?;
293+
let mut commands = self
294+
.header
295+
.load_commands(self.endian, self.data, self.header_offset)?;
282296
while let Some(command) = commands.next()? {
283297
if let Some(command) = command.dysymtab()? {
284298
dysymtab = Some(command);
@@ -313,11 +327,14 @@ where
313327
}
314328

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

319333
fn entry(&self) -> u64 {
320-
if let Ok(mut commands) = self.header.load_commands(self.endian, self.data) {
334+
if let Ok(mut commands) =
335+
self.header
336+
.load_commands(self.endian, self.data, self.header_offset)
337+
{
321338
while let Ok(Some(command)) = commands.next() {
322339
if let Ok(Some(command)) = command.entry_point() {
323340
return command.entryoff.get(self.endian);
@@ -480,9 +497,9 @@ pub trait MachHeader: Debug + Pod {
480497
/// Read the file header.
481498
///
482499
/// Also checks that the magic field in the file header is a supported format.
483-
fn parse<'data, R: ReadRef<'data>>(data: R) -> read::Result<&'data Self> {
500+
fn parse<'data, R: ReadRef<'data>>(data: R, offset: u64) -> read::Result<&'data Self> {
484501
let header = data
485-
.read_at::<Self>(0)
502+
.read_at::<Self>(offset)
486503
.read_error("Invalid Mach-O header size or alignment")?;
487504
if !header.is_supported() {
488505
return Err(Error("Unsupported Mach-O header"));
@@ -502,10 +519,11 @@ pub trait MachHeader: Debug + Pod {
502519
&self,
503520
endian: Self::Endian,
504521
data: R,
522+
header_offset: u64,
505523
) -> Result<LoadCommandIterator<'data, Self::Endian>> {
506524
let data = data
507525
.read_bytes_at(
508-
mem::size_of::<Self>() as u64,
526+
header_offset + mem::size_of::<Self>() as u64,
509527
self.sizeofcmds(endian).into(),
510528
)
511529
.read_error("Invalid Mach-O load command table size")?;
@@ -517,8 +535,9 @@ pub trait MachHeader: Debug + Pod {
517535
&self,
518536
endian: Self::Endian,
519537
data: R,
538+
header_offset: u64,
520539
) -> Result<Option<[u8; 16]>> {
521-
let mut commands = self.load_commands(endian, data)?;
540+
let mut commands = self.load_commands(endian, data, header_offset)?;
522541
while let Some(command) = commands.next()? {
523542
if let Ok(Some(uuid)) = command.uuid() {
524543
return Ok(Some(uuid.uuid));

tests/round_trip/macho.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ fn issue_286_segment_file_size() {
1414
object.append_section_data(text, &[1; 30], 0x1000);
1515

1616
let bytes = &*object.write().unwrap();
17-
let header = macho::MachHeader64::parse(bytes).unwrap();
17+
let header = macho::MachHeader64::parse(bytes, 0).unwrap();
1818
let endian: Endianness = header.endian().unwrap();
19-
let mut commands = header.load_commands(endian, bytes).unwrap();
19+
let mut commands = header.load_commands(endian, bytes, 0).unwrap();
2020
let command = commands.next().unwrap().unwrap();
2121
let (segment, _) = command.segment_64().unwrap().unwrap();
2222
assert_eq!(segment.vmsize.get(endian), 30);

0 commit comments

Comments
 (0)