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 {
register_function(&self, name: &str, code: &[u8])67     fn register_function(&self, name: &str, code: &[u8]);
68 
69     #[cfg(all(feature = "runtime", feature = "pulley"))]
register_interpreter(&self, interp: &crate::vm::Interpreter)70     fn register_interpreter(&self, interp: &crate::vm::Interpreter) {
71         let _ = interp;
72     }
73 
register_module(&self, code: &[u8], custom_name: &dyn Fn(usize) -> Option<String>)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 
new_null() -> Box<dyn ProfilingAgent>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 {
register_function(&self, _name: &str, _code: &[u8])129     fn register_function(&self, _name: &str, _code: &[u8]) {}
register_module(&self, _code: &[u8], _custom_name: &dyn Fn(usize) -> Option<String>)130     fn register_module(&self, _code: &[u8], _custom_name: &dyn Fn(usize) -> Option<String>) {}
131 }
132