Skip to content

Add support for arm (armhf) #618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions samply/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ readme = "README.md"
[dependencies]

fxprof-processed-profile = { version = "0.8", path = "../fxprof-processed-profile" }
# framehop = { path = "../../framehop" }
framehop = "0.14"
# linux-perf-data = { path = "../../linux-perf-data" }
linux-perf-data = "0.11"
framehop = { path = "../../framehop" }
#framehop = "0.14"
linux-perf-data = { path = "../../linux-perf-data" }
#linux-perf-data = "0.11"

tokio = { version = "1.39", features = ["rt", "rt-multi-thread", "macros"] }
tokio-util = "0.7.11"
Expand Down
13 changes: 12 additions & 1 deletion samply/src/import/perf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use linux_perf_data::{linux_perf_event_reader, DsoInfo, DsoKey, PerfFileReader,
use linux_perf_event_reader::EventRecord;

use crate::linux_shared::{
ConvertRegs, ConvertRegsAarch64, ConvertRegsX86_64, Converter, EventInterpretation, KnownEvent,
ConvertRegs, ConvertRegsAarch64, ConvertRegsX86_64, ConvertRegsArmhf, Converter, EventInterpretation, KnownEvent,
MmapRangeOrVec,
};
use crate::shared::prop_types::ProfileCreationProps;
Expand Down Expand Up @@ -47,6 +47,17 @@ pub fn convert<C: Read + Seek>(
profile_creation_props,
)
}
Some("arm") => {
let cache = framehop::armhf::CacheArmhf::new();
convert_impl::<framehop::armhf::UnwinderArmhf<MmapRangeOrVec>, ConvertRegsArmhf, _>(
perf_file,
file_mod_time,
binary_lookup_dirs,
aux_file_lookup_dirs,
cache,
profile_creation_props,
)
}
_ => {
if arch != Some("x86_64") {
eprintln!(
Expand Down
3 changes: 3 additions & 0 deletions samply/src/linux/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ pub type ConvertRegsNative = crate::linux_shared::ConvertRegsX86_64;
#[cfg(target_arch = "aarch64")]
pub type ConvertRegsNative = crate::linux_shared::ConvertRegsAarch64;

#[cfg(target_arch = "arm")]
pub type ConvertRegsNative = crate::linux_shared::ConvertRegsArmhf;

pub fn run(
recording_mode: RecordingMode,
recording_props: RecordingProps,
Expand Down
26 changes: 25 additions & 1 deletion samply/src/linux_shared/convert_regs.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use framehop::aarch64::UnwindRegsAarch64;
use framehop::x86_64::UnwindRegsX86_64;
use framehop::armhf::UnwindRegsArmhf;
use linux_perf_data::linux_perf_event_reader;
use linux_perf_event_reader::constants::{
PERF_REG_ARM64_LR, PERF_REG_ARM64_PC, PERF_REG_ARM64_SP, PERF_REG_ARM64_X29, PERF_REG_X86_BP,
PERF_REG_X86_IP, PERF_REG_X86_SP,
PERF_REG_X86_IP, PERF_REG_X86_SP,PERF_REG_ARM_PC, PERF_REG_ARM_LR, PERF_REG_ARM_SP, PERF_REG_ARM_R7
};
use linux_perf_event_reader::Regs;

Expand Down Expand Up @@ -50,3 +51,26 @@ impl ConvertRegs for ConvertRegsAarch64 {
| (1 << PERF_REG_ARM64_X29)
}
}

pub struct ConvertRegsArmhf;
impl ConvertRegs for ConvertRegsArmhf {
type UnwindRegs = UnwindRegsArmhf;
fn convert_regs(regs: &Regs) -> (u64, u64, UnwindRegsArmhf) {
// println!("{:?}", regs);
let ip = regs.get(PERF_REG_ARM_PC).unwrap();
let lr = regs.get(PERF_REG_ARM_LR).unwrap();
let sp = regs.get(PERF_REG_ARM_SP).unwrap();
// Note: This is x7 for thumb, x11 for arm mode.
let fp = regs.get(PERF_REG_ARM_R7).unwrap();
// println!("Convert: lr, sp, fp: {:x} {:x} {:x}", lr, sp, fp);
let regs = UnwindRegsArmhf::new(lr, sp, fp);
(ip, sp, regs)
}

fn regs_mask() -> u64 {
(1 << PERF_REG_ARM_PC)
| (1 << PERF_REG_ARM_LR)
| (1 << PERF_REG_ARM_SP)
| (1 << PERF_REG_ARM_R7)
}
}
86 changes: 78 additions & 8 deletions samply/src/linux_shared/converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,71 @@ use crate::shared::unresolved_samples::{
};
use crate::shared::utils::open_file_with_fallback;

use byteorder::NativeEndian;
use byteorder::ByteOrder;
use std::mem;
use crate::linux_shared::converter::linux_perf_event_reader::RawData;

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct RawDataU32<'a> {
swapped_endian: bool,
raw_data: RawData<'a>,
}

pub fn is_swapped_endian<T: ByteOrder>() -> bool {
let mut buf = [0; 2];
T::write_u16(&mut buf, 0x1234);
u16::from_ne_bytes(buf) != 0x1234
}

impl<'a> RawDataU32<'a> {
#[inline]
pub fn from_raw_data<T: ByteOrder>(raw_data: RawData<'a>) -> Self {
RawDataU32 {
raw_data,
swapped_endian: is_swapped_endian::<T>(),
}
}

pub fn is_empty(&self) -> bool {
self.raw_data.is_empty()
}

pub fn len(&self) -> usize {
self.raw_data.len() / mem::size_of::<u32>()
}

pub fn get(&self, index: usize) -> Option<u32> {
let offset = index * mem::size_of::<u32>();
let mut data = self.raw_data;
data.skip(offset).ok()?;
let value = data.read_u32::<NativeEndian>().ok()?;
Some(if self.swapped_endian {
value.swap_bytes()
} else {
value
})
}
}

impl std::fmt::Debug for RawDataU32<'_> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let mut list = fmt.debug_list();
let mut data = self.raw_data;
while let Ok(value) = data.read_u64::<NativeEndian>() {
let value = if self.swapped_endian {
value.swap_bytes()
} else {
value
};
list.entry(&value);
}

list.finish()
}
}


