-
Notifications
You must be signed in to change notification settings - Fork 24
WIP android64 support #12
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,114 @@ | ||
| /// A u128 that matches the layout of uint128_t for C FFI purposes | ||
| /// **BUT NOT THE ABI**. This is safe for pass-by-ref but not pass-by-value. | ||
| /// | ||
| /// Rust underaligns u128 compared to C's ABI due to a long-standing llvm bug. | ||
| /// Unfortuantely library code *can't* perfectly work around this, because | ||
| /// primitives have magic ABIs. | ||
| /// | ||
| /// Although repr(transparent) *exists* to preserve the magic ABI of primitives, | ||
| /// you can't combine this with other reprs (which makes a kind of sense), | ||
| /// and we need to apply repr(align(16)). | ||
| /// | ||
| /// The upshot of this is that this type (or a struct containing it) can be | ||
| /// passed *by-reference* to C, but if you try to pass it *by-value* then | ||
| /// the ABI might not match and this value may not be passed to the function | ||
| /// right. | ||
| /// | ||
| /// This is good enough for our purposes, because we largely just want this | ||
| /// for APIs like linux's getcontext which does in fact work by-reference. | ||
| /// | ||
| /// See "i128 / u128 are not compatible with C's definition." | ||
| /// https://github.com/rust-lang/rust/issues/54341 | ||
| #[repr(C, align(16))] | ||
| #[derive(Debug, Copy, Clone, Default)] | ||
| #[allow(non_camel_case_types)] | ||
| pub struct layout_only_ffi_u128(u128); | ||
|
|
||
| impl layout_only_ffi_u128 { | ||
| pub fn to_ne_bytes(self) -> [u8; 16] { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this function used? |
||
| self.0.to_ne_bytes() | ||
| } | ||
| } | ||
|
|
||
| pub const MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT: usize = 32; | ||
| pub const MD_CONTEXT_ARM64_GPR_COUNT: usize = 33; | ||
|
|
||
|
|
||
|
|
||
| /* Indices into iregs for registers with a dedicated or conventional | ||
| * purpose. | ||
| */ | ||
| #[allow(non_camel_case_types)] | ||
| pub enum MDARM64RegisterNumbers { | ||
| MD_CONTEXT_ARM64_REG_FP = 29, | ||
| MD_CONTEXT_ARM64_REG_LR = 30, | ||
| MD_CONTEXT_ARM64_REG_SP = 31, | ||
| MD_CONTEXT_ARM64_REG_PC = 32, | ||
| } | ||
|
|
||
| /* Windows only? | ||
| #[repr(C)] | ||
| #[derive(Default)] | ||
| pub struct MDRawContextARM64 { | ||
| pub context_flags: u32, | ||
| pub cpsr: u32, | ||
| pub iregs: [u64; 32], | ||
| pub pc: u64, | ||
| pub float_save: libc_user_fpsimd_struct, | ||
| pub bcr: [u32; 8], | ||
| pub bvr: [u64; 8], | ||
| pub wcr: [u32; 2], | ||
| pub wvr: [u64; 2], | ||
| } | ||
| */ | ||
|
|
||
| #[repr(C)] | ||
| #[derive(Default)] | ||
| pub struct MDRawContextARM64Old { | ||
| pub context_flags: u64, | ||
| pub iregs: [u64; 32], | ||
| pub pc: u64, | ||
| pub cpsr: u32, | ||
| pub float_save: FloatingSaveAreaARM64Old, | ||
| } | ||
|
|
||
| /// aarch64 floating point state | ||
| #[repr(C)] | ||
| #[derive(Debug, Copy, Clone, Default)] | ||
| #[allow(non_camel_case_types)] | ||
| pub struct libc_user_fpsimd_struct { | ||
| pub regs: [layout_only_ffi_u128; 32usize], | ||
| pub fpsr: u32, | ||
| pub fpcr: u32, | ||
| } | ||
|
|
||
| /// aarch64 floating point state (old) | ||
| #[repr(C)] | ||
| #[derive(Debug, Clone, Copy, Default)] | ||
| pub struct FloatingSaveAreaARM64Old { | ||
| pub fpsr: u32, | ||
| pub fpcr: u32, | ||
| pub regs: [layout_only_ffi_u128; 32usize], | ||
| } | ||
|
|
||
| pub const MD_CONTEXT_ARM64: u32 = 0x400000; | ||
| pub const MD_CONTEXT_ARM64_OLD: u64 = 0x80000000; | ||
|
|
||
| pub const MD_CONTEXT_ARM64_ALL_OLD: u64 = MD_CONTEXT_ARM64_OLD | 0x2 | 0x4; | ||
|
|
||
| /* | ||
| /* For (MDRawContextARM64_Old).context_flags. These values indicate the type of | ||
| * context stored in the structure. MD_CONTEXT_ARM64_OLD is Breakpad-defined. | ||
| * This value was chosen to avoid likely conflicts with MD_CONTEXT_* | ||
| * for other CPUs. */ | ||
| #define MD_CONTEXT_ARM64_OLD 0x80000000 | ||
| #define MD_CONTEXT_ARM64_INTEGER_OLD (MD_CONTEXT_ARM64_OLD | 0x00000002) | ||
| #define MD_CONTEXT_ARM64_FLOATING_POINT_OLD (MD_CONTEXT_ARM64_OLD | 0x00000004) | ||
|
|
||
| #define MD_CONTEXT_ARM64_FULL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \ | ||
| MD_CONTEXT_ARM64_FLOATING_POINT_OLD) | ||
|
|
||
| #define MD_CONTEXT_ARM64_ALL_OLD (MD_CONTEXT_ARM64_INTEGER_OLD | \ | ||
| MD_CONTEXT_ARM64_FLOATING_POINT_OLD) | ||
|
|
||
| */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| use super::Pid; | ||
| use super::{Pid, CommonThreadInfo}; | ||
| use crate::errors::ThreadInfoError; | ||
| use crate::minidump_cpu::imp::{MDARM64RegisterNumbers, MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT}; | ||
| use crate::minidump_cpu::imp::{MDARM64RegisterNumbers, MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT, libc_user_fpsimd_struct, MD_CONTEXT_ARM64_OLD, MD_CONTEXT_ARM64_ALL_OLD}; | ||
| use crate::minidump_cpu::RawContextCPU; | ||
| use libc; | ||
| use nix::sys::ptrace; | ||
|
|
||
| type Result<T> = std::result::Result<T, ThreadInfoError>; | ||
|
|
||
|
|
@@ -12,37 +14,60 @@ pub struct ThreadInfoAarch64 { | |
| pub tgid: Pid, // thread group id | ||
| pub ppid: Pid, // parent process | ||
| pub regs: libc::user_regs_struct, | ||
| pub fpregs: libc::user_fpsimd_struct, | ||
| pub fpregs: libc_user_fpsimd_struct, | ||
| } | ||
|
|
||
| impl CommonThreadInfo for ThreadInfoAarch64 {} | ||
|
|
||
| impl ThreadInfoAarch64 { | ||
| // nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves | ||
| fn getfpregs(pid: Pid) -> Result<libc_user_fpsimd_struct> { | ||
| Self::ptrace_get_data::<libc_user_fpsimd_struct>( | ||
| ptrace::Request::PTRACE_GETFPREGS, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've almost got everything reasonable and compiling, but the last remaining blocker is this code here, where we get each thread's registers with ptrace-based register lookup. For whatever reason it appears that PTRACE_GETREGS and PTRACE_GETFPREGS just don't exist on aarch64 (android?). The docs note that the APIs don't exist on all platforms but it is just Weird that this was the platform to do it? Not fully clear on what's up with the breakpad version, ifdef hell...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible I want PTRACE_GETREGSET, but the nix ptrace stuff also doesn't have that for android. Not clear if that's a bug tho.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fear, I have not much to add here. I'm most certainly not an Android expert :-/ |
||
| None, | ||
| 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<libc::user_regs_struct> { | ||
| Self::ptrace_get_data::<libc::user_regs_struct>( | ||
| ptrace::Request::PTRACE_GETFPREGS, | ||
| None, | ||
| nix::unistd::Pid::from_raw(pid), | ||
| ) | ||
| } | ||
|
|
||
| pub fn get_instruction_pointer(&self) -> libc::c_ulonglong { | ||
| self.regs.pc | ||
| } | ||
|
|
||
| pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { | ||
| // out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; | ||
| out.context_flags = MD_CONTEXT_ARM64_ALL_OLD; | ||
| out.cpsr = self.regs.pstate as u32; | ||
| for idx in 0..MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_SP { | ||
| for idx in 0..MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_SP as usize { | ||
| out.iregs[idx] = self.regs.regs[idx]; | ||
| } | ||
| out.iregs[MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_SP] = self.regs.sp; | ||
| out.iregs[MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_PC] = self.regs.pc; | ||
| out.float_save.fpsr = self.fpregs.fpsr; | ||
| out.iregs[MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_SP as usize] = self.regs.sp; | ||
| out.iregs[MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_PC as usize] = self.regs.pc; | ||
| out.pc = self.regs.pc; | ||
| out.float_save.fpcr = self.fpregs.fpcr; | ||
| out.float_save.fpsr = self.fpregs.fpsr; | ||
| out.float_save.regs = self.fpregs.regs; | ||
| } | ||
| 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)?; | ||
|
|
||
| // my_memcpy(&out->float_save.regs, &fpregs.vregs, | ||
| // MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); | ||
| out.float_save.regs = self | ||
| .fpregs | ||
| .vregs | ||
| .iter() | ||
| .map(|x| x.to_ne_bytes().to_vec()) | ||
| .flatten() | ||
| .take(MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16) | ||
| .collect::<Vec<_>>() | ||
| .as_slice() | ||
| .try_into() // Make slice into fixed size array | ||
| .unwrap(); // Which has to work as we know the numbers work out | ||
| let stack_pointer = regs.uregs[13] as usize; | ||
|
|
||
| Ok(ThreadInfoAarch64 { | ||
| stack_pointer, | ||
| tgid, | ||
| ppid, | ||
| regs, | ||
| fpregs, | ||
| }) | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you created your own struct, this will not produce an error anymore? So the second half of the comment can be removed, I think.