1 use crate::prelude::*; 2 3 cfg_if::cfg_if! { 4 if #[cfg(all(feature = "profiling", target_os = "linux"))] { 5 mod jitdump; 6 pub use jitdump::new as new_jitdump; 7 } else { 8 pub fn new_jitdump() -> Result<Box<dyn ProfilingAgent>> { 9 if cfg!(feature = "profiling") { 10 bail!("jitdump is not supported on this platform"); 11 } else { 12 bail!("jitdump support disabled at compile time"); 13 } 14 } 15 } 16 } 17 18 cfg_if::cfg_if! { 19 if #[cfg(all(unix, feature = "std"))] { 20 mod perfmap; 21 pub use perfmap::new as new_perfmap; 22 } else { 23 pub fn new_perfmap() -> Result<Box<dyn ProfilingAgent>> { 24 bail!("perfmap support not supported on this platform"); 25 } 26 } 27 } 28 29 cfg_if::cfg_if! { 30 // Note that the `#[cfg]` here should be kept in sync with the 31 // corresponding dependency directive on `ittapi` in `Cargo.toml`. 32 if #[cfg(all( 33 feature = "profiling", 34 target_arch = "x86_64", 35 any( 36 target_os = "windows", 37 target_os = "macos", 38 target_os = "linux", 39 ), 40 ))] { 41 mod vtune; 42 pub use vtune::new as new_vtune; 43 } else { 44 pub fn new_vtune() -> Result<Box<dyn ProfilingAgent>> { 45 if cfg!(feature = "profiling") { 46 bail!("VTune is not supported on this platform."); 47 } else { 48 bail!("VTune support disabled at compile time."); 49 } 50 } 51 } 52 } 53 54 cfg_if::cfg_if! { 55 if #[cfg(feature = "profile-pulley")] { 56 mod pulley; 57 pub use pulley::new as new_pulley; 58 } else { 59 pub fn new_pulley() -> Result<Box<dyn ProfilingAgent>> { 60 bail!("pulley profiling support disabled at compile time."); 61 } 62 } 63 } 64 65 /// Common interface for profiling tools. 66 pub trait ProfilingAgent: Send + Sync + 'static { 67 fn register_function(&self, name: &str, code: &[u8]); 68 69 #[cfg(all(feature = "runtime", feature = "pulley"))] 70 fn register_interpreter(&self, interp: &crate::vm::Interpreter) { 71 let _ = interp; 72 } 73 74 fn register_module(&self, code: &[u8], custom_name: &dyn Fn(usize) -> Option<String>) { 75 use object::{File, Object as _, ObjectSection, ObjectSymbol, SectionKind, SymbolKind}; 76 77 let image = match File::parse(code) { 78 Ok(image) => image, 79 Err(_) => return, 80 }; 81 82 let text = match image 83 .sections() 84 .find(|s| s.kind() == SectionKind::Text || s.name() == Ok(".text")) 85 { 86 Some(section) => match section.data() { 87 Ok(data) => data, 88 Err(_) => return, 89 }, 90 None => return, 91 }; 92 93 for sym in image.symbols() { 94 if !sym.is_definition() { 95 continue; 96 } 97 if sym.kind() != SymbolKind::Text { 98 continue; 99 } 100 let address = sym.address(); 101 let size = sym.size(); 102 if size == 0 { 103 continue; 104 } 105 if let Ok(name) = sym.name() { 106 let owned; 107 let name = match custom_name(address as usize) { 108 Some(name) => { 109 owned = name; 110 &owned 111 } 112 None => name, 113 }; 114 let code = &text[address as usize..][..size as usize]; 115 self.register_function(name, code) 116 } 117 } 118 } 119 } 120 121 pub fn new_null() -> Box<dyn ProfilingAgent> { 122 Box::new(NullProfilerAgent) 123 } 124 125 #[derive(Debug, Default, Clone, Copy)] 126 struct NullProfilerAgent; 127 128 impl ProfilingAgent for NullProfilerAgent { 129 fn register_function(&self, _name: &str, _code: &[u8]) {} 130 fn register_module(&self, _code: &[u8], _custom_name: &dyn Fn(usize) -> Option<String>) {} 131 } 132