diff --git a/Cargo.lock b/Cargo.lock index cc4bcf83..57257842 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "fallible-iterator 0.3.0", - "gimli 0.28.1", + "gimli", ] [[package]] @@ -27,7 +27,7 @@ dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.32", + "zerocopy", ] [[package]] @@ -99,6 +99,12 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "assert-json-diff" version = "2.0.2" @@ -606,13 +612,15 @@ dependencies = [ [[package]] name = "framehop" -version = "0.7.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3cae7151aeb94b1e204677f528adf6f6c56c0f56dbc5661c910b1f7deab806" +checksum = "38bb3ea0d42943711eafa7a6182b47a21d51247d2ecad6641ff61d9213d099ea" dependencies = [ - "fallible-iterator 0.2.0", - "gimli 0.27.3", - "macho-unwind-info 0.3.0", + "arrayvec", + "fallible-iterator 0.3.0", + "gimli", + "macho-unwind-info", + "pe-unwind-info", "thiserror", ] @@ -761,17 +769,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -dependencies = [ - "fallible-iterator 0.2.0", - "indexmap 1.9.3", - "stable_deref_trait", -] - [[package]] name = "gimli" version = "0.28.1" @@ -779,6 +776,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" dependencies = [ "fallible-iterator 0.3.0", + "indexmap", "stable_deref_trait", ] @@ -794,19 +792,13 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.2", + "indexmap", "slab", "tokio", "tokio-util", "tracing", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - [[package]] name = "hashbrown" version = "0.14.3" @@ -910,16 +902,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - [[package]] name = "indexmap" version = "2.2.2" @@ -927,7 +909,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown", ] [[package]] @@ -1061,16 +1043,6 @@ dependencies = [ "libc", ] -[[package]] -name = "macho-unwind-info" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29014be9ddec1a1e9bfbb926493d2df811adc2e257a5a36072136eb84c19c14f" -dependencies = [ - "thiserror", - "zerocopy 0.6.6", -] - [[package]] name = "macho-unwind-info" version = "0.4.0" @@ -1078,8 +1050,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b6086acc74bc23f56b60e88bb082d505e23849d68d6c0f12bb6a7ad5c60e03e" dependencies = [ "thiserror", - "zerocopy 0.7.32", - "zerocopy-derive 0.7.32", + "zerocopy", + "zerocopy-derive", ] [[package]] @@ -1223,8 +1195,8 @@ checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.14.3", - "indexmap 2.2.2", + "hashbrown", + "indexmap", "memchr", "ruzstd", ] @@ -1300,6 +1272,19 @@ dependencies = [ "uuid", ] +[[package]] +name = "pe-unwind-info" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00503160cacc009a96696645b4acc6d8fdc7a3f3a3120eb2e08a8ec5234bc2e7" +dependencies = [ + "arrayvec", + "bitflags 2.4.2", + "thiserror", + "zerocopy", + "zerocopy-derive", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1682,10 +1667,10 @@ dependencies = [ "elsa", "flate2", "futures", - "gimli 0.28.1", + "gimli", "linux-perf-data", "lzma-rs", - "macho-unwind-info 0.4.0", + "macho-unwind-info", "memchr", "memmap2 0.9.4", "msvc-demangler", @@ -1699,8 +1684,8 @@ dependencies = [ "uuid", "yoke", "yoke-derive", - "zerocopy 0.7.32", - "zerocopy-derive 0.7.32", + "zerocopy", + "zerocopy-derive", ] [[package]] @@ -2569,16 +2554,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854e949ac82d619ee9a14c66a1b674ac730422372ccb759ce0c39cabcf2bf8e6" -dependencies = [ - "byteorder", - "zerocopy-derive 0.6.6", -] - [[package]] name = "zerocopy" version = "0.7.32" @@ -2586,18 +2561,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "byteorder", - "zerocopy-derive 0.7.32", -] - -[[package]] -name = "zerocopy-derive" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "125139de3f6b9d625c39e2efdd73d41bdac468ccd556556440e322be0e1bbd91" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "zerocopy-derive", ] [[package]] diff --git a/samply/Cargo.toml b/samply/Cargo.toml index 2cecbe4c..6ed6c36c 100644 --- a/samply/Cargo.toml +++ b/samply/Cargo.toml @@ -13,7 +13,7 @@ readme = "README.md" fxprof-processed-profile = { version = "0.6", path = "../fxprof-processed-profile" } # framehop = { path = "../../framehop" } -framehop = "0.7.2" +framehop = "0.9.0" # linux-perf-data = { path = "../../linux-perf-data" } linux-perf-data = "0.8.2" diff --git a/samply/src/linux_shared/converter.rs b/samply/src/linux_shared/converter.rs index 96fb4cff..0c49cb03 100644 --- a/samply/src/linux_shared/converter.rs +++ b/samply/src/linux_shared/converter.rs @@ -1,7 +1,7 @@ use byteorder::LittleEndian; use debugid::{CodeId, DebugId}; -use framehop::{FrameAddress, Module, ModuleSvmaInfo, ModuleUnwindData, TextByteData, Unwinder}; +use framehop::{ExplicitModuleSectionInfo, FrameAddress, Module, Unwinder}; use fxprof_processed_profile::{ CpuDelta, LibraryInfo, Profile, ReferenceTimestamp, SamplingInterval, ThreadHandle, }; @@ -1044,39 +1044,32 @@ where }; let text = file.section_by_name(".text"); - let text_env = file.section_by_name("text_env"); let eh_frame = file.section_by_name(".eh_frame"); let got = file.section_by_name(".got"); let eh_frame_hdr = file.section_by_name(".eh_frame_hdr"); - let unwind_data = match ( - eh_frame - .as_ref() - .and_then(|s| section_data(s, mmap.clone())), - eh_frame_hdr - .as_ref() - .and_then(|s| section_data(s, mmap.clone())), - ) { - (Some(eh_frame), Some(eh_frame_hdr)) => { - ModuleUnwindData::EhFrameHdrAndEhFrame(eh_frame_hdr, eh_frame) - } - (Some(eh_frame), None) => ModuleUnwindData::EhFrame(eh_frame), - (None, _) => ModuleUnwindData::None, - }; + let eh_frame_data = eh_frame + .as_ref() + .and_then(|s| section_data(s, mmap.clone())); + let eh_frame_hdr_data = eh_frame_hdr + .as_ref() + .and_then(|s| section_data(s, mmap.clone())); - let text_data = if let Some(text_segment) = file + let (text_segment, text_segment_svma) = if let Some(text_segment) = file .segments() .find(|segment| segment.name_bytes() == Ok(Some(b"__TEXT"))) { + let text_segment_svma = + Some(text_segment.address()..text_segment.address() + text_segment.size()); let (start, size) = text_segment.file_range(); - let address_range = base_avma + start..base_avma + start + size; - MmapRangeOrVec::new_mmap_range(mmap.clone(), start, size) - .map(|data| TextByteData::new(data, address_range)) - } else if let Some(text_section) = &text { + let text_segment = MmapRangeOrVec::new_mmap_range(mmap.clone(), start, size); + (text_segment, text_segment_svma) + } else { + (None, None) + }; + let text_section_data = if let Some(text_section) = &text { if let Some((start, size)) = text_section.file_range() { - let address_range = base_avma + start..base_avma + start + size; MmapRangeOrVec::new_mmap_range(mmap.clone(), start, size) - .map(|data| TextByteData::new(data, address_range)) } else { None } @@ -1088,24 +1081,28 @@ where section.address()..section.address() + section.size() } - let module_svma_info = ModuleSvmaInfo { + let module_section_info = ExplicitModuleSectionInfo { base_svma, - text: text.as_ref().map(svma_range), - text_env: text_env.as_ref().map(svma_range), - stubs: None, - stub_helper: None, - eh_frame: eh_frame.as_ref().map(svma_range), - eh_frame_hdr: eh_frame_hdr.as_ref().map(svma_range), - got: got.as_ref().map(svma_range), + text_svma: text.as_ref().map(svma_range), + text: text_section_data, + stubs_svma: None, + stub_helper_svma: None, + got_svma: got.as_ref().map(svma_range), + unwind_info: None, + eh_frame_svma: eh_frame.as_ref().map(svma_range), + eh_frame: eh_frame_data, + eh_frame_hdr_svma: eh_frame_hdr.as_ref().map(svma_range), + eh_frame_hdr: eh_frame_hdr_data, + debug_frame: None, + text_segment_svma, + text_segment, }; let module = Module::new( path.to_string(), avma_range.clone(), base_avma, - module_svma_info, - unwind_data, - text_data, + module_section_info, ); process.unwinder.add_module(module); diff --git a/samply/src/mac/proc_maps.rs b/samply/src/mac/proc_maps.rs index c8e15516..f99c5b57 100644 --- a/samply/src/mac/proc_maps.rs +++ b/samply/src/mac/proc_maps.rs @@ -10,7 +10,7 @@ use mach::thread_status::thread_state_flavor_t; use mach::thread_status::thread_state_t; use mach::traps::mach_task_self; use mach::vm::{mach_vm_deallocate, mach_vm_read, mach_vm_remap}; -use mach::vm_inherit::VM_INHERIT_SHARE; +use mach::vm_inherit::VM_INHERIT_NONE; use mach::vm_page_size::{mach_vm_trunc_page, vm_page_size}; use mach::vm_prot::{vm_prot_t, VM_PROT_NONE, VM_PROT_READ}; use mach::vm_types::{mach_vm_address_t, mach_vm_size_t}; @@ -63,13 +63,56 @@ pub struct DyldInfo { pub file: String, pub base_avma: u64, pub vmsize: u64, - pub svma_info: framehop::ModuleSvmaInfo, + pub module_info: ModuleInfo, pub debug_id: Option, pub code_id: Option, pub arch: Option<&'static str>, pub unwind_sections: UnwindSectionInfo, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ModuleInfo { + pub base_svma: u64, + pub text_svma: Option>, + pub stubs_svma: Option>, + pub stub_helper_svma: Option>, + pub got_svma: Option>, + pub eh_frame_svma: Option>, + pub eh_frame_hdr_svma: Option>, + pub text_segment_svma: Option>, +} + +impl ModuleInfo { + pub fn framehop_section_info(&self) -> framehop::ExplicitModuleSectionInfo { + let ModuleInfo { + base_svma, + text_svma, + stubs_svma, + stub_helper_svma, + got_svma, + eh_frame_svma, + eh_frame_hdr_svma, + text_segment_svma, + } = self.clone(); + framehop::ExplicitModuleSectionInfo { + base_svma, + text_svma, + text: None, + stubs_svma, + stub_helper_svma, + got_svma, + unwind_info: None, + eh_frame_svma, + eh_frame: None, + eh_frame_hdr_svma, + eh_frame_hdr: None, + debug_frame: None, + text_segment_svma, + text_segment: None, + } + } +} + /// These are SVMAs. #[derive(Debug, Clone, PartialEq, Eq)] pub struct UnwindSectionInfo { @@ -309,15 +352,15 @@ fn get_dyld_image_info( file: filename, base_avma, vmsize, - svma_info: framehop::ModuleSvmaInfo { + module_info: ModuleInfo { base_svma, - text: section_svma_range(b"__text"), - text_env: section_svma_range(b"text_env"), - stubs: section_svma_range(b"__stubs"), - stub_helper: section_svma_range(b"__stub_helper"), - eh_frame: section_svma_range(b"__eh_frame"), - eh_frame_hdr: section_svma_range(b"__eh_frame_hdr"), - got: section_svma_range(b"__got"), + text_svma: section_svma_range(b"__text"), + stubs_svma: section_svma_range(b"__stubs"), + stub_helper_svma: section_svma_range(b"__stub_helper"), + got_svma: section_svma_range(b"__got"), + eh_frame_svma: section_svma_range(b"__eh_frame"), + eh_frame_hdr_svma: section_svma_range(b"__eh_frame_hdr"), + text_segment_svma: Some(base_svma..base_svma + vmsize), }, debug_id: uuid.map(DebugId::from_uuid), code_id: uuid.map(CodeId::MachoUuid), @@ -334,6 +377,7 @@ fn get_dyld_image_info( // bindgen seemed to put all the members for this struct as a single opaque blob: // (bindgen /usr/include/mach/task_info.h --with-derive-default --whitelist-type task_dyld_info) // rather than debug the bindgen command, just define manually here +#[allow(non_camel_case_types)] #[repr(C)] #[derive(Default, Debug)] pub struct task_dyld_info { @@ -342,6 +386,7 @@ pub struct task_dyld_info { pub all_image_info_format: mach::vm_types::integer_t, } +#[allow(non_camel_case_types)] #[cfg(target_arch = "aarch64")] #[repr(C)] #[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)] @@ -617,6 +662,7 @@ impl ForeignMemory { } } +#[derive(Debug)] pub struct VmSubData { page_aligned_data: VmData, address_range: std::ops::Range, @@ -715,7 +761,7 @@ impl VmData { 0, &mut cur_protection as *mut i32, &mut max_protection as *mut i32, - VM_INHERIT_SHARE, + VM_INHERIT_NONE, ) } .into_result()?; @@ -748,7 +794,7 @@ impl VmData { pub unsafe fn get_type_ref(&self, address: u64) -> &T { assert!(address % mem::align_of::() as u64 == 0); let range = address..(address + mem::size_of::() as u64); - let slice = self.get_slice(range); + let slice = self.get_slice(range.clone()); assert!(slice.len() == mem::size_of::()); &*(slice.as_ptr() as *const T) } diff --git a/samply/src/mac/task_profiler.rs b/samply/src/mac/task_profiler.rs index f525a451..1965c495 100644 --- a/samply/src/mac/task_profiler.rs +++ b/samply/src/mac/task_profiler.rs @@ -1,7 +1,6 @@ use crossbeam_channel::Receiver; use framehop::{ - CacheNative, FrameAddress, MayAllocateDuringUnwind, Module, ModuleUnwindData, TextByteData, - Unwinder, UnwinderNative, + CacheNative, FrameAddress, MayAllocateDuringUnwind, Module, Unwinder, UnwinderNative, }; use fxprof_processed_profile::debugid::DebugId; use fxprof_processed_profile::{LibraryInfo, ProcessHandle, Profile, ThreadHandle, Timestamp}; @@ -41,6 +40,7 @@ use super::proc_maps::{DyldInfo, DyldInfoManager, Modification, StackwalkerRef, use super::sampler::TaskInit; use super::thread_profiler::{get_thread_id, get_thread_name, ThreadProfiler}; +#[derive(Debug)] pub enum UnwindSectionBytes { Remapped(VmSubData), Mmap(MmapSubData), @@ -59,6 +59,7 @@ impl Deref for UnwindSectionBytes { } } +#[derive(Debug)] pub struct MmapSubData { mmap: memmap2::Mmap, offset: usize, @@ -431,7 +432,8 @@ impl TaskProfiler { } fn add_lib_to_unwinder_and_ensure_debug_id(&mut self, lib: &mut DyldInfo) { - let base_svma = lib.svma_info.base_svma; + let mut module_section_info = lib.module_info.framehop_section_info(); + let base_svma = module_section_info.base_svma; let base_avma = lib.base_avma; let unwind_info_data = lib .unwind_sections @@ -445,24 +447,25 @@ impl TaskProfiler { .and_then(|(svma, size)| { VmSubData::map_from_task(self.task, svma - base_svma + base_avma, size).ok() }); - let text_data = lib.unwind_sections.text_segment.and_then(|(svma, size)| { + let text_segment = lib.unwind_sections.text_segment.and_then(|(svma, size)| { let avma = svma - base_svma + base_avma; VmSubData::map_from_task(self.task, avma, size) .ok() - .map(|data| { - TextByteData::new(UnwindSectionBytes::Remapped(data), avma..avma + size) - }) + .map(|data| (UnwindSectionBytes::Remapped(data), avma..avma + size)) }); if lib.debug_id.is_none() { - if let (Some(text_data), Some(text_section)) = - (text_data.as_ref(), lib.svma_info.text.clone()) + if let (Some((text_segment, text_segment_avma)), Some(text_section)) = + (text_segment.as_ref(), lib.module_info.text_svma.clone()) { let text_section_start_avma = text_section.start - base_svma + base_avma; let text_section_first_page_end_avma = text_section_start_avma.wrapping_add(4096); - let debug_id = if let Some(text_first_page) = - text_data.get_bytes(text_section_start_avma..text_section_first_page_end_avma) - { + let debug_id = if let Some(text_first_page) = text_section_start_avma + .checked_sub(text_segment_avma.start) + .zip(text_section_first_page_end_avma.checked_sub(text_segment_avma.start)) + .and_then(|(rel_start, rel_end)| { + text_segment.get(rel_start as usize..rel_end as usize) + }) { // Generate a debug ID from the __text section. DebugId::from_text_first_page(text_first_page, true) } else { @@ -471,33 +474,24 @@ impl TaskProfiler { lib.debug_id = Some(debug_id); } } - - let unwind_data = match (unwind_info_data, eh_frame_data) { - (Some(unwind_info), eh_frame) => ModuleUnwindData::CompactUnwindInfoAndEhFrame( - UnwindSectionBytes::Remapped(unwind_info), - eh_frame.map(UnwindSectionBytes::Remapped), - ), - (None, Some(eh_frame)) => { - ModuleUnwindData::EhFrame(UnwindSectionBytes::Remapped(eh_frame)) - } - (None, None) => { - // Have no unwind information. - // Let's try to open the file and use debug_frame. - if let Some(debug_frame) = get_debug_frame(&lib.file) { - ModuleUnwindData::DebugFrame(debug_frame) - } else { - ModuleUnwindData::None - } - } - }; + let (text_segment, text_segment_svma_range) = text_segment.unzip(); + + module_section_info.text_segment = text_segment; + module_section_info.text_segment_svma = text_segment_svma_range; + module_section_info.text = None; + module_section_info.unwind_info = unwind_info_data.map(UnwindSectionBytes::Remapped); + module_section_info.eh_frame = eh_frame_data.map(UnwindSectionBytes::Remapped); + if module_section_info.unwind_info.is_none() && module_section_info.eh_frame.is_none() { + // We have no unwind information. + // Let's try to open the file and use debug_frame. + module_section_info.debug_frame = get_debug_frame(&lib.file); + } let module = Module::new( lib.file.clone(), lib.base_avma..(lib.base_avma + lib.vmsize), lib.base_avma, - lib.svma_info.clone(), - unwind_data, - text_data, + module_section_info, ); self.unwinder.add_module(module); }