Skip to content
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

Stabilize ARM and AArch64 support on both Linux and Android, add support for x86-64 on Android #81

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/linux/maps_reader.rs
Expand Up @@ -108,7 +108,7 @@ impl MappingInfo {
{
module.system_mapping_info.end_address = end_address;
module.size = end_address - module.start_address;
module.permissions |= mm.perms & MMPermissions::EXECUTE;
module.permissions |= mm.perms;
continue;
}
} else {
Expand Down Expand Up @@ -433,7 +433,10 @@ ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsysca
end_address: 0x559748406000,
},
offset: 0,
permissions: MMPermissions::READ | MMPermissions::EXECUTE | MMPermissions::PRIVATE,
permissions: MMPermissions::READ
| MMPermissions::WRITE
| MMPermissions::EXECUTE
| MMPermissions::PRIVATE,
name: Some("/usr/bin/cat".into()),
};

Expand Down Expand Up @@ -540,7 +543,10 @@ ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsysca
end_address: 0x7efd96d8c000, // ..but this is not visible here
},
offset: 0,
permissions: MMPermissions::READ | MMPermissions::EXECUTE | MMPermissions::PRIVATE,
permissions: MMPermissions::READ
| MMPermissions::WRITE
| MMPermissions::EXECUTE
| MMPermissions::PRIVATE,
name: Some("/lib64/libc-2.32.so".into()),
};

