From 727d34465bd897e23a890b7072e7d8fb28fb078b Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Sat, 11 May 2024 12:25:26 -0700 Subject: [PATCH 1/5] Allow attaching to existing macOS process --- samply/src/mac/process_launcher.rs | 186 ++++++++++++++++++++++------- samply/src/mac/profiler.rs | 93 ++++++++------- samply/src/mac/sampler.rs | 34 +++++- 3 files changed, 226 insertions(+), 87 deletions(-) diff --git a/samply/src/mac/process_launcher.rs b/samply/src/mac/process_launcher.rs index cbdb6299f..bfe09eb11 100644 --- a/samply/src/mac/process_launcher.rs +++ b/samply/src/mac/process_launcher.rs @@ -5,24 +5,97 @@ use std::io::Write; use std::mem; use std::os::unix::prelude::OsStrExt; use std::path::PathBuf; -use std::process::{Child, Command}; +use std::process::{Child, Command, ExitStatus}; use std::sync::Arc; use std::time::Duration; use flate2::write::GzDecoder; +use mach::task::{task_resume, task_suspend}; +use mach::traps::task_for_pid; use tempfile::tempdir; +use crate::shared::ctrl_c::CtrlC; + pub use super::mach_ipc::{mach_port_t, MachError, OsIpcSender}; -use super::mach_ipc::{BlockingMode, OsIpcMultiShotServer, MACH_PORT_NULL}; +use super::mach_ipc::{mach_task_self, BlockingMode, OsIpcMultiShotServer, MACH_PORT_NULL}; + +pub trait RootTaskRunner { + fn run_root_task(&self) -> Result; +} pub struct TaskLauncher { program: OsString, args: Vec, child_env: Vec<(OsString, OsString)>, - _temp_dir: Arc, + iteration_count: u32, +} + +impl RootTaskRunner for TaskLauncher { + fn run_root_task(&self) -> Result { + // Ignore Ctrl+C while the subcommand is running. The signal still reaches the process + // under observation while we continue to record it. (ctrl+c will send the SIGINT signal + // to all processes in the foreground process group). + let mut ctrl_c_receiver = CtrlC::observe_oneshot(); + + let mut root_child = self.launch_child(); + let mut exit_status = root_child.wait().expect("couldn't wait for child"); + + for i in 2..=self.iteration_count { + if !exit_status.success() { + eprintln!( + "Skipping remaining iterations due to non-success exit status: \"{}\"", + exit_status + ); + break; + } + eprintln!("Running iteration {i} of {}...", self.iteration_count); + let mut root_child = self.launch_child(); + exit_status = root_child.wait().expect("couldn't wait for child"); + } + + // From now on, we want to terminate if the user presses Ctrl+C. + ctrl_c_receiver.close(); + + Ok(exit_status) + } } impl TaskLauncher { + pub fn new( + program: S, + args: I, + iteration_count: u32, + env_vars: &[(OsString, OsString)], + extra_env_vars: &[(OsString, OsString)], + ) -> Result + where + I: IntoIterator, + S: Into, + { + // Take this process's environment variables and add DYLD_INSERT_LIBRARIES + // and SAMPLY_BOOTSTRAP_SERVER_NAME. + let mut child_env: BTreeMap = std::env::vars_os().collect(); + for (name, val) in env_vars { + child_env.insert(name.to_owned(), val.to_owned()); + } + for (name, val) in extra_env_vars { + child_env.insert(name.to_owned(), val.to_owned()); + } + let child_env: Vec<(OsString, OsString)> = child_env.into_iter().collect(); + + let args: Vec = args.into_iter().map(|a| a.into()).collect(); + let program: OsString = program.into(); + + Ok( + TaskLauncher { + program, + args, + child_env, + iteration_count, + }, + ) + } + pub fn launch_child(&self) -> Child { match Command::new(&self.program) .args(&self.args) @@ -49,6 +122,8 @@ impl TaskLauncher { pub struct TaskAccepter { server: OsIpcMultiShotServer, + added_env: Vec<(OsString, OsString)>, + queue: Vec, _temp_dir: Arc, } @@ -56,15 +131,7 @@ static PRELOAD_LIB_CONTENTS: &[u8] = include_bytes!("../../resources/libsamply_mac_preload.dylib.gz"); impl TaskAccepter { - pub fn new( - program: S, - args: I, - env_vars: &[(OsString, OsString)], - ) -> Result<(Self, TaskLauncher), MachError> - where - I: IntoIterator, - S: Into, - { + pub fn new() -> Result { let (server, server_name) = OsIpcMultiShotServer::new()?; // Launch the child with DYLD_INSERT_LIBRARIES set to libsamply_mac_preload.dylib. @@ -84,42 +151,38 @@ impl TaskAccepter { .finish() .expect("Couldn't write libsamply_mac_preload.dylib (error during finish)"); - // Take this process's environment variables and add DYLD_INSERT_LIBRARIES - // and SAMPLY_BOOTSTRAP_SERVER_NAME. - let mut child_env: BTreeMap = std::env::vars_os().collect(); - for (name, val) in env_vars { - child_env.insert(name.to_owned(), val.to_owned()); - } + let mut added_env: Vec<(OsString, OsString)> = vec![]; let mut add_env = |name: &str, val: &OsStr| { - child_env.insert(name.into(), val.to_owned()); + added_env.push((name.into(), val.to_owned())); // Also set the same variable with an `__XPC_` prefix, so that it gets applied // to services launched via XPC. XPC strips the prefix when setting these environment // variables on the launched process. - child_env.insert(format!("__XPC_{name}").into(), val.to_owned()); + added_env.push((format!("__XPC_{name}").into(), val.to_owned())); }; add_env("DYLD_INSERT_LIBRARIES", preload_lib_path.as_os_str()); add_env("SAMPLY_BOOTSTRAP_SERVER_NAME", OsStr::new(&server_name)); - let child_env: Vec<(OsString, OsString)> = child_env.into_iter().collect(); - let args: Vec = args.into_iter().map(|a| a.into()).collect(); - let program: OsString = program.into(); - let dir = Arc::new(dir); + Ok(TaskAccepter { + server, + added_env, + queue: vec![], + _temp_dir: Arc::new(dir), + }) + } - Ok(( - TaskAccepter { - server, - _temp_dir: dir.clone(), - }, - TaskLauncher { - program, - args, - child_env, - _temp_dir: dir, - }, - )) + pub fn extra_env_vars(&self) -> &[(OsString, OsString)] { + &self.added_env + } + + pub fn queue_received_stuff(&mut self, rs: ReceivedStuff) { + self.queue.push(rs); } pub fn next_message(&mut self, timeout: Duration) -> Result { + if let Some(rs) = self.queue.pop() { + return Ok(rs); + } + // Wait until the child is ready let (res, mut channels, _) = self .server @@ -138,7 +201,7 @@ impl TaskAccepter { ReceivedStuff::AcceptedTask(AcceptedTask { task, pid, - sender_channel, + sender_channel: Some(sender_channel), }) } (b"Jitdump", jitdump_info) => { @@ -174,12 +237,15 @@ pub enum ReceivedStuff { pub struct AcceptedTask { task: mach_port_t, pid: u32, - sender_channel: OsIpcSender, + sender_channel: Option, } impl AcceptedTask { pub fn take_task(&mut self) -> mach_port_t { - mem::replace(&mut self.task, MACH_PORT_NULL) + // TODO: I think it's safe to not do this mem::replace; we may need to resume the task + // in start_execution() + //mem::replace(&mut self.task, MACH_PORT_NULL) + self.task } pub fn get_id(&self) -> u32 { @@ -187,6 +253,46 @@ impl AcceptedTask { } pub fn start_execution(&self) { - self.sender_channel.send(b"Proceed", vec![]).unwrap(); + if let Some(sender_channel) = &self.sender_channel { + sender_channel.send(b"Proceed", vec![]).unwrap(); + } else { + unsafe { task_resume(self.task) }; + } } } + +pub struct ExistingProcessRunner { + pid: u32, +} + +impl RootTaskRunner for ExistingProcessRunner { + fn run_root_task(&self) -> Result { + let ctrl_c_receiver = CtrlC::observe_oneshot(); + + eprintln!("Profiling {}, press Ctrl-C to stop...", self.pid); + + ctrl_c_receiver.blocking_recv().expect("Ctrl+C receiver failed"); + + eprintln!("Done."); + + Ok(ExitStatus::default()) + } +} + +impl ExistingProcessRunner { + pub fn new(pid: u32, task_accepter: &mut TaskAccepter) -> ExistingProcessRunner { + let task = unsafe { + let mut task = MACH_PORT_NULL; + let kr = task_for_pid(mach_task_self(), pid as i32, &mut task); + if kr != 0 { + eprintln!("Error: task_for_pid failed with error code {kr}. Does the profiler have entitlements?"); + std::process::exit(1); + } + task_suspend(task); + task + }; + task_accepter.queue_received_stuff(ReceivedStuff::AcceptedTask(AcceptedTask { task, pid, sender_channel: None })); + ExistingProcessRunner { pid } + } +} + diff --git a/samply/src/mac/profiler.rs b/samply/src/mac/profiler.rs index 1c963742d..aa59b498a 100644 --- a/samply/src/mac/profiler.rs +++ b/samply/src/mac/profiler.rs @@ -10,11 +10,10 @@ use crossbeam_channel::unbounded; use serde_json::to_writer; use super::error::SamplingError; -use super::process_launcher::{MachError, ReceivedStuff, TaskAccepter}; -use super::sampler::{JitdumpOrMarkerPath, Sampler, TaskInit}; +use super::process_launcher::{ExistingProcessRunner, MachError, ReceivedStuff, RootTaskRunner, TaskAccepter, TaskLauncher}; +use super::sampler::{JitdumpOrMarkerPath, Sampler, TaskInit, TaskInitOrShutdown}; use super::time::get_monotonic_timestamp; use crate::server::{start_server_main, ServerProps}; -use crate::shared::ctrl_c::CtrlC; use crate::shared::recording_props::{ ProcessLaunchProps, ProfileCreationProps, RecordingMode, RecordingProps, }; @@ -25,30 +24,62 @@ pub fn start_recording( profile_creation_props: ProfileCreationProps, server_props: Option, ) -> Result { - let process_launch_props = match recording_mode { - RecordingMode::All | RecordingMode::Pid(_) => { + let mut unlink_aux_files = profile_creation_props.unlink_aux_files; + let output_file = recording_props.output_file.clone(); + let mut profile_name: String = "".to_owned(); + + let mut task_accepter = TaskAccepter::new()?; + + let root_task_runner: Box = match recording_mode { + RecordingMode::All => { // TODO: Implement, by sudo launching a helper process which uses task_for_pid eprintln!("Error: Profiling existing processes is currently not supported on macOS."); eprintln!("You can only profile processes which you launch via samply."); std::process::exit(1) } - RecordingMode::Launch(process_launch_props) => process_launch_props, + RecordingMode::Pid(pid) => { + profile_name = format!("pid {pid}"); + + Box::new(ExistingProcessRunner::new(pid, &mut task_accepter)) + } + RecordingMode::Launch(process_launch_props) => { + profile_name = process_launch_props.command_name.to_string_lossy().to_string(); + + let ProcessLaunchProps { + mut env_vars, + command_name, + args, + iteration_count, + } = process_launch_props; + + if recording_props.coreclr { + // We need to set DOTNET_PerfMapEnabled=2 in the environment if it's not already set. + // If we set it, we'll also set unlink_aux_files=true to avoid leaving files + // behind in the temp directory. But if it's set manually, assume the user + // knows what they're doing and will specify the arg as needed. + if !env_vars.iter().any(|p| p.0 == "DOTNET_PerfMapEnabled") { + env_vars.push(("DOTNET_PerfMapEnabled".into(), "2".into())); + unlink_aux_files = true; + } + } + + let task_launcher = TaskLauncher::new(&command_name, &args, iteration_count, + &env_vars, task_accepter.extra_env_vars())?; + + Box::new(task_launcher) + } }; - let ProcessLaunchProps { - env_vars, - command_name, - args, - iteration_count, - } = process_launch_props; - let command_name_copy = command_name.to_string_lossy().to_string(); - let output_file = recording_props.output_file.clone(); + let profile_creation_props = ProfileCreationProps { + unlink_aux_files, + ..profile_creation_props + }; let (task_sender, task_receiver) = unbounded(); let sampler_thread = thread::spawn(move || { let sampler = Sampler::new( - command_name_copy, + profile_name, task_receiver, recording_props, profile_creation_props, @@ -56,13 +87,6 @@ pub fn start_recording( sampler.run() }); - // Ignore Ctrl+C while the subcommand is running. The signal still reaches the process - // under observation while we continue to record it. (ctrl+c will send the SIGINT signal - // to all processes in the foreground process group). - let mut ctrl_c_receiver = CtrlC::observe_oneshot(); - - let (mut task_accepter, task_launcher) = TaskAccepter::new(&command_name, &args, &env_vars)?; - let (accepter_sender, accepter_receiver) = unbounded(); let accepter_thread = thread::spawn(move || { // Loop while accepting messages from the spawned process tree. @@ -74,6 +98,7 @@ pub fn start_recording( loop { if let Ok(()) = accepter_receiver.try_recv() { + task_sender.send(TaskInitOrShutdown::Shutdown).ok(); break; } let timeout = Duration::from_secs_f64(1.0); @@ -81,12 +106,12 @@ pub fn start_recording( Ok(ReceivedStuff::AcceptedTask(mut accepted_task)) => { let pid = accepted_task.get_id(); let (path_sender, path_receiver) = unbounded(); - let send_result = task_sender.send(TaskInit { + let send_result = task_sender.send(TaskInitOrShutdown::TaskInit(TaskInit { start_time_mono: get_monotonic_timestamp(), task: accepted_task.take_task(), pid, path_receiver, - }); + })); path_senders_per_pid.insert(pid, path_sender); if send_result.is_err() { // The sampler has already shut down. This task arrived too late. @@ -138,24 +163,8 @@ pub fn start_recording( } }); - let mut root_child = task_launcher.launch_child(); - let mut exit_status = root_child.wait().expect("couldn't wait for child"); - - for i in 2..=iteration_count { - if !exit_status.success() { - eprintln!( - "Skipping remaining iterations due to non-success exit status: \"{}\"", - exit_status - ); - break; - } - eprintln!("Running iteration {i} of {iteration_count}..."); - let mut root_child = task_launcher.launch_child(); - exit_status = root_child.wait().expect("couldn't wait for child"); - } - - // The launched subprocess is done. From now on, we want to terminate if the user presses Ctrl+C. - ctrl_c_receiver.close(); + // Run the root task: either launch or attach to existing pid + let exit_status = root_task_runner.run_root_task()?; accepter_sender .send(()) diff --git a/samply/src/mac/sampler.rs b/samply/src/mac/sampler.rs index 62717ffac..cb70e485f 100644 --- a/samply/src/mac/sampler.rs +++ b/samply/src/mac/sampler.rs @@ -20,6 +20,12 @@ pub enum JitdumpOrMarkerPath { MarkerFilePath(PathBuf), } +#[derive(Debug, Clone)] +pub enum TaskInitOrShutdown { + TaskInit(TaskInit), + Shutdown, +} + #[derive(Debug, Clone)] pub struct TaskInit { pub start_time_mono: u64, @@ -30,7 +36,7 @@ pub struct TaskInit { pub struct Sampler { command_name: String, - task_receiver: Receiver, + task_receiver: Receiver, recording_props: Arc, profile_creation_props: Arc, } @@ -38,7 +44,7 @@ pub struct Sampler { impl Sampler { pub fn new( command: String, - task_receiver: Receiver, + task_receiver: Receiver, recording_props: RecordingProps, profile_creation_props: ProfileCreationProps, ) -> Self { @@ -80,7 +86,11 @@ impl Sampler { CategoryPairHandle::from(profile.add_category("User", CategoryColor::Yellow)); let root_task_init = match self.task_receiver.recv() { - Ok(task_init) => task_init, + Ok(TaskInitOrShutdown::TaskInit(task_init)) => task_init, + Ok(TaskInitOrShutdown::Shutdown) => { + eprintln!("Unexpected Shutdown message for root task?"); + return Err(SamplingError::CouldNotObtainRootTask); + } Err(_) => { // The sender went away. No profiling today. return Err(SamplingError::CouldNotObtainRootTask); @@ -109,10 +119,11 @@ impl Sampler { let mut unwinder_cache = Default::default(); let mut unresolved_stacks = UnresolvedStacks::default(); let mut last_sleep_overshoot = 0; + let mut stop_profiling = false; loop { loop { - let task_init = if !live_tasks.is_empty() { + let task_init_or_shutdown = if !live_tasks.is_empty() { // Poll to see if there are any new tasks we should add. If no new tasks are available, // this completes immediately. self.task_receiver.try_recv().ok() @@ -122,7 +133,15 @@ impl Sampler { let all_dead_timeout = Duration::from_secs_f32(0.5); self.task_receiver.recv_timeout(all_dead_timeout).ok() }; - let Some(task_init) = task_init else { break }; + let Some(task_or_shutdown) = task_init_or_shutdown else { break }; + let task_init = match task_or_shutdown { + TaskInitOrShutdown::TaskInit(task_init) => task_init, + TaskInitOrShutdown::Shutdown => { + // We got a shutdown message, so we should just stop profiling. + stop_profiling = true; + break; + } + }; if let Ok(new_task) = TaskProfiler::new( task_init, timestamp_converter, @@ -139,6 +158,11 @@ impl Sampler { } } + if stop_profiling { + eprintln!("Stopping profile."); + break; + } + if live_tasks.is_empty() { eprintln!("All tasks terminated."); break; From d4d7126158db40c6e37d77cdf1421d55518d9f45 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Sat, 11 May 2024 18:52:42 -0700 Subject: [PATCH 2/5] fmt and clippy --- samply/src/mac/process_launcher.rs | 26 ++++++++++++++------------ samply/src/mac/profiler.rs | 20 +++++++++++++++----- samply/src/mac/sampler.rs | 6 ++++-- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/samply/src/mac/process_launcher.rs b/samply/src/mac/process_launcher.rs index bfe09eb11..6d9490dfd 100644 --- a/samply/src/mac/process_launcher.rs +++ b/samply/src/mac/process_launcher.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::ffi::{OsStr, OsString}; use std::fs::File; use std::io::Write; -use std::mem; use std::os::unix::prelude::OsStrExt; use std::path::PathBuf; use std::process::{Child, Command, ExitStatus}; @@ -86,14 +85,12 @@ impl TaskLauncher { let args: Vec = args.into_iter().map(|a| a.into()).collect(); let program: OsString = program.into(); - Ok( - TaskLauncher { - program, - args, - child_env, - iteration_count, - }, - ) + Ok(TaskLauncher { + program, + args, + child_env, + iteration_count, + }) } pub fn launch_child(&self) -> Child { @@ -271,7 +268,9 @@ impl RootTaskRunner for ExistingProcessRunner { eprintln!("Profiling {}, press Ctrl-C to stop...", self.pid); - ctrl_c_receiver.blocking_recv().expect("Ctrl+C receiver failed"); + ctrl_c_receiver + .blocking_recv() + .expect("Ctrl+C receiver failed"); eprintln!("Done."); @@ -291,8 +290,11 @@ impl ExistingProcessRunner { task_suspend(task); task }; - task_accepter.queue_received_stuff(ReceivedStuff::AcceptedTask(AcceptedTask { task, pid, sender_channel: None })); + task_accepter.queue_received_stuff(ReceivedStuff::AcceptedTask(AcceptedTask { + task, + pid, + sender_channel: None, + })); ExistingProcessRunner { pid } } } - diff --git a/samply/src/mac/profiler.rs b/samply/src/mac/profiler.rs index aa59b498a..047eb355a 100644 --- a/samply/src/mac/profiler.rs +++ b/samply/src/mac/profiler.rs @@ -10,7 +10,9 @@ use crossbeam_channel::unbounded; use serde_json::to_writer; use super::error::SamplingError; -use super::process_launcher::{ExistingProcessRunner, MachError, ReceivedStuff, RootTaskRunner, TaskAccepter, TaskLauncher}; +use super::process_launcher::{ + ExistingProcessRunner, MachError, ReceivedStuff, RootTaskRunner, TaskAccepter, TaskLauncher, +}; use super::sampler::{JitdumpOrMarkerPath, Sampler, TaskInit, TaskInitOrShutdown}; use super::time::get_monotonic_timestamp; use crate::server::{start_server_main, ServerProps}; @@ -26,7 +28,7 @@ pub fn start_recording( ) -> Result { let mut unlink_aux_files = profile_creation_props.unlink_aux_files; let output_file = recording_props.output_file.clone(); - let mut profile_name: String = "".to_owned(); + let profile_name; let mut task_accepter = TaskAccepter::new()?; @@ -43,7 +45,10 @@ pub fn start_recording( Box::new(ExistingProcessRunner::new(pid, &mut task_accepter)) } RecordingMode::Launch(process_launch_props) => { - profile_name = process_launch_props.command_name.to_string_lossy().to_string(); + profile_name = process_launch_props + .command_name + .to_string_lossy() + .to_string(); let ProcessLaunchProps { mut env_vars, @@ -63,8 +68,13 @@ pub fn start_recording( } } - let task_launcher = TaskLauncher::new(&command_name, &args, iteration_count, - &env_vars, task_accepter.extra_env_vars())?; + let task_launcher = TaskLauncher::new( + &command_name, + &args, + iteration_count, + &env_vars, + task_accepter.extra_env_vars(), + )?; Box::new(task_launcher) } diff --git a/samply/src/mac/sampler.rs b/samply/src/mac/sampler.rs index cb70e485f..8318075e2 100644 --- a/samply/src/mac/sampler.rs +++ b/samply/src/mac/sampler.rs @@ -87,7 +87,7 @@ impl Sampler { let root_task_init = match self.task_receiver.recv() { Ok(TaskInitOrShutdown::TaskInit(task_init)) => task_init, - Ok(TaskInitOrShutdown::Shutdown) => { + Ok(TaskInitOrShutdown::Shutdown) => { eprintln!("Unexpected Shutdown message for root task?"); return Err(SamplingError::CouldNotObtainRootTask); } @@ -133,7 +133,9 @@ impl Sampler { let all_dead_timeout = Duration::from_secs_f32(0.5); self.task_receiver.recv_timeout(all_dead_timeout).ok() }; - let Some(task_or_shutdown) = task_init_or_shutdown else { break }; + let Some(task_or_shutdown) = task_init_or_shutdown else { + break; + }; let task_init = match task_or_shutdown { TaskInitOrShutdown::TaskInit(task_init) => task_init, TaskInitOrShutdown::Shutdown => { From 5d40d7db0638e39c8d74b47bf395f47d39668ba8 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Sat, 11 May 2024 18:54:20 -0700 Subject: [PATCH 3/5] pr feedback --- samply/src/mac/process_launcher.rs | 5 +---- samply/src/mac/profiler.rs | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/samply/src/mac/process_launcher.rs b/samply/src/mac/process_launcher.rs index 6d9490dfd..5206407bd 100644 --- a/samply/src/mac/process_launcher.rs +++ b/samply/src/mac/process_launcher.rs @@ -238,10 +238,7 @@ pub struct AcceptedTask { } impl AcceptedTask { - pub fn take_task(&mut self) -> mach_port_t { - // TODO: I think it's safe to not do this mem::replace; we may need to resume the task - // in start_execution() - //mem::replace(&mut self.task, MACH_PORT_NULL) + pub fn task(&self) -> mach_port_t { self.task } diff --git a/samply/src/mac/profiler.rs b/samply/src/mac/profiler.rs index 047eb355a..ee04c8dbb 100644 --- a/samply/src/mac/profiler.rs +++ b/samply/src/mac/profiler.rs @@ -118,7 +118,7 @@ pub fn start_recording( let (path_sender, path_receiver) = unbounded(); let send_result = task_sender.send(TaskInitOrShutdown::TaskInit(TaskInit { start_time_mono: get_monotonic_timestamp(), - task: accepted_task.take_task(), + task: accepted_task.task(), pid, path_receiver, })); From a1dc68f5a5d3857d081067b85b280371855a67b0 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Sat, 11 May 2024 18:55:05 -0700 Subject: [PATCH 4/5] Add entitlement.xml to resources --- samply/resources/entitlement.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 samply/resources/entitlement.xml diff --git a/samply/resources/entitlement.xml b/samply/resources/entitlement.xml new file mode 100644 index 000000000..782ae7eff --- /dev/null +++ b/samply/resources/entitlement.xml @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.debugger + + com.apple.security.cs.disable-library-validation + + + From c4e03660d1704e9cd6a211abd90c99cfa3afc0c2 Mon Sep 17 00:00:00 2001 From: Vladimir Vukicevic Date: Sun, 12 May 2024 12:31:00 -0700 Subject: [PATCH 5/5] clippy --- samply/src/mac/profiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samply/src/mac/profiler.rs b/samply/src/mac/profiler.rs index ee04c8dbb..7d3a4f94b 100644 --- a/samply/src/mac/profiler.rs +++ b/samply/src/mac/profiler.rs @@ -113,7 +113,7 @@ pub fn start_recording( } let timeout = Duration::from_secs_f64(1.0); match task_accepter.next_message(timeout) { - Ok(ReceivedStuff::AcceptedTask(mut accepted_task)) => { + Ok(ReceivedStuff::AcceptedTask(accepted_task)) => { let pid = accepted_task.get_id(); let (path_sender, path_receiver) = unbounded(); let send_result = task_sender.send(TaskInitOrShutdown::TaskInit(TaskInit {