Skip to content

Commit 69db3b7

Browse files
committed
Parse fat files
1 parent 0cd5cca commit 69db3b7

File tree

1 file changed

+66
-4
lines changed

1 file changed

+66
-4
lines changed

src/symbolize/gimli.rs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ cfg_if::cfg_if! {
176176
use std::os::unix::prelude::*;
177177
use std::ffi::{OsStr, CStr};
178178
use object::{Bytes, NativeEndian};
179+
use object::macho;
179180
use object::read::macho::{MachHeader, Section, Segment as _, Nlist};
180181

181182
#[cfg(target_pointer_width = "32")]
@@ -248,6 +249,69 @@ cfg_if::cfg_if! {
248249
}
249250
}
250251

252+
fn find_header(mut data: Bytes<'_>) -> Option<(&'_ Mach, Bytes<'_>)> {
253+
use object::endian::BigEndian;
254+
255+
let desired_cpu = || {
256+
if cfg!(target_arch = "x86") {
257+
Some(macho::CPU_TYPE_X86)
258+
} else if cfg!(target_arch = "x86_64") {
259+
Some(macho::CPU_TYPE_X86_64)
260+
} else if cfg!(target_arch = "arm") {
261+
Some(macho::CPU_TYPE_ARM)
262+
} else if cfg!(target_arch = "aarch64") {
263+
Some(macho::CPU_TYPE_ARM64)
264+
} else {
265+
None
266+
}
267+
};
268+
269+
match data.clone().read::<object::endian::U32<NativeEndian>>().ok()?.get(NativeEndian) {
270+
macho::MH_MAGIC_64
271+
| macho::MH_MAGIC
272+
| macho::MH_CIGAM_64
273+
| macho::MH_CIGAM => {}
274+
275+
macho::FAT_MAGIC
276+
| macho::FAT_CIGAM => {
277+
let mut header_data = data;
278+
let endian = BigEndian;
279+
let header = header_data.read::<macho::FatHeader>().ok()?;
280+
let nfat = header.nfat_arch.get(endian);
281+
let arch = (0..nfat)
282+
.filter_map(|_| header_data.read::<macho::FatArch32>().ok())
283+
.find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?;
284+
let offset = arch.offset.get(endian);
285+
let size = arch.size.get(endian);
286+
data = data.read_bytes_at(
287+
offset.try_into().ok()?,
288+
size.try_into().ok()?,
289+
).ok()?;
290+
}
291+
292+
macho::FAT_MAGIC_64
293+
| macho::FAT_CIGAM_64 => {
294+
let mut header_data = data;
295+
let endian = BigEndian;
296+
let header = header_data.read::<macho::FatHeader>().ok()?;
297+
let nfat = header.nfat_arch.get(endian);
298+
let arch = (0..nfat)
299+
.filter_map(|_| header_data.read::<macho::FatArch64>().ok())
300+
.find(|arch| desired_cpu() == Some(arch.cputype.get(endian)))?;
301+
let offset = arch.offset.get(endian);
302+
let size = arch.size.get(endian);
303+
data = data.read_bytes_at(
304+
offset.try_into().ok()?,
305+
size.try_into().ok()?,
306+
).ok()?;
307+
}
308+
309+
_ => return None,
310+
}
311+
312+
Mach::parse(data).ok().map(|h| (h, data))
313+
}
314+
251315
#[allow(deprecated)]
252316
fn native_libraries() -> Vec<Library> {
253317
let mut ret = Vec::new();
@@ -476,8 +540,7 @@ impl Mapping {
476540
// First up we need to load the unique UUID which is stored in the macho
477541
// header of the file we're reading, specified at `path`.
478542
let map = mmap(path)?;
479-
let data = Bytes(&map);
480-
let macho = Mach::parse(data).ok()?;
543+
let (macho, data) = find_header(Bytes(&map))?;
481544
let endian = macho.endian().ok()?;
482545
let uuid = macho.uuid(endian, data).ok()??;
483546

@@ -513,8 +576,7 @@ impl Mapping {
513576
for entry in dir.read_dir().ok()? {
514577
let entry = entry.ok()?;
515578
let map = mmap(&entry.path())?;
516-
let data = Bytes(&map);
517-
let macho = Mach::parse(data).ok()?;
579+
let (macho, data) = find_header(Bytes(&map))?;
518580
let endian = macho.endian().ok()?;
519581
let entry_uuid = macho.uuid(endian, data).ok()??;
520582
if entry_uuid != uuid {

0 commit comments

Comments
 (0)