From 3c143d442e637aba1e034edfe9e38fb58658d3d9 Mon Sep 17 00:00:00 2001 From: Marco Concetto Rudilosso Date: Wed, 7 May 2025 12:18:03 +0200 Subject: [PATCH 1/2] Add framehow as an unwinder and support perfmaps perfmaps are reloaded on demand in a bg thread Signed-off-by: Marco Concetto Rudilosso --- Cargo.lock | 156 +++++++++++++++++++-- Cargo.toml | 10 ++ src/backtrace/framehop_unwinder.rs | 170 +++++++++++++++++++++++ src/backtrace/framehop_unwinder/shlib.rs | 78 +++++++++++ src/backtrace/mod.rs | 18 ++- src/frames.rs | 30 +++- src/lib.rs | 9 ++ src/perfmap.rs | 99 +++++++++++++ 8 files changed, 552 insertions(+), 18 deletions(-) create mode 100644 src/backtrace/framehop_unwinder.rs create mode 100644 src/backtrace/framehop_unwinder/shlib.rs create mode 100644 src/perfmap.rs diff --git a/Cargo.lock b/Cargo.lock index b3ae7f40..49a8373e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ - "gimli", + "gimli 0.27.3", ] [[package]] @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -27,7 +33,7 @@ dependencies = [ "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -66,6 +72,12 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -88,8 +100,8 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", - "object", + "miniz_oxide 0.7.1", + "object 0.31.1", "rustc-demangle", ] @@ -126,6 +138,12 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -223,6 +241,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.5.1" @@ -285,12 +312,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -374,6 +398,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fastrand" version = "2.0.1" @@ -398,6 +428,30 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "framehop" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bdf491caf8284489b65c99366d0f88393709b8214e4ccff2f55d9892da7713" +dependencies = [ + "arrayvec", + "cfg-if", + "fallible-iterator", + "gimli 0.31.1", + "macho-unwind-info", + "pe-unwind-info", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -425,6 +479,16 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + [[package]] name = "half" version = "1.8.2" @@ -529,9 +593,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "linux-raw-sys" @@ -555,6 +619,17 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror 2.0.12", + "zerocopy 0.8.25", + "zerocopy-derive 0.8.25", +] + [[package]] name = "memchr" version = "2.6.3" @@ -588,6 +663,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "multimap" version = "0.8.3" @@ -624,6 +708,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "object" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +dependencies = [ + "flate2", + "memchr", +] + [[package]] name = "object" version = "0.31.1" @@ -668,6 +762,19 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "pe-unwind-info" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fe3d7d11dde0fd142bf734ae5d645a4c62ede7c188bccc73dec5082359ff84" +dependencies = [ + "arrayvec", + "bitflags 2.4.0", + "thiserror 1.0.69", + "zerocopy 0.7.35", + "zerocopy-derive 0.7.35", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -711,14 +818,18 @@ name = "pprof" version = "0.14.0" dependencies = [ "aligned-vec", + "arc-swap", "backtrace", "cfg-if", "criterion", "findshlibs", + "framehop", "inferno", "libc", "log", + "memmap2", "nix", + "object 0.29.0", "once_cell", "parking_lot", "prost", @@ -1395,7 +1506,17 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "zerocopy-derive", + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive 0.8.25", ] [[package]] @@ -1408,3 +1529,14 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml index e6840812..2cc94214 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,10 @@ frame-pointer = [] _protobuf = [] prost-codec = ["prost", "prost-derive", "prost-build", "sha2", "_protobuf"] protobuf-codec = ["protobuf", "protobuf-codegen", "_protobuf"] +framehop-unwinder = ["framehop", "memmap2", "object"] +perfmaps = ["arc-swap"] +large-depth = [] +huge-depth = [] [dependencies] backtrace = { version = "0.3" } @@ -41,6 +45,12 @@ protobuf = { version = ">=3.7.2", optional = true } criterion = {version = "0.5", optional = true} aligned-vec = "0.6" +# framehop unwinder dependencies +framehop = { version = "0.13", optional = true } +memmap2 = { version = "0.5.5", optional = true } +object = { version = "0.29.0", optional = true } +arc-swap = { version = "1.7.1", optional = true } + [dependencies.symbolic-demangle] version = "12.1" default-features = false diff --git a/src/backtrace/framehop_unwinder.rs b/src/backtrace/framehop_unwinder.rs new file mode 100644 index 00000000..3d0846fb --- /dev/null +++ b/src/backtrace/framehop_unwinder.rs @@ -0,0 +1,170 @@ +use framehop::{ + CacheNative, MustNotAllocateDuringUnwind, UnwindRegsNative, Unwinder, UnwinderNative, +}; +use libc::{c_void, ucontext_t}; +use once_cell::sync::Lazy; +mod shlib; + +#[cfg(all(target_arch = "aarch64", target_os = "macos"))] +fn get_regs_from_context(ucontext: *mut c_void) -> Option<(UnwindRegsNative, u64)> { + let ucontext: *mut ucontext_t = ucontext as *mut ucontext_t; + if ucontext.is_null() { + return None; + } + + let thread_state = unsafe { + let mcontext = (*ucontext).uc_mcontext; + if mcontext.is_null() { + return None; + } else { + (*mcontext).__ss + } + }; + + Some(( + UnwindRegsNative::new(thread_state.__lr, thread_state.__sp, thread_state.__fp), + thread_state.__pc, + )) +} + +#[cfg(all(target_arch = "x86_64", target_os = "macos"))] +fn get_regs_from_context(ucontext: *mut c_void) -> Option<(UnwindRegsNative, u64)> { + let ucontext: *mut ucontext_t = ucontext as *mut ucontext_t; + if ucontext.is_null() { + return None; + } + + let thread_state = unsafe { + let mcontext = (*ucontext).uc_mcontext; + if mcontext.is_null() { + return None; + } else { + (*mcontext).__ss + } + }; + + Some(( + UnwindRegsNative::new(thread_state.__rip, thread_state.__rsp, thread_state.__rbp), + thread_state.__rip, + )) +} + +#[cfg(all(target_arch = "aarch64", target_os = "linux"))] +fn get_regs_from_context(ucontext: *mut c_void) -> Option<(UnwindRegsNative, u64)> { + let ucontext: *mut ucontext_t = ucontext as *mut ucontext_t; + if ucontext.is_null() { + return None; + } + + let regs = unsafe { &(*ucontext).uc_mcontext.regs }; + let sp = unsafe { (*ucontext).uc_mcontext.sp }; + Some(( + UnwindRegsNative::new(regs[30], sp, regs[29]), + regs[30], + )) +} + +#[cfg(all(target_arch = "x86_64", target_os = "linux"))] +fn get_regs_from_context(ucontext: *mut c_void) -> Option<(UnwindRegsNative, u64)> { + let ucontext: *mut ucontext_t = ucontext as *mut ucontext_t; + if ucontext.is_null() { + return None; + } + let regs = unsafe { &(*ucontext).uc_mcontext.gregs }; + + Some(( + UnwindRegsNative::new( + regs[libc::REG_RIP as usize] as u64, + regs[libc::REG_RSP as usize] as u64, + regs[libc::REG_RBP as usize] as u64, + ), + regs[libc::REG_RIP as usize] as u64, + )) +} + +struct FramehopUnwinder { + unwinder: UnwinderNative, MustNotAllocateDuringUnwind>, + cache: CacheNative, +} + +impl FramehopUnwinder { + pub fn new() -> Self { + let mut unwinder = UnwinderNative::new(); + for obj in shlib::get_objects() { + unwinder.add_module(obj.clone()); + } + let cache = CacheNative::default(); + FramehopUnwinder { unwinder, cache } + } + + pub fn iter_frames bool>(&mut self, ctx: *mut c_void, mut cb: F) { + let (regs, pc) = match get_regs_from_context(ctx) { + Some(fp) => fp, + None => return, + }; + + let mut closure = |addr| read_stack(addr); + let mut iter = self + .unwinder + .iter_frames(pc, regs, &mut self.cache, &mut closure); + while let Ok(Some(frame)) = iter.next() { + if !cb(&Frame { + ip: frame.address() as usize, + }) { + break; + } + } + } +} + +fn read_stack(addr: u64) -> Result { + let aligned_addr = addr & !0b111; + if crate::addr_validate::validate(aligned_addr as _) { + Ok(unsafe { (aligned_addr as *const u64).read() }) + } else { + Err(()) + } +} + +static mut UNWINDER: Lazy = Lazy::new(|| FramehopUnwinder::new()); +#[derive(Clone, Debug)] +pub struct Frame { + pub ip: usize, +} + +extern "C" { + fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void; + +} + +impl super::Frame for Frame { + type S = backtrace::Symbol; + fn ip(&self) -> usize { + self.ip + } + + fn symbol_address(&self) -> *mut c_void { + if cfg!(target_os = "macos") || cfg!(target_os = "ios") { + self.ip as *mut c_void + } else { + unsafe { _Unwind_FindEnclosingFunction(self.ip as *mut c_void) } + } + } + + fn resolve_symbol(&self, cb: F) { + backtrace::resolve(self.ip as *mut c_void, cb); + } +} + +pub struct Trace; + +impl super::Trace for Trace { + type Frame = Frame; + + fn trace bool>(ctx: *mut c_void, cb: F) + where + Self: Sized, + { + unsafe { UNWINDER.iter_frames(ctx, cb) }; + } +} diff --git a/src/backtrace/framehop_unwinder/shlib.rs b/src/backtrace/framehop_unwinder/shlib.rs new file mode 100644 index 00000000..0ad59089 --- /dev/null +++ b/src/backtrace/framehop_unwinder/shlib.rs @@ -0,0 +1,78 @@ +use std::path::PathBuf; + +use findshlibs::{SharedLibrary, TargetSharedLibrary}; +use framehop::{Module, ModuleSectionInfo}; +use memmap2::Mmap; +use object::{Object, ObjectSection}; +use once_cell::sync::Lazy; + +static OBJECTS: Lazy>>> = Lazy::new(find_objects); + +pub fn get_objects() -> &'static [Module>] { + &OBJECTS +} + +pub struct ObjectInfo<'f>(object::File<'f>); + +impl<'file, D> ModuleSectionInfo for ObjectInfo<'file> +where + D: From<&'file [u8]>, +{ + fn base_svma(&self) -> u64 { + if let Some(section) = self.0.section_by_name("__TEXT") { + // in mach-o addresses are relative to __TEXT + section.address() + } else { + self.0.relative_address_base() + } + } + + fn section_svma_range(&mut self, name: &[u8]) -> Option> { + if let Some(section) = self.0.section_by_name_bytes(name) { + let start = section.address(); + let end = start + section.size(); + Some(start..end) + } else { + None + } + } + + fn section_data(&mut self, name: &[u8]) -> Option { + if let Some(section) = self.0.section_by_name_bytes(name) { + let data = section.data().ok()?; + Some(D::from(data)) + } else { + None + } + } +} + +fn open_mmap(path: &PathBuf) -> Option { + let file = std::fs::File::open(path).ok()?; + let mmap = unsafe { Mmap::map(&file) }.ok()?; + Some(mmap) +} + +fn find_objects() -> Vec>> { + let mut objects = Vec::new(); + // objects + TargetSharedLibrary::each(|shlib| { + let path = PathBuf::from(shlib.name()); + let base_avma = shlib.actual_load_addr().0 as u64; + let avma_range = base_avma..base_avma + shlib.len() as u64; + if let Some(mmap) = open_mmap(&path) { + if let Ok(obj) = object::File::parse(&*mmap) { + let section_info = ObjectInfo(obj); + + objects.push(Module::new( + path.to_string_lossy().to_string(), + avma_range, + base_avma, + section_info, + )); + } + } + }); + + objects +} diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 903d3120..810fb2b9 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -55,7 +55,7 @@ pub trait Trace { target_arch = "riscv64", target_arch = "loongarch64" ), - feature = "frame-pointer" + any(feature = "frame-pointer", feature = "framehop-unwinder") )))] mod backtrace_rs; #[cfg(not(all( @@ -65,7 +65,7 @@ mod backtrace_rs; target_arch = "riscv64", target_arch = "loongarch64" ), - feature = "frame-pointer" + any(feature = "frame-pointer", feature = "framehop-unwinder") )))] pub use backtrace_rs::Trace as TraceImpl; @@ -89,3 +89,17 @@ pub mod frame_pointer; feature = "frame-pointer" ))] pub use frame_pointer::Trace as TraceImpl; + +#[cfg(all( + any(target_arch = "x86_64", target_arch = "aarch64",), + any(target_os = "linux", target_os = "macos",), + feature = "framehop-unwinder" +))] +pub mod framehop_unwinder; + +#[cfg(all( + any(target_arch = "x86_64", target_arch = "aarch64",), + any(target_os = "linux", target_os = "macos",), + feature = "framehop-unwinder" +))] +pub use framehop_unwinder::Trace as TraceImpl; diff --git a/src/frames.rs b/src/frames.rs index c7653ba3..5092eace 100644 --- a/src/frames.rs +++ b/src/frames.rs @@ -13,6 +13,24 @@ use symbolic_demangle::demangle; use crate::backtrace::{Frame, Trace, TraceImpl}; use crate::{MAX_DEPTH, MAX_THREAD_NAME}; +#[cfg(feature = "perfmaps")] +fn resolve_in_perfmap(ip: usize) -> Option { + use crate::perfmap::get_resolver; + + if let Some(perf_map_resolver) = get_resolver().as_ref() { + if let Some(symbol) = perf_map_resolver.find(ip as _) { + return Some(Symbol::from(symbol)); + } + } + + None +} + +#[cfg(not(feature = "perfmaps"))] +fn resolve_in_perfmap(_ip: usize) -> Option { + None +} + #[derive(Clone)] pub struct UnresolvedFrames { pub frames: SmallVec<[::Frame; MAX_DEPTH]>, @@ -192,10 +210,14 @@ impl From for Frames { while let Some(frame) = frame_iter.next() { let mut symbols: Vec = Vec::new(); - frame.resolve_symbol(|symbol| { - let symbol = Symbol::from(symbol); - symbols.push(symbol); - }); + if let Some(perfmap_symbol) = resolve_in_perfmap(frame.ip() as usize) { + symbols.push(perfmap_symbol); + } else { + frame.resolve_symbol(|symbol| { + let symbol = Symbol::from(symbol); + symbols.push(symbol); + }); + } if symbols.iter().any(|symbol| { // macOS prepends an underscore even with `#[no_mangle]` diff --git a/src/lib.rs b/src/lib.rs index 448c52b4..b8181932 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,13 @@ //! [README.md](https://github.com/tikv/pprof-rs/blob/master/README.md) /// Define the MAX supported stack depth. TODO: make this variable mutable. +#[cfg(feature = "large-depth")] +pub const MAX_DEPTH: usize = 1024; + +#[cfg(all(feature = "huge-depth", not(feature = "large-depth")))] +pub const MAX_DEPTH: usize = 512; + +#[cfg(not(any(feature = "large-depth", feature = "huge-depth")))] pub const MAX_DEPTH: usize = 128; /// Define the MAX supported thread name length. TODO: make this variable mutable. @@ -51,6 +58,8 @@ mod backtrace; mod collector; mod error; mod frames; +#[cfg(feature = "perfmaps")] +mod perfmap; mod profiler; mod report; mod timer; diff --git a/src/perfmap.rs b/src/perfmap.rs new file mode 100644 index 00000000..6be9cb8e --- /dev/null +++ b/src/perfmap.rs @@ -0,0 +1,99 @@ +use std::{fs::File, io::BufRead, path::PathBuf, sync::{atomic::AtomicU64, Arc}}; + +use arc_swap::ArcSwap; +use once_cell::sync::Lazy; + +use crate::{Error, Symbol}; + +#[derive(Debug)] +pub struct PerfMap { + ranges: Vec<(usize, usize, String)>, +} + +impl PerfMap { + pub fn new(file: File) -> Option { + let reader = std::io::BufReader::new(file); + let mut ranges = Vec::new(); + for line in reader.lines() { + let line = line.ok()?; + // The format of perf map is: + // + // where and are hexadecimal numbers. + // where may contain spaces. + let mut parts = line.split_whitespace(); + let start = usize::from_str_radix(parts.next()?, 16).ok()?; + let len = usize::from_str_radix(parts.next()?, 16).ok()?; + let name = parts.collect::>().join(" "); + ranges.push((start, start + len, name)); + } + Some(Self { ranges }) + } + + pub fn find(&self, addr: usize) -> Option { + for (start, end, name) in &self.ranges { + if *start <= addr && addr < *end { + return Some(PerfMapSymbol(name.clone())); + } + } + None + } +} + +#[derive(Debug)] +pub struct PerfMapSymbol(String); + +impl From for Symbol { + fn from(value: PerfMapSymbol) -> Self { + Symbol { + name: Some(value.0.into_bytes()), + addr: None, + filename: None, + lineno: None, + } + } +} + +fn touch(path: &PathBuf) -> Result<(), Error> { + std::fs::OpenOptions::new() + .create(true) + .write(true) + .open(path) + .map_err(|_| Error::CreatingError)?; + Ok(()) +} + +static MTIME: AtomicU64 = AtomicU64::new(0); + +fn init_resolver() -> Option { + let path = PathBuf::from("/tmp/").join(format!("perf-{}.map", std::process::id())); + File::open(&path).ok().and_then(|f| { + let mtime = path.metadata().ok()?.modified().ok()?; + let mtime = mtime.duration_since(std::time::UNIX_EPOCH).ok()?; + if MTIME.load(std::sync::atomic::Ordering::Relaxed) == mtime.as_secs() { + return None; + } else { + MTIME.store(mtime.as_secs(), std::sync::atomic::Ordering::Relaxed); + } + PerfMap::new(f) + }) +} + +pub fn get_resolver() -> Arc> { + static RESOLVER: Lazy>> = Lazy::new(|| { + // this makes sure the file exists + touch(&PathBuf::from("/tmp/").join(format!("perf-{}.map", std::process::id()))).ok(); + ArcSwap::from(Arc::new(init_resolver())) + }); + + std::thread::spawn(|| { + let perf_map = init_resolver(); + + if perf_map.is_none() { + return; + } + + RESOLVER.store(Arc::new(perf_map)); + }); + + RESOLVER.load().clone() +} From d6accddf81b80085c02b881e0d01ae814c1b79f2 Mon Sep 17 00:00:00 2001 From: Marco Concetto Rudilosso Date: Tue, 13 May 2025 15:24:13 +0200 Subject: [PATCH 2/2] fix cargo fmt Signed-off-by: Marco Concetto Rudilosso --- src/backtrace/framehop_unwinder.rs | 5 +---- src/perfmap.rs | 7 ++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/backtrace/framehop_unwinder.rs b/src/backtrace/framehop_unwinder.rs index 3d0846fb..98ac8f3b 100644 --- a/src/backtrace/framehop_unwinder.rs +++ b/src/backtrace/framehop_unwinder.rs @@ -58,10 +58,7 @@ fn get_regs_from_context(ucontext: *mut c_void) -> Option<(UnwindRegsNative, u64 let regs = unsafe { &(*ucontext).uc_mcontext.regs }; let sp = unsafe { (*ucontext).uc_mcontext.sp }; - Some(( - UnwindRegsNative::new(regs[30], sp, regs[29]), - regs[30], - )) + Some((UnwindRegsNative::new(regs[30], sp, regs[29]), regs[30])) } #[cfg(all(target_arch = "x86_64", target_os = "linux"))] diff --git a/src/perfmap.rs b/src/perfmap.rs index 6be9cb8e..61b95b8b 100644 --- a/src/perfmap.rs +++ b/src/perfmap.rs @@ -1,4 +1,9 @@ -use std::{fs::File, io::BufRead, path::PathBuf, sync::{atomic::AtomicU64, Arc}}; +use std::{ + fs::File, + io::BufRead, + path::PathBuf, + sync::{atomic::AtomicU64, Arc}, +}; use arc_swap::ArcSwap; use once_cell::sync::Lazy;