Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ license = "MIT"
byteorder = "1.3.2"
cfg-if = "1.0"
memoffset = "0.5.1"
minidump-common = "0.10"
scroll = "0.11"
tempfile = "3.1.0"
thiserror = "1.0.21"

Expand All @@ -21,5 +23,8 @@ memmap2 = "0.2.2"
nix = "0.23"

[dev-dependencies]
minidump = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" }
minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" }
minidump = "0.10"

[patch.crates-io]
minidump = { git = "https://github.com/luser/rust-minidump", branch = "master" }
minidump-common = { git = "https://github.com/luser/rust-minidump", branch = "master" }
21 changes: 20 additions & 1 deletion src/linux/crash_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,26 @@ cfg_if::cfg_if! {
} else if #[cfg(target_arch = "aarch64")] {
pub(crate) mod aarch64;

pub type fpstate_t = libc::fpsimd_context; // Currently not part of libc! This will produce an error.
/// Magic value written by the kernel and our custom getcontext
pub const FPSIMD_MAGIC: u32 = 0x46508001;

#[repr(C)]
#[derive(Clone)]
pub struct _aarch64_ctx {
pub magic: u32,
pub size: u32,
}

#[repr(C)]
#[derive(Clone)]
pub struct fpsimd_context {
pub head: _aarch64_ctx,
pub fpsr: u32,
pub fpcr: u32,
pub vregs: [u128; 32],
}

pub type fpstate_t = fpsimd_context;
}
}

Expand Down
21 changes: 19 additions & 2 deletions src/linux/crash_context/aarch64.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
use super::CrashContext;
use crate::{
minidump_cpu::{RawContextCPU, FP_REG_COUNT, GP_REG_COUNT},
minidump_format::format,
};

