Skip to content

Commit 3252a71

Browse files
use mach2 crate instead of depracated Mach-O types from libc crate
1 parent dbc8d47 commit 3252a71

3 files changed

Lines changed: 41 additions & 9 deletions

File tree

Cargo.lock

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

profiling/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ thiserror = "2"
4040
tracing = { version = "0.1", optional = true }
4141
uuid = { version = "1.0", features = ["v4"] }
4242

43+
[target.'cfg(target_vendor = "apple")'.dependencies]
44+
mach2 = "0.5" # version 0.6 requires edition="2024"
45+
4346
[dependencies.tracing-subscriber]
4447
version = "0.3"
4548
optional = true

profiling/src/io/got_macho.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
//
77
// ## Mach-O layout (the parts we care about)
88
//
9-
// mach_header_64
9+
// mach_header
1010
// ├─ LC_SEGMENT_64 __TEXT, __DATA, __DATA_CONST, __LINKEDIT
1111
// ├─ LC_SYMTAB → symbol table + string table (in __LINKEDIT)
1212
// └─ LC_DYSYMTAB → indirect symbol table (in __LINKEDIT)
@@ -51,11 +51,12 @@
5151

5252
// The libc crate deprecates Mach-O types in favor of the mach2 crate, but we only use a few
5353
// types and don't want to add a dependency just for that.
54-
#![allow(deprecated)]
54+
// #![allow(deprecated)]
5555

5656
use super::GotSymbolOverwrite;
5757
use libc::{c_char, c_void};
5858
use log::{error, trace};
59+
use mach2::loader;
5960
use std::ffi::CStr;
6061

6162
// ----- Mach-O load command types -----
@@ -152,6 +153,24 @@ struct Nlist64 {
152153
n_value: u64,
153154
}
154155

156+
/// Corresponds to `struct mach_header_64` in <mach-o/loader.h>.
157+
/// Used only for computing the correct load-command offset on 64-bit images.
158+
/// We intentionally define this locally:
159+
/// - `libc::mach_header_64` has the right layout but is deprecated.
160+
/// - `mach2::loader::mach_header` is missing the 64-bit `reserved` field (28 bytes vs 32),
161+
/// so using it for `size_of`/offset calculations would misalign load-command parsing.
162+
#[repr(C)]
163+
struct MachHeader64 {
164+
magic: u32,
165+
cputype: libc::cpu_type_t,
166+
cpusubtype: libc::cpu_subtype_t,
167+
filetype: u32,
168+
ncmds: u32,
169+
sizeofcmds: u32,
170+
flags: u32,
171+
reserved: u32,
172+
}
173+
155174
/// Corresponds to `struct section_64` in <mach-o/loader.h>.
156175
/// Describes a section within a segment (e.g. `__la_symbol_ptr` within `__DATA`).
157176
#[repr(C)]
@@ -183,8 +202,8 @@ struct Section64 {
183202
extern "C" {
184203
/// Returns the number of currently loaded Mach-O images.
185204
fn _dyld_image_count() -> u32;
186-
/// Returns a pointer to the mach_header_64 for the image at the given index.
187-
fn _dyld_get_image_header(image_index: u32) -> *const libc::mach_header_64;
205+
/// Returns a pointer to the mach_header for the image at the given index.
206+
fn _dyld_get_image_header(image_index: u32) -> *const loader::mach_header;
188207
/// Returns the ASLR slide for the image at the given index.
189208
fn _dyld_get_image_vmaddr_slide(image_index: u32) -> isize;
190209
/// Returns the file path of the image at the given index.
@@ -270,7 +289,7 @@ pub unsafe fn rebind_symbols(overwrites: &mut Vec<GotSymbolOverwrite>) {
270289
/// **Pass 2**: Walk `__DATA` and `__DATA_CONST` segments, find symbol pointer sections
271290
/// (`__la_symbol_ptr` / `__nl_symbol_ptr`), and patch matching entries.
272291
unsafe fn rebind_symbols_for_image(
273-
header: *const libc::mach_header_64,
292+
header: *const loader::mach_header,
274293
slide: isize,
275294
overwrites: &mut Vec<GotSymbolOverwrite>,
276295
) -> bool {
@@ -281,7 +300,7 @@ unsafe fn rebind_symbols_for_image(
281300

282301
// Load commands are stored sequentially right after the mach_header_64. Each command has
283302
// a `cmd` type and `cmdsize` telling us how many bytes to skip to reach the next command.
284-
let mut cmd_ptr = (header as *const u8).add(std::mem::size_of::<libc::mach_header_64>());
303+
let mut cmd_ptr = (header as *const u8).add(std::mem::size_of::<MachHeader64>());
285304
let ncmds = (*header).ncmds;
286305

287306
let mut symtab_cmd: *const SymtabCommand = std::ptr::null();
@@ -338,7 +357,7 @@ unsafe fn rebind_symbols_for_image(
338357
(linkedit_base + (*dysymtab_cmd).indirectsymoff as usize) as *const u32;
339358

340359
// ---- Pass 2: Find symbol pointer sections in __DATA / __DATA_CONST and patch them ----
341-
cmd_ptr = (header as *const u8).add(std::mem::size_of::<libc::mach_header_64>());
360+
cmd_ptr = (header as *const u8).add(std::mem::size_of::<MachHeader64>());
342361
let mut hooked = false;
343362

344363
for _ in 0..ncmds {
@@ -406,7 +425,7 @@ unsafe fn rebind_symbols_in_section(
406425
symtab: *const Nlist64,
407426
strtab: *const c_char,
408427
indirect_symtab: *const u32,
409-
overwrites: &mut Vec<GotSymbolOverwrite>,
428+
overwrites: &mut [GotSymbolOverwrite],
410429
is_data_const: bool,
411430
) -> bool {
412431
// Each slot in the section is one pointer (8 bytes on 64-bit). The number of slots is

0 commit comments

Comments
 (0)