pub struct Converter<U>
where
U: Unwinder<Module = Module<MmapRangeOrVec>> + Default,
Expand Down Expand Up @@ -642,9 +707,9 @@ where

let stack_frame =
match (is_first_frame, call_chain_return_addresses_are_preadjusted) {
(true, _) => StackFrame::InstructionPointer(address, mode),
(false, false) => StackFrame::ReturnAddress(address, mode),
(false, true) => StackFrame::AdjustedReturnAddress(address, mode),
(true, _) => StackFrame::InstructionPointer(address & 0x00000000_fffffffeu64, mode),
(false, false) => StackFrame::ReturnAddress(address & 0x00000000_fffffffeu64, mode),
(false, true) => StackFrame::AdjustedReturnAddress(address & 0x00000000_fffffffeu64, mode),
};
stack.push(stack_frame);

Expand All @@ -654,13 +719,16 @@ where

// Append the user stack with the help of DWARF unwinding.
if let (Some(regs), Some((user_stack, _))) = (&e.user_regs, e.user_stack) {
let ustack_bytes = RawDataU64::from_raw_data::<LittleEndian>(user_stack);
let ustack_bytes = RawDataU32::from_raw_data::<LittleEndian>(user_stack);
let (pc, sp, regs) = C::convert_regs(regs);
// println!("pc: {:x}, sp: {:x}", pc, sp);
let mut read_stack = |addr: u64| {
// ustack_bytes has the stack bytes starting from the current stack pointer.
let offset = addr.checked_sub(sp).ok_or(())?;
let index = usize::try_from(offset / 8).map_err(|_| ())?;
ustack_bytes.get(index).ok_or(())
let index = usize::try_from(offset / 4).map_err(|_| ())?;
let result = ustack_bytes.get(index).ok_or(())?;
// println!("Stack: {:x} = {:x}", addr, result);
Ok(result as u64)
};

// Unwind.
Expand All @@ -676,10 +744,12 @@ where
};
let stack_frame = match frame {
FrameAddress::InstructionPointer(addr) => {
StackFrame::InstructionPointer(addr, StackMode::User)
// println!("Stack frame: {:x}", addr & 0x00000000_fffffffeu64);
StackFrame::InstructionPointer(addr & 0x00000000_fffffffeu64, StackMode::User)
}
FrameAddress::ReturnAddress(addr) => {
StackFrame::ReturnAddress(addr.into(), StackMode::User)
// println!("(+)Stack frame: {:x}", addr.get() & 0x00000000_fffffffeu64);
StackFrame::ReturnAddress(addr.get() & 0x00000000_fffffffeu64, StackMode::User)
}
};
stack.push(stack_frame);
Expand Down
2 changes: 1 addition & 1 deletion samply/src/linux_shared/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod thread;
#[allow(unused)]
pub mod vdso;

pub use convert_regs::{ConvertRegs, ConvertRegsAarch64, ConvertRegsX86_64};
pub use convert_regs::{ConvertRegs, ConvertRegsAarch64, ConvertRegsX86_64, ConvertRegsArmhf};
pub use converter::Converter;
#[allow(unused)]
pub use event_interpretation::{EventInterpretation, KnownEvent, OffCpuIndicator};
Expand Down