Skip to content

Commit

Permalink
On MacOS, always wrap "dtrace" invocation in "arch -arch $native_arch" (
Browse files Browse the repository at this point in the history
  • Loading branch information
zbentley authored Feb 12, 2024
1 parent 651bfbf commit 1d7be18
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ perf*

# IntelliJ IDE files
.idea/
# MacOS desktop layout files
.DS_Store
35 changes: 32 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,36 @@ mod arch {
#[cfg(target_os = "windows")]
pub const BLONDIE_ERROR: &str = "could not find dtrace and could not profile using blondie";

#[cfg(target_os = "macos")]
fn base_dtrace_command(sudo: Option<Option<&str>>) -> Command {
// If DTrace is spawned from a parent process (or grandparent process etc.) running in Rosetta-emulated x86 mode
// on an ARM mac, it will fail to trace the child process with a confusing syntax error in its stdlib .d file.
// If the flamegraph binary, or the cargo binary, have been compiled as x86, this can cause all tracing to fail.
// To work around that, we unconditionally wrap dtrace on MacOS in the "arch -64/-32" wrapper so it's always
// running in the native architecture matching the bit width (32 oe 64) with which "flamegraph" was compiled.
// NOTE that dtrace-as-x86 won't trace a deliberately-cross-compiled x86 binary running under Rosetta regardless
// of "arch" wrapping; attempts to do that will fail with "DTrace cannot instrument translated processes".
// NOTE that using the ARCHPREFERENCE environment variable documented here
// (https://www.unix.com/man-page/osx/1/arch/) would be a much simpler solution to this issue, but it does not
// seem to have any effect on dtrace when set (via Command::env, shell export, or std::env in the spawning
// process).
let mut command = sudo_command("arch", sudo);

#[cfg(target_pointer_width = "64")]
command.arg("-64".to_string());
#[cfg(target_pointer_width = "32")]
command.arg("-32".to_string());

command.arg(env::var("DTRACE").unwrap_or_else(|_| "dtrace".to_string()));
command
}

#[cfg(not(target_os = "macos"))]
fn base_dtrace_command(sudo: Option<Option<&str>>) -> Command {
let dtrace = env::var("DTRACE").unwrap_or_else(|_| "dtrace".to_string());
sudo_command(&dtrace, sudo)
}

pub(crate) fn initial_command(
workload: Workload,
sudo: Option<Option<&str>>,
Expand All @@ -139,8 +169,7 @@ mod arch {
verbose: bool,
ignore_status: bool,
) -> Option<String> {
let dtrace = env::var("DTRACE").unwrap_or_else(|_| "dtrace".to_string());
let mut command = sudo_command(&dtrace, sudo);
let mut command = base_dtrace_command(sudo);

let dtrace_script = custom_cmd.unwrap_or(format!(
"profile-{} /pid == $target/ \
Expand Down Expand Up @@ -172,7 +201,7 @@ mod arch {

#[cfg(target_os = "windows")]
{
let mut help_test = Command::new(&dtrace);
let mut help_test = crate::arch::base_dtrace_command(None);

let dtrace_found = help_test
.arg("--help")
Expand Down

0 comments on commit 1d7be18

Please sign in to comment.