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