Skip to content

Commit

Permalink
introduce custom unwinding on macOS+aarch64
Browse files Browse the repository at this point in the history
Signed-off-by: mornyx <mornyx.z@gmail.com>
  • Loading branch information
mornyx committed Feb 25, 2022
1 parent 50d9b8d commit a68772c
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 7 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ prost = { version = "0.9", optional = true }
prost-derive = { version = "0.9", optional = true }
criterion = {version = "0.3", optional = true}

unwind = { git = "https://github.com/mornyx/unwind.git", branch = "master" }

[dependencies.symbolic-demangle]
version = "8.0"
default-features = false
Expand Down
59 changes: 54 additions & 5 deletions src/frames.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::hash::{Hash, Hasher};
use std::os::raw::c_void;
use std::path::PathBuf;

use backtrace::Frame;
use smallvec::SmallVec;
use symbolic_demangle::demangle;

Expand Down Expand Up @@ -150,6 +149,48 @@ impl Hash for Symbol {
}
}

#[derive(Debug, Clone)]
pub struct UnwindStackFrame {
pub pc: u64,
pub fp: u64,
}

#[derive(Debug, Clone)]
pub enum Frame {
Backtrace(backtrace::Frame),
Unwind(UnwindStackFrame),
}

impl Frame {
pub fn ip(&self) -> *mut c_void {
match self {
Frame::Backtrace(frame) => frame.ip(),
Frame::Unwind(frame) => unsafe { std::mem::transmute(frame.pc) },
}
}

pub fn sp(&self) -> *mut c_void {
match self {
Frame::Backtrace(frame) => frame.sp(),
Frame::Unwind(_) => std::ptr::null_mut(),
}
}

pub fn symbol_address(&self) -> *mut c_void {
match self {
Frame::Backtrace(frame) => frame.symbol_address(),
Frame::Unwind(frame) => unsafe { std::mem::transmute(frame.pc) },
}
}

pub fn module_base_address(&self) -> Option<*mut c_void> {
match self {
Frame::Backtrace(frame) => frame.module_base_address(),
Frame::Unwind(_) => None,
}
}
}

/// A representation of a backtrace. `thread_name` and `thread_id` was got from `pthread_getname_np`
/// and `pthread_self`. frames is a vector of symbols.
#[derive(Clone, PartialEq, Hash)]
Expand Down Expand Up @@ -179,10 +220,18 @@ impl From<UnresolvedFrames> for Frames {
while let Some(frame) = frame_iter.next() {
let mut symbols = Vec::new();

backtrace::resolve_frame(frame, |symbol| {
let symbol = Symbol::from(symbol);
symbols.push(symbol);
});
match frame {
Frame::Backtrace(frame) => backtrace::resolve_frame(frame, |symbol| {
let symbol = Symbol::from(symbol);
symbols.push(symbol);
}),
Frame::Unwind(frame) => unsafe {
backtrace::resolve(std::mem::transmute(frame.pc), |symbol| {
let symbol = Symbol::from(symbol);
symbols.push(symbol);
})
},
}

if symbols
.iter()
Expand Down
24 changes: 22 additions & 2 deletions src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use std::convert::TryInto;
use std::os::raw::c_int;

use backtrace::Frame;
use nix::sys::signal;
use parking_lot::RwLock;
use smallvec::SmallVec;
Expand All @@ -14,6 +13,7 @@ use findshlibs::{Segment, SharedLibrary, TargetSharedLibrary};
use crate::collector::Collector;
use crate::error::{Error, Result};
use crate::frames::UnresolvedFrames;
use crate::frames::{Frame, UnwindStackFrame};
use crate::report::ReportBuilder;
use crate::timer::Timer;
use crate::{MAX_DEPTH, MAX_THREAD_NAME};
Expand Down Expand Up @@ -247,10 +247,11 @@ extern "C" fn perf_signal_handler(
let mut bt: SmallVec<[Frame; MAX_DEPTH]> = SmallVec::with_capacity(MAX_DEPTH);
let mut index = 0;

#[cfg(any(not(target_arch = "aarch64"), not(target_os = "macos")))]
unsafe {
backtrace::trace_unsynchronized(|frame| {
if index < MAX_DEPTH {
bt.push(frame.clone());
bt.push(Frame::Backtrace(frame.clone()));
index += 1;
true
} else {
Expand All @@ -259,6 +260,25 @@ extern "C" fn perf_signal_handler(
});
}

#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
{
if let Some(context) = unwind::UnwindContext::from_ucontext(ucontext) {
let mut cursor = unwind::UnwindCursor::new(context);
let mut context = &context;
while index < MAX_DEPTH {
bt.push(Frame::Unwind(UnwindStackFrame {
fp: context.fp,
pc: context.pc,
}));
index += 1;
match cursor.step() {
Some(ctx) => context = ctx,
None => break,
}
}
}
}

let current_thread = unsafe { libc::pthread_self() };
let mut name = [0; MAX_THREAD_NAME];
let name_ptr = &mut name as *mut [libc::c_char] as *mut libc::c_char;
Expand Down

0 comments on commit a68772c

Please sign in to comment.