impl CrashContext {
pub fn get_instruction_pointer(&self) -> usize {
self.context.uc_mcontext.sp as usize
self.context.uc_mcontext.pc as usize
}

pub fn get_stack_pointer(&self) -> usize {
self.context.uc_mcontext.pc as usize
self.context.uc_mcontext.sp as usize
}

pub fn fill_cpu_context(&self, out: &mut RawContextCPU) {
out.context_flags = format::ContextFlagsArm64Old::CONTEXT_ARM64_OLD_FULL.bits() as u64;

out.cpsr = self.context.uc_mcontext.pstate as u32;
out.iregs[..GP_REG_COUNT].copy_from_slice(&self.context.uc_mcontext.regs[..GP_REG_COUNT]);
out.sp = self.context.uc_mcontext.sp;
out.pc = self.context.uc_mcontext.pc;

out.fpsr = self.float_state.fpsr;
out.fpcr = self.float_state.fpcr;
out.float_regs[..FP_REG_COUNT].copy_from_slice(&self.float_state.vregs[..FP_REG_COUNT]);
}
}
68 changes: 40 additions & 28 deletions src/linux/crash_context/x86.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::CrashContext;
use crate::minidump_cpu::imp::*;
use crate::minidump_cpu::RawContextCPU;
use crate::{minidump_cpu::RawContextCPU, minidump_format::format::ContextFlagsX86};
use libc::{
REG_CS, REG_DS, REG_EAX, REG_EBP, REG_EBX, REG_ECX, REG_EDI, REG_EDX, REG_EFL, REG_EIP, REG_ES,
REG_ESI, REG_ESP, REG_FS, REG_GS, REG_SS, REG_UESP,
Expand All @@ -15,36 +14,49 @@ impl CrashContext {
}

pub fn fill_cpu_context(&self, out: &mut RawContextCPU) {
out.context_flags = MD_CONTEXT_X86_FULL | MD_CONTEXT_X86_FLOATING_POINT;
out.context_flags = ContextFlagsX86::CONTEXT_X86_FULL.bits()
| ContextFlagsX86::CONTEXT_X86_FLOATING_POINT.bits();

out.gs = self.context.uc_mcontext.gregs[REG_GS as usize] as u32;
out.fs = self.context.uc_mcontext.gregs[REG_FS as usize] as u32;
out.es = self.context.uc_mcontext.gregs[REG_ES as usize] as u32;
out.ds = self.context.uc_mcontext.gregs[REG_DS as usize] as u32;
{
let gregs = &self.context.uc_mcontext.gregs;
out.gs = gregs[REG_GS as usize] as u32;
out.fs = gregs[REG_FS as usize] as u32;
out.es = gregs[REG_ES as usize] as u32;
out.ds = gregs[REG_DS as usize] as u32;

out.edi = self.context.uc_mcontext.gregs[REG_EDI as usize] as u32;
out.esi = self.context.uc_mcontext.gregs[REG_ESI as usize] as u32;
out.ebx = self.context.uc_mcontext.gregs[REG_EBX as usize] as u32;
out.edx = self.context.uc_mcontext.gregs[REG_EDX as usize] as u32;
out.ecx = self.context.uc_mcontext.gregs[REG_ECX as usize] as u32;
out.eax = self.context.uc_mcontext.gregs[REG_EAX as usize] as u32;
out.edi = gregs[REG_EDI as usize] as u32;
out.esi = gregs[REG_ESI as usize] as u32;
out.ebx = gregs[REG_EBX as usize] as u32;
out.edx = gregs[REG_EDX as usize] as u32;
out.ecx = gregs[REG_ECX as usize] as u32;
out.eax = gregs[REG_EAX as usize] as u32;

out.ebp = self.context.uc_mcontext.gregs[REG_EBP as usize] as u32;
out.eip = self.context.uc_mcontext.gregs[REG_EIP as usize] as u32;
out.cs = self.context.uc_mcontext.gregs[REG_CS as usize] as u32;
out.eflags = self.context.uc_mcontext.gregs[REG_EFL as usize] as u32;
out.esp = self.context.uc_mcontext.gregs[REG_UESP as usize] as u32;
out.ss = self.context.uc_mcontext.gregs[REG_SS as usize] as u32;
out.ebp = gregs[REG_EBP as usize] as u32;
out.eip = gregs[REG_EIP as usize] as u32;
out.cs = gregs[REG_CS as usize] as u32;
out.eflags = gregs[REG_EFL as usize] as u32;
out.esp = gregs[REG_UESP as usize] as u32;
out.ss = gregs[REG_SS as usize] as u32;
}

out.float_save.control_word = self.float_state.cw;
out.float_save.status_word = self.float_state.sw;
out.float_save.tag_word = self.float_state.tag;
out.float_save.error_offset = self.float_state.ipoff;
out.float_save.error_selector = self.float_state.cssel;
out.float_save.data_offset = self.float_state.dataoff;
out.float_save.data_selector = self.float_state.datasel;
{
let fs = &self.float_state;
let mut out = &mut out.float_save;
out.control_word = fs.cw;
out.status_word = fs.sw;
out.tag_word = fs.tag;
out.error_offset = fs.ipoff;
out.error_selector = fs.cssel;
out.data_offset = fs.dataoff;
out.data_selector = fs.datasel;

// 8 registers * 10 bytes per register.
// my_memcpy(out->float_save.register_area, fp->_st, 10 * 8);
debug_assert_eq!(fs._st.len() * std::mem::size_of::<libc::_libc_fpreg>(), 80);
out.register_area.copy_from_slice(unsafe {
std::slice::from_raw_parts(
fs._st.as_ptr().cast(),
fs._st.len() * std::mem::size_of::<libc::_libc_fpreg>(),
)
});
}
}
}
93 changes: 51 additions & 42 deletions src/linux/crash_context/x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use super::CrashContext;
use crate::minidump_cpu::imp::*;
use crate::minidump_cpu::RawContextCPU;
use crate::thread_info::to_u128;
use crate::{
minidump_cpu::RawContextCPU, minidump_format::format, thread_info::copy_u32_registers,
};
use libc::{
REG_CSGSFS, REG_EFL, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_R8, REG_R9,
REG_RAX, REG_RBP, REG_RBX, REG_RCX, REG_RDI, REG_RDX, REG_RIP, REG_RSI, REG_RSP,
};
use scroll::Pwrite;