Expand Down
4 changes: 3 additions & 1 deletion src/linux/ptrace_dumper.rs
@@ -1,5 +1,7 @@
#[cfg(target_os = "android")]
use crate::linux::android::late_process_mappings;
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use crate::thread_info;
use crate::{
linux::{
auxv_reader::{AuxvType, ProcfsAuxvIter},
Expand Down Expand Up @@ -147,7 +149,7 @@ impl PtraceDumper {
// We thus test the stack pointer and exclude any threads that are part of
// the seccomp sandbox's trusted code.
let skip_thread;
let regs = ptrace::getregs(pid);
let regs = thread_info::ThreadInfo::getregs(pid.into());
if let Ok(regs) = regs {
#[cfg(target_arch = "x86_64")]
{
Expand Down
18 changes: 7 additions & 11 deletions src/linux/thread_info.rs
Expand Up @@ -34,6 +34,7 @@ enum NT_Elf {
//NT_PRPSINFO = 3,
//NT_TASKSTRUCT = 4,
//NT_AUXV = 6,
NT_ARM_VFP = 0x400, // ARM VFP/NEON registers
}

#[inline]
Expand Down Expand Up @@ -96,14 +97,14 @@ trait CommonThreadInfo {
/// and therefore use the data field to return values. This function handles these
/// requests.
fn ptrace_get_data<T>(
request: ptrace::Request,
request: ptrace::RequestType,
flag: Option<NT_Elf>,
pid: nix::unistd::Pid,
) -> Result<T> {
let mut data = std::mem::MaybeUninit::uninit();
let res = unsafe {
libc::ptrace(
request as ptrace::RequestType,
request,
libc::pid_t::from(pid),
flag.unwrap_or(NT_Elf::NT_NONE),
data.as_mut_ptr(),
Expand All @@ -119,7 +120,7 @@ trait CommonThreadInfo {
/// and therefore use the data field to return values. This function handles these
/// requests.
fn ptrace_get_data_via_io<T>(
request: ptrace::Request,
request: ptrace::RequestType,
flag: Option<NT_Elf>,
pid: nix::unistd::Pid,
) -> Result<T> {
Expand All @@ -130,7 +131,7 @@ trait CommonThreadInfo {
};
let res = unsafe {
libc::ptrace(
request as ptrace::RequestType,
request,
libc::pid_t::from(pid),
flag.unwrap_or(NT_Elf::NT_NONE),
&io as *const _,
Expand All @@ -142,19 +143,14 @@ trait CommonThreadInfo {

/// COPY FROM CRATE nix BECAUSE ITS NOT PUBLIC
fn ptrace_peek(
request: ptrace::Request,
request: ptrace::RequestType,
pid: unistd::Pid,
addr: ptrace::AddressType,
data: *mut libc::c_void,
) -> nix::Result<libc::c_long> {
let ret = unsafe {
Errno::clear();
libc::ptrace(
request as ptrace::RequestType,
libc::pid_t::from(pid),
addr,
data,
)
libc::ptrace(request, libc::pid_t::from(pid), addr, data)
};
match Errno::result(ret) {
Ok(..) | Err(Errno::UnknownErrno) => Ok(ret),
Expand Down
84 changes: 34 additions & 50 deletions src/linux/thread_info/aarch64.rs
@@ -1,9 +1,8 @@
use super::{CommonThreadInfo, Pid};
use super::{CommonThreadInfo, NT_Elf, Pid};
use crate::{
errors::ThreadInfoError,
minidump_cpu::{RawContextCPU, FP_REG_COUNT, GP_REG_COUNT},
};
#[cfg(not(target_os = "android"))]
use nix::sys::ptrace;

/// https://github.com/rust-lang/libc/pull/2719
Expand Down Expand Up @@ -34,55 +33,40 @@ impl ThreadInfoAarch64 {
self.regs.pc as usize
}

// nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves
fn getfpregs(pid: Pid) -> Result<user_fpsimd_struct> {
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
// TODO: nix restricts PTRACE_GETFPREGS to arm android for some reason
let mut data = std::mem::MaybeUninit::<user_fpsimd_struct>::uninit();
let res = unsafe {
libc::ptrace(
14,
libc::pid_t::from(pid),
super::NT_Elf::NT_NONE,
data.as_mut_ptr(),
)
};
nix::errno::Errno::result(res)?;
Ok(unsafe { data.assume_init() })
} else {
Self::ptrace_get_data_via_io::<user_fpsimd_struct>(
ptrace::Request::PTRACE_GETREGSET,
Some(super::NT_Elf::NT_PRFPREGSET),
nix::unistd::Pid::from_raw(pid),
)
}
}
// nix currently doesn't support PTRACE_GETREGSET, so we have to do it ourselves
fn getregset(pid: Pid) -> Result<libc::user_regs_struct> {
Self::ptrace_get_data_via_io(
0x4204 as ptrace::RequestType, // PTRACE_GETREGSET
Some(NT_Elf::NT_PRSTATUS),
nix::unistd::Pid::from_raw(pid),
)
}

fn getregs(pid: Pid) -> Result<libc::user_regs_struct> {
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
// TODO: nix restricts PTRACE_GETREGS to arm android for some reason
let mut data = std::mem::MaybeUninit::<libc::user_regs_struct>::uninit();
let res = unsafe {
libc::ptrace(
12,
libc::pid_t::from(pid),
super::NT_Elf::NT_NONE,
data.as_mut_ptr(),
)
};
nix::errno::Errno::result(res)?;
Ok(unsafe { data.assume_init() })
} else {
Self::ptrace_get_data_via_io::<libc::user_regs_struct>(
ptrace::Request::PTRACE_GETREGSET,
Some(super::NT_Elf::NT_PRSTATUS),
nix::unistd::Pid::from_raw(pid),
)
}
}
// TODO: nix restricts PTRACE_GETREGS to arm android for some reason
Self::ptrace_get_data(
12 as ptrace::RequestType, // PTRACE_GETREGS
None,
nix::unistd::Pid::from_raw(pid),
)
}

// nix currently doesn't support PTRACE_GETREGSET, so we have to do it ourselves
fn getfpregset(pid: Pid) -> Result<user_fpsimd_struct> {
Self::ptrace_get_data_via_io(
0x4204 as ptrace::RequestType, // PTRACE_GETREGSET
Some(NT_Elf::NT_PRFPREGSET),
nix::unistd::Pid::from_raw(pid),
)
}

// nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves
fn getfpregs(pid: Pid) -> Result<user_fpsimd_struct> {
Self::ptrace_get_data(
14 as ptrace::RequestType, // PTRACE_GETFPREGS
None,
nix::unistd::Pid::from_raw(pid),
)
}

pub fn fill_cpu_context(&self, out: &mut RawContextCPU) {
Expand All @@ -104,8 +88,8 @@ impl ThreadInfoAarch64 {

pub fn create_impl(_pid: Pid, tid: Pid) -> Result<Self> {
let (ppid, tgid) = Self::get_ppid_and_tgid(tid)?;
let regs = Self::getregs(tid)?;
let fpregs = Self::getfpregs(tid)?;
let regs = Self::getregset(tid).or_else(|_| Self::getregs(tid))?;
let fpregs = Self::getfpregset(tid).or_else(|_| Self::getfpregs(tid))?;

let stack_pointer = regs.sp as usize;

Expand Down
68 changes: 21 additions & 47 deletions src/linux/thread_info/arm.rs
@@ -1,43 +1,21 @@
use super::{CommonThreadInfo, Pid};
use super::{CommonThreadInfo, NT_Elf, Pid};
use crate::{errors::ThreadInfoError, minidump_cpu::RawContextCPU};
use nix::sys::ptrace;

type Result<T> = std::result::Result<T, ThreadInfoError>;
// These are not (yet) part of the libc-crate
// #[repr(C)]
// #[derive(Debug, Eq, Hash, PartialEq, Copy, Clone, Default)]
// pub struct fp_reg {
// // TODO: No bitfields at the moment, just the next best integer-type
// sign1: u8,
// unused: u16,
// sign2: u8,
// exponent: u16,
// j: u8,
// mantissa1: u32,
// mantissa2: u32,
// // unsigned int sign1:1;
// // unsigned int unused:15;
// // unsigned int sign2:1;
// // unsigned int exponent:14;
// // unsigned int j:1;
// // unsigned int mantissa1:31;
// // unsigned int mantissa0:32;
// }

// Not defined by libc because this works only for cores support VFP
#[allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, Eq, Hash, PartialEq, Copy, Clone, Default)]
pub struct user_fpregs {
// fpregs: [fp_reg; 8],
fpregs: [u32; 8 * 3], // Fields not used, so shortening the struct to 3 x u32
fpsr: u32,
fpcr: u32,
ftype: [u8; 8],
init_flag: u32,
pub struct user_fpregs_struct {
pub fpregs: [u64; 32],
pub fpscr: u32,
}

#[repr(C)]
#[derive(Debug, Eq, Hash, PartialEq, Copy, Clone, Default)]
pub struct user_regs {
pub struct user_regs_struct {
uregs: [u32; 18],
}

Expand All @@ -46,26 +24,26 @@ pub struct ThreadInfoArm {
pub stack_pointer: usize,
pub tgid: Pid, // thread group id
pub ppid: Pid, // parent process
pub regs: user_regs,
pub fpregs: user_fpregs,
pub regs: user_regs_struct,
pub fpregs: user_fpregs_struct,
}

impl CommonThreadInfo for ThreadInfoArm {}

impl ThreadInfoArm {
// nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves
fn getfpregs(pid: Pid) -> Result<user_fpregs> {
Self::ptrace_get_data::<user_fpregs>(
ptrace::Request::PTRACE_GETFPREGS,
None,
fn getfpregs(pid: Pid) -> Result<user_fpregs_struct> {
Self::ptrace_get_data_via_io(
0x4204 as ptrace::RequestType, // PTRACE_GETREGSET
Some(NT_Elf::NT_ARM_VFP),
nix::unistd::Pid::from_raw(pid),
)
}

// nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves
fn getregs(pid: Pid) -> Result<user_regs> {
Self::ptrace_get_data::<user_regs>(
ptrace::Request::PTRACE_GETFPREGS,
// nix currently doesn't support PTRACE_GETREGS, so we have to do it ourselves
fn getregs(pid: Pid) -> Result<user_regs_struct> {
Self::ptrace_get_data::<user_regs_struct>(
ptrace::Request::PTRACE_GETREGS as ptrace::RequestType,
None,
nix::unistd::Pid::from_raw(pid),
)
Expand All @@ -80,19 +58,15 @@ impl ThreadInfoArm {
crate::minidump_format::format::ContextFlagsArm::CONTEXT_ARM_FULL.bits();

out.iregs.copy_from_slice(&self.regs.uregs[..16]);
// No CPSR register in ThreadInfo(it's not accessible via ptrace)
out.cpsr = 0;

#[cfg(not(target_os = "android"))]
{
out.float_save.fpscr = self.fpregs.fpsr as u64 | ((self.fpregs.fpcr as u64) << 32);
}
out.cpsr = self.regs.uregs[16];
out.float_save.fpscr = self.fpregs.fpscr as u64;
out.float_save.regs = self.fpregs.fpregs;
}

pub fn create_impl(_pid: Pid, tid: Pid) -> Result<Self> {
let (ppid, tgid) = Self::get_ppid_and_tgid(tid)?;
let regs = Self::getregs(tid)?;
let fpregs = Self::getfpregs(tid)?;
let fpregs = Self::getfpregs(tid).unwrap_or(Default::default());

let stack_pointer = regs.uregs[13] as usize;

Expand Down