From 5e8c821daaab7c04acba7f8c2fddba0d265c8f1d Mon Sep 17 00:00:00 2001 From: wokron Date: Tue, 16 Sep 2025 23:31:14 +0800 Subject: [PATCH 1/8] sync with latest libprofiler --- src/profiler/Cargo.lock | 12 ++++++ src/profiler/Cargo.toml | 1 + src/profiler/src/bin/heatmap.rs | 2 +- src/profiler/src/bpf/native_stack.bpf.c | 31 +++++++++++--- src/profiler/src/heatmap.rs | 2 +- src/profiler/src/probes/probes.rs | 6 ++- src/profiler/src/probes/stack_delta.rs | 29 ++++++-------- src/profiler/src/profiler.rs | 9 ++++- .../src/symbollizer/lru_process_files.rs | 20 +++++++++- src/profiler/src/symbollizer/symbolizer.rs | 5 +++ src/profiler/src/tpbase/libc.rs | 2 +- src/profiler/src/utils/mod.rs | 1 + src/profiler/src/utils/process.rs | 40 +++++++++++++++++++ src/profiler/src/utils/v2p.rs | 33 +++++++++++++++ 14 files changed, 164 insertions(+), 29 deletions(-) create mode 100644 src/profiler/src/utils/v2p.rs diff --git a/src/profiler/Cargo.lock b/src/profiler/Cargo.lock index 9b6b569..8073804 100644 --- a/src/profiler/Cargo.lock +++ b/src/profiler/Cargo.lock @@ -1127,6 +1127,17 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "pagemap" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b10bd736861cab1e4a800e7547d08f5103929b3549a45a23408aaff0c1ee71" +dependencies = [ + "bitflags 1.3.2", + "libc", + "thiserror", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -1280,6 +1291,7 @@ dependencies = [ "num_cpus", "object", "once_cell", + "pagemap", "perf-event-open-sys", "procfs", "protobuf", diff --git a/src/profiler/Cargo.toml b/src/profiler/Cargo.toml index 34983b6..02fed57 100644 --- a/src/profiler/Cargo.toml +++ b/src/profiler/Cargo.toml @@ -29,6 +29,7 @@ moka = { version = "0.12.10", features = ["sync"] } num_cpus = "1.16.0" object = "0.36.1" once_cell = "1.19.0" +pagemap = "0.1.0" perf-event-open-sys = "4.0.0" procfs = "0.16.0" protobuf = "3.5.1" diff --git a/src/profiler/src/bin/heatmap.rs b/src/profiler/src/bin/heatmap.rs index a8ac780..dde5b58 100644 --- a/src/profiler/src/bin/heatmap.rs +++ b/src/profiler/src/bin/heatmap.rs @@ -7,7 +7,7 @@ use std::ffi::CString; use structopt::StructOpt; #[derive(Debug, StructOpt)] -#[structopt(name = "rtrace", about = "Diagnosing tools of kernel network")] +#[structopt(name = "heatmap", about = "show cpu heatmap")] pub struct Command { #[structopt(long, help = "Specify the Pid of the tracking process")] pid: u32, diff --git a/src/profiler/src/bpf/native_stack.bpf.c b/src/profiler/src/bpf/native_stack.bpf.c index e8c7edb..305f8df 100644 --- a/src/profiler/src/bpf/native_stack.bpf.c +++ b/src/profiler/src/bpf/native_stack.bpf.c @@ -668,10 +668,20 @@ static inline ErrorCode copy_state_regs(UnwindState *state, // Check if the process is running in 32-bit mode on the x86_64 system. // This check follows the Linux kernel implementation of user_64bit_mode() in // arch/x86/include/asm/ptrace.h. - if (regs->cs == __USER32_CS) - { - return ERR_NATIVE_X64_32BIT_COMPAT_MODE; + if (bpf_core_field_size(regs->cs) == 2) { + u16 cs; + bpf_probe_read_kernel(&cs, sizeof(cs), ®s->cs); + if (cs == __USER32_CS) + { + return ERR_NATIVE_X64_32BIT_COMPAT_MODE; + } + } else { + if (regs->cs == __USER32_CS) + { + return ERR_NATIVE_X64_32BIT_COMPAT_MODE; + } } + state->pc = regs->ip; state->sp = regs->sp; state->fp = regs->bp; @@ -731,9 +741,18 @@ static inline bool ptregs_is_usermode(struct pt_regs *regs) { #if defined(__x86_64__) // On x86_64 the user mode SS should always be __USER_DS. - if (regs->ss != __USER_DS) - { - return false; + if (bpf_core_field_size(regs->ss) == 2) { + u16 ss; + bpf_probe_read_kernel(&ss, sizeof(ss), ®s->ss); + if (ss != __USER_DS) + { + return false; + } + } else { + if (regs->ss != __USER_DS) + { + return false; + } } return true; #elif defined(__aarch64__) diff --git a/src/profiler/src/heatmap.rs b/src/profiler/src/heatmap.rs index 369179b..3379f9a 100644 --- a/src/profiler/src/heatmap.rs +++ b/src/profiler/src/heatmap.rs @@ -57,7 +57,7 @@ impl ProcessHeatMap { // find it in previous heatmap if base < heat.base { for single in self.done.iter_mut() { - if single.base == base { + if pid == single.pid && single.base == base { single.inc(slot); return; } diff --git a/src/profiler/src/probes/probes.rs b/src/profiler/src/probes/probes.rs index 9429d7d..6d5019e 100644 --- a/src/profiler/src/probes/probes.rs +++ b/src/profiler/src/probes/probes.rs @@ -267,7 +267,11 @@ impl<'a> Probes<'a> { let hotspot_skel = load_skel!(maps, hotspot::HotspotSkelBuilder); let python_skel = load_skel!(maps, python::PythonSkelBuilder); - let (tx, rx) = crossbeam_channel::unbounded(); + let ms = profile_period() as usize; + let sample_per_sec = 1000 / ms; + let ten_sec_samples = sample_per_sec * 10 * num_possible_cpus().unwrap_or(1); + log::info!("cache max stack samples: {}", ten_sec_samples); + let (tx, rx) = crossbeam_channel::bounded(ten_sec_samples); let trace_thread_handle = { let mut cloned_tx = tx.clone(); diff --git a/src/profiler/src/probes/stack_delta.rs b/src/profiler/src/probes/stack_delta.rs index a9ca5b3..c2b20fc 100644 --- a/src/profiler/src/probes/stack_delta.rs +++ b/src/profiler/src/probes/stack_delta.rs @@ -131,17 +131,15 @@ impl StackDeltaMap { pub fn update(&self, file_id: FileId64, deltas: Vec) -> Result { let map_id = get_map_id(deltas.len() as u32)?; - let inner = self - .create_inner_map(map_id) - .expect("failed to create inner map"); + let inner = self.create_inner_map(map_id)?; let outer = self.outer_map(map_id); if self.batch { - update_batch_inner_map(&inner, deltas); + update_batch_inner_map(&inner, deltas)?; } else { - update_inner_map(&inner, deltas).expect("failed to update inner map"); + update_inner_map(&inner, deltas)?; } - update_outer_map(outer, file_id, &inner).expect("failed to update outer map"); + update_outer_map(outer, file_id, &inner)?; Ok(map_id) } @@ -194,7 +192,7 @@ fn update_inner_map(inner: &MapHandle, deltas: Vec) -> Result<()> { Ok(()) } -fn update_batch_inner_map(inner: &MapHandle, deltas: Vec) { +fn update_batch_inner_map(inner: &MapHandle, deltas: Vec) -> Result<()> { let mut batch_key = Vec::with_capacity(deltas.len() * 4); let mut batch_val: Vec = Vec::with_capacity(deltas.len() * deltas[0].raw_size()); @@ -203,15 +201,14 @@ fn update_batch_inner_map(inner: &MapHandle, deltas: Vec) { batch_key.extend(idx.to_ne_bytes()); batch_val.extend(delta.slice()); } - inner - .update_batch( - &batch_key, - &batch_val, - deltas.len() as u32, - MapFlags::ANY, - MapFlags::ANY, - ) - .expect("failed to update inner map") + inner.update_batch( + &batch_key, + &batch_val, + deltas.len() as u32, + MapFlags::ANY, + MapFlags::ANY, + )?; + Ok(()) } pub fn create_inner_map(map_id: u32) -> Result { diff --git a/src/profiler/src/profiler.rs b/src/profiler/src/profiler.rs index 612d098..d051c83 100644 --- a/src/profiler/src/profiler.rs +++ b/src/profiler/src/profiler.rs @@ -15,6 +15,7 @@ use crate::stack::SymbolizedStack; use crate::symbollizer::file_cache::FileCache; use crate::symbollizer::symbolizer::Symbolizer; use crate::utils::lpm::Prefix; +use crate::utils::process::get_comm_by_pid; use crate::utils::time::init_tstamp; use crate::utils::time::time_delta; use crate::MIN_PROCESS_SAMPLES; @@ -27,7 +28,7 @@ pub struct Profiler<'a> { probes: Probes<'a>, caches: FileCache, executables: ExecutableCache, - symbolizer: Symbolizer, + pub symbolizer: Symbolizer, interpreters: HashMap, all_system_profiling: bool, @@ -261,7 +262,11 @@ impl<'a> Profiler<'a> { Ok(Some(a)) => a, Ok(None) => continue, Err(e) => { - log::error!("failed to get executable: {e}"); + log::error!( + "failed to get executable for comm {}: {:?}, err: {e}", + get_comm_by_pid(pid), + map + ); continue; } }; diff --git a/src/profiler/src/symbollizer/lru_process_files.rs b/src/profiler/src/symbollizer/lru_process_files.rs index 7128255..c8e169a 100644 --- a/src/profiler/src/symbollizer/lru_process_files.rs +++ b/src/profiler/src/symbollizer/lru_process_files.rs @@ -87,11 +87,17 @@ impl ProcessFiles { } syms } + + pub fn cache(&self, lru_files: &mut LruFileSymbols) { + for file in &self.files { + let _ = lru_files.symbolize_with_path(file.file_id, 0, &file.path); + } + } } #[derive(Debug)] pub struct LruProcessFiles { - lru: LruCache, + pub(crate) lru: LruCache, } impl LruProcessFiles { @@ -124,6 +130,18 @@ impl LruProcessFiles { } } } + + pub fn cache(&mut self, pid: u32, lru_files: &mut LruFileSymbols) { + match self + .lru + .try_get_or_insert(pid, || -> Result { ProcessFiles::new(pid) }) + { + Ok(pf) => pf.cache(lru_files), + Err(e) => { + log::warn!("failed to add process files for pid {pid}: {e}"); + } + } + } } impl Deref for LruProcessFiles { diff --git a/src/profiler/src/symbollizer/symbolizer.rs b/src/profiler/src/symbollizer/symbolizer.rs index 9ebe1e6..6974e56 100644 --- a/src/profiler/src/symbollizer/symbolizer.rs +++ b/src/profiler/src/symbollizer/symbolizer.rs @@ -183,6 +183,11 @@ impl Symbolizer { } syms } + + pub fn cache_process(&mut self, pid: u32) { + let _ = self.proc_comm(pid); + self.proc_files.cache(pid, &mut self.file_symbols); + } } #[cfg(test)] diff --git a/src/profiler/src/tpbase/libc.rs b/src/profiler/src/tpbase/libc.rs index d9bb7b6..e416006 100644 --- a/src/profiler/src/tpbase/libc.rs +++ b/src/profiler/src/tpbase/libc.rs @@ -17,7 +17,7 @@ use super::libc_decode::extract_tsd_info_native; /// Determines if the DSO filename potentially contains pthread code pub fn is_potential_tsd_dso(filename: &str) -> bool { - let libc_regex: Regex = Regex::new(r".*/(ld-musl|libpthread)([-.].*)?\.so").unwrap(); + let libc_regex: Regex = Regex::new(r".*/(ld-musl|libc|libpthread)([-.].*)?\.so").unwrap(); libc_regex.is_match(filename) } diff --git a/src/profiler/src/utils/mod.rs b/src/profiler/src/utils/mod.rs index 7ce9d57..6dd4976 100644 --- a/src/profiler/src/utils/mod.rs +++ b/src/profiler/src/utils/mod.rs @@ -3,3 +3,4 @@ pub mod process; pub mod remote_reader; pub mod safe_reader; pub mod time; +pub mod v2p; diff --git a/src/profiler/src/utils/process.rs b/src/profiler/src/utils/process.rs index b1b323a..cdd00c3 100644 --- a/src/profiler/src/utils/process.rs +++ b/src/profiler/src/utils/process.rs @@ -14,3 +14,43 @@ pub fn find_processes_by_comm(pat: &str) -> Vec { ret } + +pub fn get_comm_by_pid(pid: u32) -> String { + let path = format!("/proc/{}/comm", pid); + match std::fs::read_to_string(path) { + Ok(mut s) => { + s.pop(); // 去除末尾换行符 + s + } + Err(_) => "Unknown".to_string(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_valid_pid() { + // 获取当前进程的 PID + let current_pid = std::process::id(); + // 获取当前进程的 comm + let comm = get_comm_by_pid(current_pid); + // 验证 comm 不为空且不为 "Unknown" + assert!( + !comm.is_empty(), + "Expected non-empty comm for current process" + ); + assert_ne!(comm, "Unknown", "Expected valid comm for current process"); + log::info!("Current process (PID {}): {}", current_pid, comm); + } + + #[test] + fn test_invalid_pid() { + // 使用一个不可能存在的 PID + let invalid_pid = u32::MAX; // 4294967295 + let comm = get_comm_by_pid(invalid_pid); + assert_eq!(comm, "Unknown", "Expected 'Unknown' for invalid PID"); + log::info!("Invalid process (PID {}): {}", invalid_pid, comm); + } +} diff --git a/src/profiler/src/utils/v2p.rs b/src/profiler/src/utils/v2p.rs new file mode 100644 index 0000000..6bb6698 --- /dev/null +++ b/src/profiler/src/utils/v2p.rs @@ -0,0 +1,33 @@ +use anyhow::bail; +use anyhow::Result; +use pagemap::MemoryRegion; +use procfs::page_size; + +// user virtual address to page frame number(pfn) +pub fn v2p(pid: u32, virt: u64) -> Result { + let mut maps = pagemap::PageMap::new(pid as u64)?; + let page = page_size(); + + let start = virt & !(page - 1); + let end = start + page; + + let entries = maps.pagemap_region(&MemoryRegion::from((start, end)))?; + + if entries.len() != 1 { + bail!("Number of entries is not 1") + } + + let pfn = entries[0].pfn()?; + Ok(pfn) +} + +// user virtual address to kernel virtual address +// page_kv = (pfn << 12) + page_offset_base +// kv = page_kv + offset in page +pub fn v2kv(pid: u32, virt: u64, page_offset_base: u64) -> Result { + let pfn = v2p(pid, virt)?; + let page_kv = (pfn << 12) + page_offset_base; + let page = page_size(); + let off = virt & (page - 1); + Ok(page_kv + off) +} -- Gitee From 4917b5e3d75bf00df3b69cc6ed375ca2a54f2e15 Mon Sep 17 00:00:00 2001 From: wokron Date: Tue, 19 Aug 2025 15:05:01 +0800 Subject: [PATCH 2/8] fix memory leak --- src/profiler/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/profiler/src/lib.rs b/src/profiler/src/lib.rs index 308ec0f..13f6c3f 100644 --- a/src/profiler/src/lib.rs +++ b/src/profiler/src/lib.rs @@ -110,7 +110,7 @@ pub extern "C" fn livetrace_profiler_create() -> *mut Profiler<'static> { #[no_mangle] pub extern "C" fn livetrace_profiler_destroy(profiler: *mut Profiler) { if !profiler.is_null() { - unsafe { std::ptr::drop_in_place(profiler) } + unsafe { Box::from_raw(profiler); } } } -- Gitee From 7a004e02aff7c26b0eb3951c442beaa914df70a0 Mon Sep 17 00:00:00 2001 From: wokron Date: Tue, 19 Aug 2025 15:05:20 +0800 Subject: [PATCH 3/8] support load as so --- src/profiler/src/probes/probes.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/profiler/src/probes/probes.rs b/src/profiler/src/probes/probes.rs index 6d5019e..45cba7e 100644 --- a/src/profiler/src/probes/probes.rs +++ b/src/profiler/src/probes/probes.rs @@ -158,6 +158,10 @@ fn get_self_path() -> PathBuf { return PathBuf::from(p); } + if let Some(p) = pm.find_so("libprofiler.so") { + return PathBuf::from(p); + } + current_exe().expect("failed to find executable name") } @@ -566,9 +570,9 @@ fn thread_poll_trace_event(map: &StackMap, tx: &mut Sender, cpu: i32 let user_stackid = (*raw).user_stack_id; let user_stack = if user_stackid == i32::MAX { - RawUserStack::Native((*raw).__bindgen_anon_1.user_stack[..stack_len].to_vec()) + RawUserStack::Native((&(*raw).__bindgen_anon_1.user_stack)[..stack_len].to_vec()) } else { - RawUserStack::Dynamic((*raw).__bindgen_anon_1.frames[..stack_len].to_vec()) + RawUserStack::Dynamic((&(*raw).__bindgen_anon_1.frames)[..stack_len].to_vec()) }; let kernel_stack = if kernel_stackid >= 0 { -- Gitee From 05ba2068989a79d1f8c6a54bb1a0e1dc69536a39 Mon Sep 17 00:00:00 2001 From: wokron Date: Tue, 26 Aug 2025 11:22:08 +0800 Subject: [PATCH 4/8] support change host root path --- src/profiler/src/heatmap.rs | 3 ++- src/profiler/src/lib.rs | 20 ++++++++++++++++++++ src/profiler/src/probes/probes.rs | 5 +++-- src/profiler/src/process/maps.rs | 17 ++++++++++++++--- src/profiler/src/profiler.rs | 4 +++- src/profiler/src/symbollizer/symbolizer.rs | 5 +++-- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/profiler/src/heatmap.rs b/src/profiler/src/heatmap.rs index 3379f9a..bf632de 100644 --- a/src/profiler/src/heatmap.rs +++ b/src/profiler/src/heatmap.rs @@ -1,3 +1,4 @@ +use crate::get_host_root_path; use std::collections::HashMap; use std::collections::LinkedList; use std::fs::read_to_string; @@ -34,7 +35,7 @@ pub struct ProcessHeatMap { impl ProcessHeatMap { pub fn add_process(&mut self, pid: u32) { self.heat_maps.entry(pid).or_insert_with(|| { - let comm = match read_to_string(format!("/proc/{pid}/comm")) { + let comm = match read_to_string(format!("{}/proc/{pid}/comm", get_host_root_path())) { Ok(mut comm) => { comm.pop(); comm diff --git a/src/profiler/src/lib.rs b/src/profiler/src/lib.rs index 13f6c3f..d908db6 100644 --- a/src/profiler/src/lib.rs +++ b/src/profiler/src/lib.rs @@ -5,6 +5,7 @@ use std::ffi::CString; use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicU64; use std::sync::atomic::Ordering; +use std::sync::OnceLock; pub mod error; pub mod executable; pub mod interpreter; @@ -29,6 +30,11 @@ pub static ENABLE_SYMBOLIZER: AtomicBool = AtomicBool::new(true); pub static SYMBOL_FILE_MAX_SIZE: AtomicU64 = AtomicU64::new(u64::MAX); pub static LIVETRACE_ENABLE_CPU_INFO: AtomicBool = AtomicBool::new(false); pub static LIVETRACE_ENABLE_FUNCTION_OFFSET: AtomicBool = AtomicBool::new(false); +pub static HOST_ROOT_PATH: OnceLock = OnceLock::new(); + +pub fn get_host_root_path() -> &'static str { + HOST_ROOT_PATH.get().map(|s| s.as_str()).unwrap_or("/") +} pub fn is_enable_cpuno() -> bool { LIVETRACE_ENABLE_CPU_INFO.load(Ordering::SeqCst) @@ -102,6 +108,20 @@ pub extern "C" fn livetrace_disable_symbolizer() { ENABLE_SYMBOLIZER.store(false, Ordering::SeqCst); } +#[no_mangle] +pub extern "C" fn livetrace_set_host_root_path(path: *const libc::c_char) -> i32 { + let path = unsafe { CStr::from_ptr(path) }; + let path = match path.to_str() { + Ok(path) => path, + Err(_e) => { + return -1; + } + }; + let path = path.to_string(); + HOST_ROOT_PATH.set(path); + 0 +} + #[no_mangle] pub extern "C" fn livetrace_profiler_create() -> *mut Profiler<'static> { Box::into_raw(Box::new(Profiler::new())) diff --git a/src/profiler/src/probes/probes.rs b/src/profiler/src/probes/probes.rs index 45cba7e..65cc3b3 100644 --- a/src/profiler/src/probes/probes.rs +++ b/src/profiler/src/probes/probes.rs @@ -1,5 +1,6 @@ use crate::is_system_profiling; use crate::process::maps::ProcessMaps; +use crate::HOST_ROOT_PATH; use super::event::ProbeEvent; use super::event::RawStack; @@ -149,7 +150,7 @@ fn set_thread_need_exit() { fn get_self_path() -> PathBuf { let pid = unsafe { libc::getpid() }; - let pm = ProcessMaps::new(pid as u32).unwrap(); + let pm = ProcessMaps::new_local(pid as u32).unwrap(); if let Some(p) = pm.find_so("libmullprof.so") { return PathBuf::from(p); } @@ -453,7 +454,7 @@ impl<'a> Probes<'a> { let ret_value = SystemAnalysis::from(value); assert!(ret_value.raw.pid == 0); sc.set_stack_ptregs_offset((ret_value.raw.address - ret_value.code_u64()) as u32); - sc.set_has_pid_namespace(self.pid != self.nspid); + sc.set_has_pid_namespace(self.pid != self.nspid && HOST_ROOT_PATH.get().is_none()); system_config_skel .maps_mut() diff --git a/src/profiler/src/process/maps.rs b/src/profiler/src/process/maps.rs index b8bc647..e51400b 100644 --- a/src/profiler/src/process/maps.rs +++ b/src/profiler/src/process/maps.rs @@ -1,4 +1,5 @@ use crate::symbollizer::file_id::FileId64; +use crate::get_host_root_path; use anyhow::Result; use std::cmp::Ordering; use std::collections::HashMap; @@ -9,6 +10,7 @@ use std::io::BufReader; use std::ops::Deref; use std::ops::DerefMut; use std::path::Path; +use std::path::PathBuf; #[derive(Debug, Eq, Hash, PartialEq, Clone, Copy)] pub struct DiskFileKey { @@ -114,7 +116,7 @@ impl ProcessMapsEntry { if self.is_anonymous() || self.is_vdso() { "".to_owned() } else { - format!("/proc/{}/root/{}", pid, self.path.as_ref().unwrap()) + format!("{}/proc/{}/root/{}", get_host_root_path(), pid, self.path.as_ref().unwrap()) } } } @@ -142,8 +144,7 @@ impl DerefMut for ProcessMaps { } impl ProcessMaps { - pub fn new(pid: u32) -> Result { - let maps_path = Path::new("/proc").join(pid.to_string()).join("maps"); + fn new_inner(maps_path: PathBuf) -> Result { let file = File::open(maps_path)?; let reader = BufReader::new(file); @@ -188,6 +189,16 @@ impl ProcessMaps { Ok(Self { entries }) } + pub fn new(pid: u32) -> Result { + let maps_path = Path::new(get_host_root_path()).join("proc").join(pid.to_string()).join("maps"); + Self::new_inner(maps_path) + } + + pub fn new_local(pid: u32) -> Result { + let maps_path = Path::new("/proc").join(pid.to_string()).join("maps"); + Self::new_inner(maps_path) + } + /// Compares two `ProcessMaps` instances and returns the added and removed entries. pub fn diff(&self, other: &Self) -> (Vec, Vec) { let mut added = Vec::new(); diff --git a/src/profiler/src/profiler.rs b/src/profiler/src/profiler.rs index d051c83..8c5bf84 100644 --- a/src/profiler/src/profiler.rs +++ b/src/profiler/src/profiler.rs @@ -19,6 +19,7 @@ use crate::utils::process::get_comm_by_pid; use crate::utils::time::init_tstamp; use crate::utils::time::time_delta; use crate::MIN_PROCESS_SAMPLES; +use crate::get_host_root_path; use anyhow::Result; use std::collections::HashMap; use std::time::Instant; @@ -42,7 +43,8 @@ pub struct Profiler<'a> { impl<'a> Profiler<'a> { pub fn new() -> Self { let mut symer = Symbolizer::new(); - symer.add_kernel("/proc/kallsyms"); + let kallsyms_path = format!("{}/proc/kallsyms", get_host_root_path()); + symer.add_kernel(kallsyms_path.as_str()); init_tstamp(); Profiler { pids: HashMap::new(), diff --git a/src/profiler/src/symbollizer/symbolizer.rs b/src/profiler/src/symbollizer/symbolizer.rs index 6974e56..7fe5767 100644 --- a/src/profiler/src/symbollizer/symbolizer.rs +++ b/src/profiler/src/symbollizer/symbolizer.rs @@ -2,6 +2,7 @@ use crate::is_enable_cpuno; use crate::is_enable_function_offset; use crate::process::maps::ProcessMaps; use crate::MAX_NUM_OF_PROCESSES; +use crate::get_host_root_path; use anyhow::bail; use anyhow::Result; use lru::LruCache; @@ -125,7 +126,7 @@ impl Symbolizer { pub fn proc_comm(&mut self, pid: u32) -> Result<&String> { let get_comm = || { - let mut comm = read_to_string(format!("/proc/{pid}/comm"))?; + let mut comm = read_to_string(format!("{}/proc/{pid}/comm", get_host_root_path()))?; comm.pop(); Ok(comm) }; @@ -133,7 +134,7 @@ impl Symbolizer { self.procs .try_get_or_insert(pid, || -> Result { let comm = if let Some(reg) = &self.adb_regex { - let cmdline = read_to_string(format!("/proc/{pid}/cmdline"))?; + let cmdline = read_to_string(format!("{}/proc/{pid}/cmdline", get_host_root_path()))?; reg.find(&cmdline) .map_or_else(|| get_comm(), |x| Ok(x.as_str().to_owned())) } else { -- Gitee From d6cd95d20111460a140012bdf6a6c2e2f3a2ddcf Mon Sep 17 00:00:00 2001 From: wokron Date: Thu, 18 Sep 2025 13:52:56 +0800 Subject: [PATCH 5/8] check if btf path exists --- src/profiler/src/probes/probes.rs | 8 +++++++- src/profiler/src/probes/system_config.rs | 12 +++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/profiler/src/probes/probes.rs b/src/profiler/src/probes/probes.rs index 65cc3b3..ba8711f 100644 --- a/src/profiler/src/probes/probes.rs +++ b/src/profiler/src/probes/probes.rs @@ -51,6 +51,7 @@ use std::ffi::CString; use std::os::fd::AsFd; use std::os::fd::AsRawFd; use std::path; +use std::path::Path; use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::AtomicBool; @@ -97,8 +98,13 @@ pub static SYSAK_BTF_PATH: Lazy> = Lazy::new(|| { if info.release.starts_with("5.10") { return None; } + let path = format!("{}/tools/vmlinux-{}", sysak, info.release); + if !Path::new(&path).exists() { + log::warn!("failed to find custom btf on path: {}", path); + return None; + } return Some( - CString::new(format!("{}/tools/vmlinux-{}", sysak, info.release)).unwrap(), + CString::new(path).unwrap(), ); } } diff --git a/src/profiler/src/probes/system_config.rs b/src/profiler/src/probes/system_config.rs index 7aba761..c87f1ea 100644 --- a/src/profiler/src/probes/system_config.rs +++ b/src/profiler/src/probes/system_config.rs @@ -1,5 +1,6 @@ use crate::SYSTEM_PROFILING; +use std::path::Path; use super::types::SystemConfig; use libbpf_rs::btf::types::Composite; use libbpf_rs::btf::types::MemberAttr; @@ -12,10 +13,15 @@ pub fn get_system_config() -> SystemConfig { let btf_path: Option = { if let Ok(sysak) = std::env::var("SYSAK_WORK_PATH") { if let Ok(info) = uname::uname() { - if !info.release.starts_with("5.10") { - Some(format!("{}/tools/vmlinux-{}", sysak, info.release)) - } else { + if info.release.starts_with("5.10") { None + } else { + let path = format!("{}/tools/vmlinux-{}", sysak, info.release); + if !Path::new(&path).exists() { + None + } else { + Some(path) + } } } else { None -- Gitee From 4b821e04643fcf3f908a4552315007468b92b6bf Mon Sep 17 00:00:00 2001 From: wokron Date: Mon, 20 Oct 2025 13:11:08 +0800 Subject: [PATCH 6/8] support profiling with trace_id --- src/profiler/build.rs | 2 + .../src/bpf/interpreter_dispatcher.bpf.c | 21 +++++ src/profiler/src/bpf/tracemgmt.h | 1 + src/profiler/src/bpf/types.h | 11 +++ src/profiler/src/lib.rs | 10 +++ src/profiler/src/probes/event.rs | 1 + src/profiler/src/probes/probes.rs | 15 +++- src/profiler/src/probes/types.rs | 14 ++++ src/profiler/src/profiler.rs | 45 +++++++++- src/profiler/src/stack.rs | 8 +- src/profiler/src/symbollizer/elf.rs | 84 +++++++++++++++++++ 11 files changed, 206 insertions(+), 6 deletions(-) diff --git a/src/profiler/build.rs b/src/profiler/build.rs index 5666c0c..abe508d 100644 --- a/src/profiler/build.rs +++ b/src/profiler/build.rs @@ -8,6 +8,7 @@ fn generate_skeleton(out: &mut PathBuf, name: &str) { out.push(&rs_name); SkeletonBuilder::new() .source(&c_path) + .clang_args(["-DHAS_APM"]) .build_and_generate(&out) .unwrap(); @@ -22,6 +23,7 @@ fn generate_header(out: &mut PathBuf, name: &str) { out.push(&rs_name); let bindings = bindgen::Builder::default() .header(&header_path) + .clang_args(["-DHAS_APM"]) .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .generate() .unwrap(); diff --git a/src/profiler/src/bpf/interpreter_dispatcher.bpf.c b/src/profiler/src/bpf/interpreter_dispatcher.bpf.c index 4308cde..12c90fd 100644 --- a/src/profiler/src/bpf/interpreter_dispatcher.bpf.c +++ b/src/profiler/src/bpf/interpreter_dispatcher.bpf.c @@ -34,6 +34,27 @@ void maybe_add_apm_info(Trace *trace) { DEBUG_PRINT("Trace is within a process with APM integration enabled"); + if (proc->tracing_type == TRACE_GO_AGENT) { + const struct task_struct* task_ptr = (struct task_struct*)bpf_get_current_task(); + const void* fs_base; + bpf_probe_read(&fs_base, sizeof(void *), &task_ptr->thread.fsbase); + + size_t g_addr; // address of struct runtime.g + bpf_probe_read_user(&g_addr, sizeof(void*), (void*)(fs_base + (-8))); + + size_t go_string_addr; // address of field traceId in runtime.g + bpf_probe_read_user(&go_string_addr, sizeof(void*), (void*)(g_addr + proc->tracing_field_offset + 8)); + + size_t trace_id_addr; + bpf_probe_read_user(&trace_id_addr, sizeof(void*), (void*)(go_string_addr + 0)); + + const char trace_id[32]; + bpf_probe_read_user(trace_id, sizeof(trace_id), (void*)(trace_id_addr)); + + __builtin_memcpy(trace->trace_id, trace_id, sizeof(trace->trace_id)); + return; + } + u64 tsd_base; if (tsd_get_base((void **)&tsd_base) != 0) { increment_metric(metricID_UnwindApmIntErrReadTsdBase); diff --git a/src/profiler/src/bpf/tracemgmt.h b/src/profiler/src/bpf/tracemgmt.h index b222ae7..8b0a5c2 100644 --- a/src/profiler/src/bpf/tracemgmt.h +++ b/src/profiler/src/bpf/tracemgmt.h @@ -248,6 +248,7 @@ static inline PerCPURecord *get_pristine_per_cpu_record() trace->apm_trace_id.as_int.hi = 0; trace->apm_trace_id.as_int.lo = 0; trace->apm_transaction_id.as_int = 0; + __builtin_memset(trace->trace_id, 0, TRACE_ID_LEN); #endif return record; } diff --git a/src/profiler/src/bpf/types.h b/src/profiler/src/bpf/types.h index 1111abc..8b302e4 100644 --- a/src/profiler/src/bpf/types.h +++ b/src/profiler/src/bpf/types.h @@ -501,6 +501,8 @@ typedef struct V8ProcInfo { // COMM_LEN defines the maximum length we will receive for the comm of a task. #define COMM_LEN 16 +#define TRACE_ID_LEN 32 + #ifdef HAS_APM // 128-bit APM trace ID. typedef union ApmTraceID { @@ -550,6 +552,8 @@ typedef struct Trace { ApmSpanID apm_transaction_id; // APM trace ID or all-zero if not present. ApmTraceID apm_trace_id; + // General trace id + unsigned char trace_id[TRACE_ID_LEN]; #endif // The kernel stack ID. s32 kernel_stack_id; @@ -883,8 +887,15 @@ typedef struct SystemConfig { #define PSR_MODE_MASK 0x0000000f #define PSR_MODE_EL0t 0x00000000 +typedef enum TracingType { + TRACE_NONE, + TRACE_GO_AGENT, +} TracingType; + typedef struct ApmIntProcInfo { u64 tls_offset; + TracingType tracing_type; + u64 tracing_field_offset; } ApmIntProcInfo; #endif diff --git a/src/profiler/src/lib.rs b/src/profiler/src/lib.rs index d908db6..2ef76ff 100644 --- a/src/profiler/src/lib.rs +++ b/src/profiler/src/lib.rs @@ -31,6 +31,7 @@ pub static SYMBOL_FILE_MAX_SIZE: AtomicU64 = AtomicU64::new(u64::MAX); pub static LIVETRACE_ENABLE_CPU_INFO: AtomicBool = AtomicBool::new(false); pub static LIVETRACE_ENABLE_FUNCTION_OFFSET: AtomicBool = AtomicBool::new(false); pub static HOST_ROOT_PATH: OnceLock = OnceLock::new(); +pub static ENABLE_TRACING: AtomicBool = AtomicBool::new(false); pub fn get_host_root_path() -> &'static str { HOST_ROOT_PATH.get().map(|s| s.as_str()).unwrap_or("/") @@ -56,6 +57,10 @@ pub fn symbol_file_max_size() -> u64 { SYMBOL_FILE_MAX_SIZE.load(Ordering::SeqCst) } +pub fn is_enable_tracing() -> bool { + ENABLE_TRACING.load(Ordering::SeqCst) +} + pub fn symbol_file_max_symbols() -> u64 { let sz = symbol_file_max_size(); if sz == u64::MAX { @@ -122,6 +127,11 @@ pub extern "C" fn livetrace_set_host_root_path(path: *const libc::c_char) -> i32 0 } +#[no_mangle] +pub extern "C" fn livetrace_enable_tracing() { + ENABLE_TRACING.store(true, Ordering::SeqCst); +} + #[no_mangle] pub extern "C" fn livetrace_profiler_create() -> *mut Profiler<'static> { Box::into_raw(Box::new(Profiler::new())) diff --git a/src/profiler/src/probes/event.rs b/src/profiler/src/probes/event.rs index 4c95145..a51cabb 100644 --- a/src/profiler/src/probes/event.rs +++ b/src/profiler/src/probes/event.rs @@ -68,6 +68,7 @@ pub struct RawStack { pub time: u64, pub kernel: Vec, pub user: RawUserStack, + pub trace_id: Option, } impl RawStack {} diff --git a/src/profiler/src/probes/probes.rs b/src/profiler/src/probes/probes.rs index ba8711f..0ac4303 100644 --- a/src/profiler/src/probes/probes.rs +++ b/src/profiler/src/probes/probes.rs @@ -47,6 +47,7 @@ use perf_event_open_sys::bindings::PERF_TYPE_SOFTWARE; use perf_event_open_sys::perf_event_open; use std::collections::HashMap; use std::env::current_exe; +use std::ffi::CStr; use std::ffi::CString; use std::os::fd::AsFd; use std::os::fd::AsRawFd; @@ -103,9 +104,7 @@ pub static SYSAK_BTF_PATH: Lazy> = Lazy::new(|| { log::warn!("failed to find custom btf on path: {}", path); return None; } - return Some( - CString::new(path).unwrap(), - ); + return Some(CString::new(path).unwrap()); } } None @@ -183,7 +182,7 @@ pub struct Probes<'a> { sched_skel: sched::SchedMonitorSkel<'a>, pub hotspot_skel: hotspot::HotspotSkel<'a>, pub python_skel: python::PythonSkel<'a>, - interpreter_dispatcher_skel: dispatcher::InterpreterDispatcherSkel<'a>, + pub interpreter_dispatcher_skel: dispatcher::InterpreterDispatcherSkel<'a>, links: Vec, pub rx: Receiver, pub pid_maps_info_map: PidMapsInfoMap, @@ -588,12 +587,20 @@ fn thread_poll_trace_event(map: &StackMap, tx: &mut Sender, cpu: i32 vec![] }; + let trace_id = if (*raw).trace_id[0] != 0 { + let data = std::slice::from_raw_parts((*raw).trace_id.as_ptr() as *const u8, 32); + Some(unsafe { std::str::from_utf8_unchecked(data) }.to_owned()) + } else { + None + }; + RawStack { cpu: cpu as u32, pid, time: (*raw).ktime, kernel: kernel_stack, user: user_stack, + trace_id, } }; let comm = unsafe { diff --git a/src/profiler/src/probes/types.rs b/src/profiler/src/probes/types.rs index 19d5ecc..0918448 100644 --- a/src/profiler/src/probes/types.rs +++ b/src/profiler/src/probes/types.rs @@ -156,3 +156,17 @@ pub struct HotspotProcInfo { } impl_default!(HotspotProcInfo); + + +#[repr(u32)] +#[derive(PartialEq)] +pub enum TracingType { + TraceNone = bpf::TracingType_TRACE_NONE, + TraceGoAgent = bpf::TracingType_TRACE_GO_AGENT, +} + +pub struct ApmIntProcInfo { + pub raw: bpf::ApmIntProcInfo, +} + +impl_default!(ApmIntProcInfo); \ No newline at end of file diff --git a/src/profiler/src/profiler.rs b/src/profiler/src/profiler.rs index 8c5bf84..5e3fb26 100644 --- a/src/profiler/src/profiler.rs +++ b/src/profiler/src/profiler.rs @@ -1,17 +1,22 @@ use crate::executable::ExecutableCache; +use crate::get_host_root_path; use crate::heatmap::ProcessHeatMap; use crate::heatmap::TenSecHeatMap; use crate::interpreter::Interpreter; use crate::is_enable_symbolizer; +use crate::is_enable_tracing; use crate::is_system_profiling; use crate::probes::event::ProbeEvent; use crate::probes::probes::Probes; +use crate::probes::types::ApmIntProcInfo; +use crate::probes::types::TracingType; use crate::process::maps::ExeMapsEntry; use crate::process::maps::ProcessMaps; use crate::process::process::Process; use crate::stack::Stack; use crate::stack::StackAggregator; use crate::stack::SymbolizedStack; +use crate::symbollizer::elf::ElfFile; use crate::symbollizer::file_cache::FileCache; use crate::symbollizer::symbolizer::Symbolizer; use crate::utils::lpm::Prefix; @@ -19,8 +24,8 @@ use crate::utils::process::get_comm_by_pid; use crate::utils::time::init_tstamp; use crate::utils::time::time_delta; use crate::MIN_PROCESS_SAMPLES; -use crate::get_host_root_path; use anyhow::Result; +use libbpf_rs::MapFlags; use std::collections::HashMap; use std::time::Instant; @@ -172,6 +177,9 @@ impl<'a> Profiler<'a> { proc.exit(&mut self.probes, &mut self.executables)?; } + self.probes.interpreter_dispatcher_skel.maps_mut() + .apm_int_procs().delete(&pid.to_ne_bytes())?; + if let Some(mut int) = self.interpreters.remove(&pid) { int.exit(&mut self.probes)?; } @@ -244,6 +252,41 @@ impl<'a> Profiler<'a> { } }; + if is_enable_tracing() { + let mut trace_type = TracingType::TraceNone; + let mut field_offset = 0; + if let Ok(Some(offset)) = ElfFile::extract_field_offset(&info.file, "runtime.g", "traceId") { + log::info!("found go traceId field offset: {offset} in pid: {pid}, exe: {}", map.file_path(pid)); + trace_type = TracingType::TraceGoAgent; + field_offset = offset; + } + + if trace_type != TracingType::TraceNone { + let mut pinfo = ApmIntProcInfo::default(); + pinfo.raw.tracing_type = trace_type as u32; + pinfo.raw.tracing_field_offset = field_offset as u64; + match self + .probes + .interpreter_dispatcher_skel + .maps_mut() + .apm_int_procs() + .update(&pid.to_ne_bytes(), pinfo.slice(), MapFlags::ANY) + { + Ok(_) => { + log::info!( + "update apm_int_procs map for pid: {pid} with type: {:?}", + pinfo.raw.tracing_type as u32 + ); + } + Err(e) => { + log::warn!( + "failed to update apm_int_procs map for pid: {pid}, error: {e}" + ); + } + } + } + } + let va = match info.file_offset_to_virtual_address(map.offset) { Some(x) => x, None => { diff --git a/src/profiler/src/stack.rs b/src/profiler/src/stack.rs index cb6ed96..f010fc7 100644 --- a/src/profiler/src/stack.rs +++ b/src/profiler/src/stack.rs @@ -60,6 +60,7 @@ pub enum Frame { pub struct Stack { pub count: u32, pub frames: Vec, + pub trace_id: Option, } impl Stack { @@ -105,6 +106,7 @@ impl Stack { } stack.count = cnt; + stack.trace_id = raw.trace_id.clone(); Ok(stack) } @@ -138,7 +140,11 @@ impl ToString for Stack { .collect::>() .join(";"); - format!("{} {}", s, self.count) + if self.trace_id.is_none() { + return format!("{} {}", s, self.count); + } else { + return format!("{} {} {}", s, self.count, self.trace_id.as_deref().unwrap()); + } } } diff --git a/src/profiler/src/symbollizer/elf.rs b/src/profiler/src/symbollizer/elf.rs index 66e0a0b..64853ae 100644 --- a/src/profiler/src/symbollizer/elf.rs +++ b/src/profiler/src/symbollizer/elf.rs @@ -381,6 +381,90 @@ impl ElfFile { .ok_or(anyhow!("symbol {} not found", name)) } + pub fn extract_field_offset( + file: &File, + struct_name: &str, + field_name: &str, + ) -> Result> { + let mmap_ref = unsafe { memmap2::Mmap::map(file)? }; + let elf = object::File::parse(&*mmap_ref)?; + let endian = if elf.is_little_endian() { + gimli::RunTimeEndian::Little + } else { + gimli::RunTimeEndian::Big + }; + let arena_data = Arena::new(); + let arena_relocations = Arena::new(); + let mut load_section = |id: gimli::SectionId| -> Result<_> { + load_file_section(id, &elf, endian, false, &arena_data, &arena_relocations) + }; + + let mut dwarf = gimli::Dwarf::load(load_section).unwrap(); + + // iterate over all compilation units + let mut iter = dwarf.units(); + while let Some(header) = iter.next()? { + let unit = dwarf.unit(header)?; + + let mut entries = unit.entries(); + while let Some((depth, entry)) = entries.next_dfs()? { + if entry.tag() == gimli::DW_TAG_structure_type { + if let Some(attr) = entry.attr(gimli::DW_AT_name)? { + let string = dwarf.attr_string(&unit, attr.value())?; + let actual_string = string.to_string_lossy()?.into_owned(); + if actual_string == struct_name { + // now iterate over the children to find field + let mut children = entries.clone(); + while let Some((child_depth, child)) = children.next_dfs()? { + if child.tag() == gimli::DW_TAG_member { + if let Some(attr) = child.attr(gimli::DW_AT_name)? { + let string = dwarf.attr_string(&unit, attr.value())?; + let actual_string = string.to_string_lossy()?.into_owned(); + if actual_string == field_name { + // find the field + // extract the offset from DW_AT_data_member_location + if let Some(attr) = + child.attr(gimli::DW_AT_data_member_location)? + { + match attr.value() { + gimli::AttributeValue::Udata(offset) => { + return Ok(Some(offset as usize)); + } + gimli::AttributeValue::Data1(data) => { + return Ok(Some(data as usize)); + } + gimli::AttributeValue::Data2(data) => { + return Ok(Some(data as usize)); + } + gimli::AttributeValue::Data4(data) => { + return Ok(Some(data as usize)); + } + gimli::AttributeValue::Data8(data) => { + return Ok(Some(data as usize)); + } + _ => { + return Ok(None); + } + } + } else { + return Ok(None); + } + } + } + } else { + break; + } + } + break; + } + } + } + } + } + + return Ok(None); + } + // parse eh_frame and return stack_deltas pub fn parse_eh_frame(file: &File) -> Result> { let mmap_ref = unsafe { memmap2::Mmap::map(file)? }; -- Gitee From fb970eaca737762fb27dbf032f33fd786732a451 Mon Sep 17 00:00:00 2001 From: wokron Date: Mon, 20 Oct 2025 13:47:32 +0800 Subject: [PATCH 7/8] update stack format --- src/profiler/src/stack.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/profiler/src/stack.rs b/src/profiler/src/stack.rs index f010fc7..12539b6 100644 --- a/src/profiler/src/stack.rs +++ b/src/profiler/src/stack.rs @@ -1,4 +1,5 @@ use crate::interpreter::Interpreter; +use crate::is_enable_tracing; use crate::pb::LivetraceCell; use crate::pb::LivetraceList; use crate::pb::Ustack; @@ -140,10 +141,10 @@ impl ToString for Stack { .collect::>() .join(";"); - if self.trace_id.is_none() { - return format!("{} {}", s, self.count); + if is_enable_tracing() { + return format!("{} {} {}", s, self.count, self.trace_id.as_deref().unwrap_or("null")); } else { - return format!("{} {} {}", s, self.count, self.trace_id.as_deref().unwrap()); + return format!("{} {}", s, self.count); } } } -- Gitee From c9e275f4794c4c694a2729336ca0c25911d3e95f Mon Sep 17 00:00:00 2001 From: wokron Date: Tue, 21 Oct 2025 10:28:55 +0800 Subject: [PATCH 8/8] check if is go program before find traceId field --- src/profiler/src/profiler.rs | 28 +++++++++++++++++++++------- src/profiler/src/symbollizer/elf.rs | 9 +++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/profiler/src/profiler.rs b/src/profiler/src/profiler.rs index 5e3fb26..32156ad 100644 --- a/src/profiler/src/profiler.rs +++ b/src/profiler/src/profiler.rs @@ -177,8 +177,11 @@ impl<'a> Profiler<'a> { proc.exit(&mut self.probes, &mut self.executables)?; } - self.probes.interpreter_dispatcher_skel.maps_mut() - .apm_int_procs().delete(&pid.to_ne_bytes())?; + self.probes + .interpreter_dispatcher_skel + .maps_mut() + .apm_int_procs() + .delete(&pid.to_ne_bytes())?; if let Some(mut int) = self.interpreters.remove(&pid) { int.exit(&mut self.probes)?; @@ -255,10 +258,21 @@ impl<'a> Profiler<'a> { if is_enable_tracing() { let mut trace_type = TracingType::TraceNone; let mut field_offset = 0; - if let Ok(Some(offset)) = ElfFile::extract_field_offset(&info.file, "runtime.g", "traceId") { - log::info!("found go traceId field offset: {offset} in pid: {pid}, exe: {}", map.file_path(pid)); - trace_type = TracingType::TraceGoAgent; - field_offset = offset; + if let Ok(true) = ElfFile::check_section_exist(&info.file, ".go.buildinfo") { + log::debug!( + "found .go.buildinfo section in pid: {pid}, exe: {}", + map.file_path(pid) + ); + if let Ok(Some(offset)) = + ElfFile::extract_field_offset(&info.file, "runtime.g", "traceId") + { + log::info!( + "found go traceId field offset: {offset} in pid: {pid}, exe: {}", + map.file_path(pid) + ); + trace_type = TracingType::TraceGoAgent; + field_offset = offset; + } } if trace_type != TracingType::TraceNone { @@ -286,7 +300,7 @@ impl<'a> Profiler<'a> { } } } - + let va = match info.file_offset_to_virtual_address(map.offset) { Some(x) => x, None => { diff --git a/src/profiler/src/symbollizer/elf.rs b/src/profiler/src/symbollizer/elf.rs index 64853ae..d088339 100644 --- a/src/profiler/src/symbollizer/elf.rs +++ b/src/profiler/src/symbollizer/elf.rs @@ -465,6 +465,15 @@ impl ElfFile { return Ok(None); } + pub fn check_section_exist(file: &File, section_name: &str) -> Result { + let mmap_ref = unsafe { memmap2::Mmap::map(file)? }; + let elf = object::File::parse(&*mmap_ref)?; + if elf.section_by_name(section_name).is_some() { + return Ok(true); + } + Ok(false) + } + // parse eh_frame and return stack_deltas pub fn parse_eh_frame(file: &File) -> Result> { let mmap_ref = unsafe { memmap2::Mmap::map(file)? }; -- Gitee