impl CrashContext {
pub fn get_instruction_pointer(&self) -> usize {
Expand All @@ -17,53 +18,61 @@ impl CrashContext {
}

pub fn fill_cpu_context(&self, out: &mut RawContextCPU) {
out.context_flags = MD_CONTEXT_AMD64_FULL;
out.cs = (self.context.uc_mcontext.gregs[REG_CSGSFS as usize] & 0xffff) as u16;

out.fs = ((self.context.uc_mcontext.gregs[REG_CSGSFS as usize] >> 32) & 0xffff) as u16;
out.gs = ((self.context.uc_mcontext.gregs[REG_CSGSFS as usize] >> 16) & 0xffff) as u16;
out.context_flags = format::ContextFlagsAmd64::CONTEXT_AMD64_FULL.bits();

out.eflags = self.context.uc_mcontext.gregs[REG_EFL as usize] as u32;
{
let gregs = &self.context.uc_mcontext.gregs;
out.cs = (gregs[REG_CSGSFS as usize] & 0xffff) as u16;

out.rax = self.context.uc_mcontext.gregs[REG_RAX as usize] as u64;
out.rcx = self.context.uc_mcontext.gregs[REG_RCX as usize] as u64;
out.rdx = self.context.uc_mcontext.gregs[REG_RDX as usize] as u64;
out.rbx = self.context.uc_mcontext.gregs[REG_RBX as usize] as u64;
out.fs = ((gregs[REG_CSGSFS as usize] >> 32) & 0xffff) as u16;
out.gs = ((gregs[REG_CSGSFS as usize] >> 16) & 0xffff) as u16;

out.rsp = self.context.uc_mcontext.gregs[REG_RSP as usize] as u64;
out.rbp = self.context.uc_mcontext.gregs[REG_RBP as usize] as u64;
out.rsi = self.context.uc_mcontext.gregs[REG_RSI as usize] as u64;
out.rdi = self.context.uc_mcontext.gregs[REG_RDI as usize] as u64;
out.r8 = self.context.uc_mcontext.gregs[REG_R8 as usize] as u64;
out.r9 = self.context.uc_mcontext.gregs[REG_R9 as usize] as u64;
out.r10 = self.context.uc_mcontext.gregs[REG_R10 as usize] as u64;
out.r11 = self.context.uc_mcontext.gregs[REG_R11 as usize] as u64;
out.r12 = self.context.uc_mcontext.gregs[REG_R12 as usize] as u64;
out.r13 = self.context.uc_mcontext.gregs[REG_R13 as usize] as u64;
out.r14 = self.context.uc_mcontext.gregs[REG_R14 as usize] as u64;
out.r15 = self.context.uc_mcontext.gregs[REG_R15 as usize] as u64;
out.eflags = gregs[REG_EFL as usize] as u32;

out.rip = self.context.uc_mcontext.gregs[REG_RIP as usize] as u64;
out.rax = gregs[REG_RAX as usize] as u64;
out.rcx = gregs[REG_RCX as usize] as u64;
out.rdx = gregs[REG_RDX as usize] as u64;
out.rbx = gregs[REG_RBX as usize] as u64;

out.flt_save.control_word = self.float_state.cwd;
out.flt_save.status_word = self.float_state.swd;
out.flt_save.tag_word = self.float_state.ftw as u8;
out.flt_save.error_opcode = self.float_state.fop;
out.flt_save.error_offset = self.float_state.rip as u32;
out.flt_save.data_offset = self.float_state.rdp as u32;
out.flt_save.error_selector = 0; // We don't have this.
out.flt_save.data_selector = 0; // We don't have this.
out.flt_save.mx_csr = self.float_state.mxcsr;
out.flt_save.mx_csr_mask = self.float_state.mxcr_mask;
out.rsp = gregs[REG_RSP as usize] as u64;
out.rbp = gregs[REG_RBP as usize] as u64;
out.rsi = gregs[REG_RSI as usize] as u64;
out.rdi = gregs[REG_RDI as usize] as u64;
out.r8 = gregs[REG_R8 as usize] as u64;
out.r9 = gregs[REG_R9 as usize] as u64;
out.r10 = gregs[REG_R10 as usize] as u64;
out.r11 = gregs[REG_R11 as usize] as u64;
out.r12 = gregs[REG_R12 as usize] as u64;
out.r13 = gregs[REG_R13 as usize] as u64;
out.r14 = gregs[REG_R14 as usize] as u64;
out.r15 = gregs[REG_R15 as usize] as u64;

let data = to_u128(&self.float_state.st_space);
for idx in 0..data.len() {
out.flt_save.float_registers[idx] = data[idx];
out.rip = gregs[REG_RIP as usize] as u64;
}

let data = to_u128(&self.float_state.xmm_space);
for idx in 0..data.len() {
out.flt_save.xmm_registers[idx] = data[idx];
{
let fs = &self.float_state;

let mut float_save = format::XMM_SAVE_AREA32 {
control_word: fs.cwd,
status_word: fs.swd,
tag_word: fs.ftw as u8,
error_opcode: fs.fop,
error_offset: fs.rip as u32,
data_offset: fs.rdp as u32,
error_selector: 0, // We don't have this.
data_selector: 0, // We don't have this.
mx_csr: fs.mxcsr,
mx_csr_mask: fs.mxcr_mask,
..Default::default()
};

copy_u32_registers(&mut float_save.float_registers, &fs.st_space);
copy_u32_registers(&mut float_save.xmm_registers, &fs.xmm_space);

out.float_save
.pwrite_with(float_save, 0, scroll::Endian::Little)
.expect("this is impossible");
}
}
}
2 changes: 1 addition & 1 deletion src/linux/dso_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ pub fn write_dso_debug_stream(
dyn_addr as *mut libc::c_void,
dynamic_length,
)?;
MemoryArrayWriter::<u8>::alloc_from_array(buffer, &dso_debug_data)?;
MemoryArrayWriter::write_bytes(buffer, &dso_debug_data);

Ok(dirent)
}
35 changes: 13 additions & 22 deletions src/linux/dumper_cpu_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,25 @@ cfg_if::cfg_if! {

pub use imp::write_cpu_information;

use crate::errors::MemoryWriterError;
use crate::minidump_format::{MDOSPlatform, MDRawSystemInfo};
use crate::sections::write_string_to_location;
use crate::minidump_format::PlatformId;
use nix::sys::utsname::uname;
use std::io::Cursor;

type Result<T> = std::result::Result<T, MemoryWriterError>;

pub fn write_os_information(
buffer: &mut Cursor<Vec<u8>>,
sys_info: &mut MDRawSystemInfo,
) -> Result<()> {
/// Retrieves the [`MDOSPlatform`] and synthesized version information
pub fn os_information() -> (PlatformId, String) {
let info = uname();
if cfg!(target_os = "android") {
sys_info.platform_id = MDOSPlatform::Android as u32;
} else {
sys_info.platform_id = MDOSPlatform::Linux as u32;
}
let merged = vec![
let vers = format!(
"{} {} {} {}",
info.sysname(),
info.release(),
info.version(),
info.machine(),
]
.join(" ");
info.machine()
);

let location = write_string_to_location(buffer, &merged)?;
sys_info.csd_version_rva = location.rva;
let platform_id = if cfg!(target_os = "android") {
PlatformId::Android
} else {
PlatformId::Linux
};

Ok(())
(platform_id, vers)
}
Loading