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: VTune support is disabled on windows mingw because the ittapi crate doesn't compile
31     // there; see also https://github.com/bytecodealliance/wasmtime/pull/4003 for rationale.
32     if #[cfg(all(feature = "profiling", target_arch = "x86_64", not(any(target_os = "android", all(target_os = "windows", target_env = "gnu")))))] {
33         mod vtune;
34         pub use vtune::new as new_vtune;
35     } else {
36         pub fn new_vtune() -> Result<Box<dyn ProfilingAgent>> {
37             if cfg!(feature = "profiling") {
38                 bail!("VTune is not supported on this platform.");
39             } else {
40                 bail!("VTune support disabled at compile time.");
41             }
42         }
43     }
44 }
45 
46 /// Common interface for profiling tools.
47 pub trait ProfilingAgent: Send + Sync + 'static {
48     fn register_function(&self, name: &str, code: &[u8]);
49 
50     fn register_module(&self, code: &[u8], custom_name: &dyn Fn(usize) -> Option<String>) {
51         use object::{File, Object as _, ObjectSection, ObjectSymbol, SectionKind, SymbolKind};
52 
53         let image = match File::parse(code) {
54             Ok(image) => image,
55             Err(_) => return,
56         };
57 
58         let text = match image.sections().find(|s| s.kind() == SectionKind::Text) {
59             Some(section) => match section.data() {
60                 Ok(data) => data,
61                 Err(_) => return,
62             },
63             None => return,
64         };
65 
66         for sym in image.symbols() {
67             if !sym.is_definition() {
68                 continue;
69             }
70             if sym.kind() != SymbolKind::Text {
71                 continue;
72             }
73             let address = sym.address();
74             let size = sym.size();
75             if size == 0 {
76                 continue;
77             }
78             if let Ok(name) = sym.name() {
79                 let owned;
80                 let name = match custom_name(address as usize) {
81                     Some(name) => {
82                         owned = name;
83                         &owned
84                     }
85                     None => name,
86                 };
87                 let code = &text[address as usize..][..size as usize];
88                 self.register_function(name, code)
89             }
90         }
91     }
92 }
93 
94 pub fn new_null() -> Box<dyn ProfilingAgent> {
95     Box::new(NullProfilerAgent)
96 }
97 
98 #[derive(Debug, Default, Clone, Copy)]
99 struct NullProfilerAgent;
100 
101 impl ProfilingAgent for NullProfilerAgent {
102     fn register_function(&self, _name: &str, _code: &[u8]) {}
103     fn register_module(&self, _code: &[u8], _custom_name: &dyn Fn(usize) -> Option<String>) {}
104 }
105