1 use crate::prelude::*;
2 use crate::profiling_agent::ProfilingAgent;
3 use std::io::{self, BufWriter, Write};
4 use std::process;
5 use std::{fs::File, sync::Mutex};
6 
7 /// Process-wide perf map file. Perf only reads a unique file per process.
8 static PERFMAP_FILE: Mutex<Option<BufWriter<File>>> = Mutex::new(None);
9 
10 /// Interface for driving the creation of jitdump files
11 struct PerfMapAgent;
12 
13 /// Initialize a JitDumpAgent and write out the header.
14 pub fn new() -> Result<Box<dyn ProfilingAgent>> {
15     let mut file = PERFMAP_FILE.lock().unwrap();
16     if file.is_none() {
17         let filename = format!("/tmp/perf-{}.map", process::id());
18         *file = Some(BufWriter::new(File::create(filename)?));
19     }
20     Ok(Box::new(PerfMapAgent))
21 }
22 
23 impl PerfMapAgent {
24     fn make_line(
25         writer: &mut dyn Write,
26         name: &str,
27         addr: *const u8,
28         len: usize,
29     ) -> io::Result<()> {
30         // Format is documented here: https://github.com/torvalds/linux/blob/master/tools/perf/Documentation/jit-interface.txt
31         // Try our best to sanitize the name, since wasm allows for any utf8 string in there.
32         let sanitized_name = name.replace('\n', "_").replace('\r', "_");
33         write!(writer, "{:x} {:x} {}\n", addr as usize, len, sanitized_name)?;
34         writer.flush()?;
35         Ok(())
36     }
37 }
38 
39 impl ProfilingAgent for PerfMapAgent {
40     fn register_function(&self, name: &str, addr: *const u8, size: usize) {
41         let mut file = PERFMAP_FILE.lock().unwrap();
42         let file = file.as_mut().unwrap();
43         if let Err(err) = Self::make_line(file, name, addr, size) {
44             eprintln!("Error when writing import trampoline info to the perf map file: {err}");
45         }
46     }
47 }
48