From f1f808901021a4b31912a31fc9e10ba118713970 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 9 Nov 2021 11:52:49 +0100 Subject: [PATCH 01/21] These do exist in arm --- src/crash_context/mod.rs | 1 - src/minidump_writer.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/crash_context/mod.rs b/src/crash_context/mod.rs index 2be8fb15..7714b18d 100644 --- a/src/crash_context/mod.rs +++ b/src/crash_context/mod.rs @@ -55,7 +55,6 @@ pub type fpstate_t = libc::user_fpregs_struct; pub struct CrashContext { pub siginfo: libc::siginfo_t, pub tid: libc::pid_t, // the crashing thread. - #[cfg(not(target_arch = "arm"))] pub context: libc::ucontext_t, // #ifdef this out because FP state is not part of user ABI for Linux ARM. // In case of MIPS Linux FP state is already part of ucontext_t so diff --git a/src/minidump_writer.rs b/src/minidump_writer.rs index 644843d9..4a910e14 100644 --- a/src/minidump_writer.rs +++ b/src/minidump_writer.rs @@ -165,8 +165,6 @@ impl MinidumpWriter { self } - // Has to be deactivated for ARM for now, as libc doesn't include ucontext_t for ARM yet - #[cfg(not(target_arch = "arm"))] pub fn set_crash_context(&mut self, crash_context: CrashContext) -> &mut Self { self.crash_context = Some(crash_context); self From b711755c78b7ebc1ca57d7510cb9620c11f2bed5 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 9 Nov 2021 12:20:42 +0100 Subject: [PATCH 02/21] Use nix's siginfo instead of libc's --- src/crash_context/mod.rs | 2 +- src/sections/exception_stream.rs | 6 +++--- tests/minidump_writer.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crash_context/mod.rs b/src/crash_context/mod.rs index 7714b18d..3b65d9d6 100644 --- a/src/crash_context/mod.rs +++ b/src/crash_context/mod.rs @@ -53,7 +53,7 @@ pub type fpstate_t = libc::user_fpregs_struct; #[repr(C)] #[derive(Clone)] pub struct CrashContext { - pub siginfo: libc::siginfo_t, + pub siginfo: nix::sys::signalfd::siginfo, pub tid: libc::pid_t, // the crashing thread. pub context: libc::ucontext_t, // #ifdef this out because FP state is not part of user ABI for Linux ARM. diff --git a/src/sections/exception_stream.rs b/src/sections/exception_stream.rs index 65e14119..d3c49ece 100644 --- a/src/sections/exception_stream.rs +++ b/src/sections/exception_stream.rs @@ -67,11 +67,11 @@ pub fn write(config: &mut MinidumpWriter, buffer: &mut DumpBuf) -> Result Result { #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] fn get_crash_context(tid: Pid) -> CrashContext { - let siginfo: libc::siginfo_t = unsafe { std::mem::zeroed() }; + let siginfo = unsafe { std::mem::zeroed() }; let context = get_ucontext().expect("Failed to get ucontext"); let float_state: fpstate_t = unsafe { std::mem::zeroed() }; CrashContext { From f429cba877f390ee8c88e7be34a6796a045e7503 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 11 Nov 2021 12:27:05 +0100 Subject: [PATCH 03/21] Update dependencies --- Cargo.toml | 22 +++++++++++----------- src/lib.rs | 2 ++ src/linux_ptrace_dumper.rs | 36 +++++++++++++++++++----------------- src/thread_info/mod.rs | 2 +- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 237afe6a..c1d02bf6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,21 +2,21 @@ name = "minidump_writer_linux" version = "0.1.0" authors = ["Martin Sirringhaus"] -edition = "2018" +edition = "2021" license = "MIT" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -tempfile = "3.1.0" -nix = "0.15" -libc = "0.2.74" -memoffset = "0.5.1" byteorder = "1.3.2" -memmap2 = "0.2.2" -goblin = "0.1.2" +exception-handler = { path = "../crash-handling/exception-handler" } +goblin = "0.4" +libc = "0.2.74" +memmap2 = "0.5" +memoffset = "0.6" +nix = "0.23" +tempfile = "3.1.0" thiserror = "1.0.21" +uctx = { path = "../crash-handling/uctx" } [dev-dependencies] -minidump = {git = "https://github.com/luser/rust-minidump", rev="9652b3b" } -minidump-common = {git = "https://github.com/luser/rust-minidump", rev="9652b3b" } +minidump = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } +minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } diff --git a/src/lib.rs b/src/lib.rs index 1a774cd8..5c60acc8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(unsafe_code)] + #[cfg(target_os = "android")] mod android; pub mod app_memory; diff --git a/src/linux_ptrace_dumper.rs b/src/linux_ptrace_dumper.rs index f1e249b0..0b5c4242 100644 --- a/src/linux_ptrace_dumper.rs +++ b/src/linux_ptrace_dumper.rs @@ -1,21 +1,23 @@ // use libc::c_void; #[cfg(target_os = "android")] use crate::android::late_process_mappings; -use crate::auxv_reader::{AuxvType, ProcfsAuxvIter}; -use crate::errors::{DumperError, InitError, ThreadInfoError}; -use crate::maps_reader::{MappingInfo, MappingInfoParsingResult, DELETED_SUFFIX}; -use crate::minidump_format::MDGUID; -use crate::thread_info::{Pid, ThreadInfo}; -use crate::LINUX_GATE_LIBRARY_NAME; +use crate::{ + auxv_reader::{AuxvType, ProcfsAuxvIter}, + errors::{DumperError, InitError, ThreadInfoError}, + maps_reader::{MappingInfo, MappingInfoParsingResult, DELETED_SUFFIX}, + minidump_format::MDGUID, + thread_info::{Pid, ThreadInfo}, + LINUX_GATE_LIBRARY_NAME, +}; use goblin::elf; -use nix::errno::Errno; use nix::sys::{ptrace, wait}; -use std::collections::HashMap; -use std::convert::TryInto; -use std::ffi::c_void; -use std::io::{BufRead, BufReader}; -use std::path; -use std::result::Result; +use std::{ + collections::HashMap, + ffi::c_void, + io::{BufRead, BufReader}, + path, + result::Result, +}; #[derive(Debug, Clone)] pub struct Thread { @@ -107,8 +109,8 @@ impl LinuxPtraceDumper { loop { match wait::waitpid(pid, Some(wait::WaitPidFlag::__WALL)) { Ok(_) => break, - Err(e @ nix::Error::Sys(Errno::EINTR)) => { - ptrace::detach(pid).map_err(|e| DetachErr(child, e))?; + Err(e @ nix::Error::EINTR) => { + ptrace::detach(pid, None).map_err(|e| DetachErr(child, e))?; return Err(DumperError::WaitPidError(child, e)); } Err(_) => continue, @@ -138,7 +140,7 @@ impl LinuxPtraceDumper { skip_thread = true; } if skip_thread { - ptrace::detach(pid).map_err(|e| DetachErr(child, e))?; + ptrace::detach(pid, None).map_err(|e| DetachErr(child, e))?; return Err(DumperError::DetachSkippedThread(child)); } } @@ -149,7 +151,7 @@ impl LinuxPtraceDumper { pub fn resume_thread(child: Pid) -> Result<(), DumperError> { use DumperError::PtraceDetachError as DetachErr; let pid = nix::unistd::Pid::from_raw(child); - ptrace::detach(pid).map_err(|e| DetachErr(child, e))?; + ptrace::detach(pid, None).map_err(|e| DetachErr(child, e))?; Ok(()) } diff --git a/src/thread_info/mod.rs b/src/thread_info/mod.rs index 18a9ecb0..cb918b50 100644 --- a/src/thread_info/mod.rs +++ b/src/thread_info/mod.rs @@ -166,7 +166,7 @@ trait CommonThreadInfo { ) }; match Errno::result(ret) { - Ok(..) | Err(nix::Error::Sys(Errno::UnknownErrno)) => Ok(ret), + Ok(..) | Err(nix::Error::UnknownErrno) => Ok(ret), err @ Err(..) => err, } } From 40e967b14a0d959749b02b040ac4c3ef9da076ad Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 18 Nov 2021 08:50:38 +0100 Subject: [PATCH 04/21] Remove unneeded TryInto imports --- src/android.rs | 1 - src/bin/test.rs | 1 - src/dumper_cpu_info/cpu_info_x86_mips.rs | 1 - src/maps_reader.rs | 1 - src/sections/mod.rs | 1 - src/sections/thread_names_stream.rs | 1 - src/thread_info/mod.rs | 1 - src/thread_info/thread_info_x86.rs | 2 -- tests/ptrace_dumper.rs | 1 - 9 files changed, 10 deletions(-) diff --git a/src/android.rs b/src/android.rs index b605b6ce..917b4ea1 100644 --- a/src/android.rs +++ b/src/android.rs @@ -15,7 +15,6 @@ use goblin::elf::header::header64 as elf_header; use goblin::elf::program_header::program_header32::ProgramHeader; #[cfg(target_pointer_width = "64")] use goblin::elf::program_header::program_header64::ProgramHeader; -use std::convert::TryInto; use std::ffi::c_void; type Result = std::result::Result; diff --git a/src/bin/test.rs b/src/bin/test.rs index 9899e8f9..7ae13dc8 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -4,7 +4,6 @@ use minidump_writer_linux::linux_ptrace_dumper::{LinuxPtraceDumper, AT_SYSINFO_E use minidump_writer_linux::{linux_ptrace_dumper, LINUX_GATE_LIBRARY_NAME}; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::unistd::getppid; -use std::convert::TryInto; use std::env; use std::error; use std::result; diff --git a/src/dumper_cpu_info/cpu_info_x86_mips.rs b/src/dumper_cpu_info/cpu_info_x86_mips.rs index c37fa94f..ea9cfe07 100644 --- a/src/dumper_cpu_info/cpu_info_x86_mips.rs +++ b/src/dumper_cpu_info/cpu_info_x86_mips.rs @@ -1,6 +1,5 @@ use crate::errors::CpuInfoError; use crate::minidump_format::*; -use std::convert::TryInto; use std::io::{BufRead, BufReader}; use std::path; diff --git a/src/maps_reader.rs b/src/maps_reader.rs index ec0b4543..f81f67de 100644 --- a/src/maps_reader.rs +++ b/src/maps_reader.rs @@ -4,7 +4,6 @@ use crate::thread_info::Pid; use byteorder::{NativeEndian, ReadBytesExt}; use goblin::elf; use memmap2::{Mmap, MmapOptions}; -use std::convert::TryInto; use std::fs::File; use std::mem::size_of; use std::path::PathBuf; diff --git a/src/sections/mod.rs b/src/sections/mod.rs index 086e7e23..7d56d7be 100644 --- a/src/sections/mod.rs +++ b/src/sections/mod.rs @@ -8,7 +8,6 @@ pub mod thread_names_stream; use crate::errors::MemoryWriterError; use crate::minidump_format::*; -use std::convert::TryInto; use std::io::{Cursor, Write}; type Result = std::result::Result; diff --git a/src/sections/thread_names_stream.rs b/src/sections/thread_names_stream.rs index decb1674..9a5526dc 100644 --- a/src/sections/thread_names_stream.rs +++ b/src/sections/thread_names_stream.rs @@ -4,7 +4,6 @@ use crate::minidump_format::*; use crate::minidump_writer::DumpBuf; use crate::sections::write_string_to_location; use crate::sections::{MemoryArrayWriter, MemoryWriter}; -use std::convert::TryInto; type Result = std::result::Result; diff --git a/src/thread_info/mod.rs b/src/thread_info/mod.rs index cb918b50..60f4d328 100644 --- a/src/thread_info/mod.rs +++ b/src/thread_info/mod.rs @@ -2,7 +2,6 @@ use crate::errors::ThreadInfoError; use nix::errno::Errno; use nix::sys::ptrace; use nix::unistd; -use std::convert::TryInto; use std::io::{self, BufRead}; use std::path; diff --git a/src/thread_info/thread_info_x86.rs b/src/thread_info/thread_info_x86.rs index 6dbf6c2d..d6fdfe2c 100644 --- a/src/thread_info/thread_info_x86.rs +++ b/src/thread_info/thread_info_x86.rs @@ -10,8 +10,6 @@ use libc::user; use memoffset; use nix::sys::ptrace; use nix::unistd; -#[cfg(target_arch = "x86")] -use std::convert::TryInto; type Result = std::result::Result; diff --git a/tests/ptrace_dumper.rs b/tests/ptrace_dumper.rs index c2e8fccf..d2002686 100644 --- a/tests/ptrace_dumper.rs +++ b/tests/ptrace_dumper.rs @@ -1,7 +1,6 @@ use minidump_writer_linux::linux_ptrace_dumper; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::Signal; -use std::convert::TryInto; use std::io::{BufRead, BufReader}; use std::mem::size_of; use std::os::unix::io::AsRawFd; From 6bdab6b746f96530968da19456c2e037742cb723 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 18 Nov 2021 08:51:07 +0100 Subject: [PATCH 05/21] Cleanup imports --- src/minidump_writer.rs | 20 ++++++++++-------- src/sections/thread_list_stream.rs | 16 ++++++++------- tests/minidump_writer.rs | 33 +++++++++++++++--------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/minidump_writer.rs b/src/minidump_writer.rs index 4a910e14..b9805470 100644 --- a/src/minidump_writer.rs +++ b/src/minidump_writer.rs @@ -1,12 +1,14 @@ -use crate::app_memory::AppMemoryList; -use crate::crash_context::CrashContext; -use crate::dso_debug; -use crate::errors::{FileWriterError, InitError, MemoryWriterError, WriterError}; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::maps_reader::{MappingInfo, MappingList}; -use crate::minidump_format::*; -use crate::sections::*; -use crate::thread_info::Pid; +use crate::{ + app_memory::AppMemoryList, + crash_context::{CpuContext, CrashContext}, + dso_debug, + errors::{FileWriterError, InitError, MemoryWriterError, WriterError}, + linux_ptrace_dumper::LinuxPtraceDumper, + maps_reader::{MappingInfo, MappingList}, + minidump_format::*, + sections::*, + thread_info::Pid, +}; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; pub type DumpBuf = Cursor>; diff --git a/src/sections/thread_list_stream.rs b/src/sections/thread_list_stream.rs index d3672d99..f4cb3c07 100644 --- a/src/sections/thread_list_stream.rs +++ b/src/sections/thread_list_stream.rs @@ -1,10 +1,12 @@ -use crate::errors::SectionThreadListError; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::minidump_cpu::RawContextCPU; -use crate::minidump_format::*; -use crate::minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}; -use crate::sections::{MemoryArrayWriter, MemoryWriter}; -use std::convert::TryInto; +use crate::{ + crash_context::CpuContext, + errors::SectionThreadListError, + linux_ptrace_dumper::LinuxPtraceDumper, + minidump_cpu::RawContextCPU, + minidump_format::*, + minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}, + sections::{MemoryArrayWriter, MemoryWriter}, +}; use std::io::Write; type Result = std::result::Result; diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index 38445a21..d6c307a8 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -1,22 +1,21 @@ use minidump::*; use minidump_common::format::{GUID, MINIDUMP_STREAM_TYPE::*}; -use minidump_writer_linux::app_memory::AppMemory; -#[cfg(not(any(target_arch = "mips", target_arch = "arm")))] -use minidump_writer_linux::crash_context::fpstate_t; -use minidump_writer_linux::crash_context::CrashContext; -use minidump_writer_linux::errors::*; -use minidump_writer_linux::linux_ptrace_dumper::LinuxPtraceDumper; -use minidump_writer_linux::maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}; -use minidump_writer_linux::minidump_writer::MinidumpWriter; -use minidump_writer_linux::thread_info::Pid; -use nix::errno::Errno; -use nix::sys::signal::Signal; -use std::collections::HashSet; -use std::convert::TryInto; -use std::io::{BufRead, BufReader}; -use std::os::unix::process::ExitStatusExt; -use std::process::{Command, Stdio}; -use std::str::FromStr; +use minidump_writer_linux::{ + app_memory::AppMemory, + crash_context::CrashContext, + errors::*, + linux_ptrace_dumper::LinuxPtraceDumper, + maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}, + minidump_writer::MinidumpWriter, + thread_info::Pid, +}; +use nix::{errno::Errno, sys::signal::Signal}; +use std::{ + collections::HashSet, + io::{BufRead, BufReader}, + os::unix::process::ExitStatusExt, + process::{Command, Stdio}, +}; mod common; use common::*; From 40ca0a5f83656b188b8e156ddad538489d4d4ca3 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 18 Nov 2021 08:51:59 +0100 Subject: [PATCH 06/21] Use exception_handler::CrashContext --- Cargo.toml | 1 + src/crash_context/crash_context_x86_64.rs | 94 ++++++++++++----------- src/crash_context/mod.rs | 85 ++++++++------------ tests/minidump_writer.rs | 52 ++++++++++--- 4 files changed, 124 insertions(+), 108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c1d02bf6..d0a3966a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT" [dependencies] byteorder = "1.3.2" +cfg-if = "1.0" exception-handler = { path = "../crash-handling/exception-handler" } goblin = "0.4" libc = "0.2.74" diff --git a/src/crash_context/crash_context_x86_64.rs b/src/crash_context/crash_context_x86_64.rs index dd82d29a..87bccc77 100644 --- a/src/crash_context/crash_context_x86_64.rs +++ b/src/crash_context/crash_context_x86_64.rs @@ -1,69 +1,75 @@ -use super::CrashContext; use crate::minidump_cpu::imp::*; -use crate::minidump_cpu::RawContextCPU; + use crate::thread_info::to_u128; 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, }; -impl CrashContext { - pub fn get_instruction_pointer(&self) -> usize { +impl super::CpuContext for super::CrashContext { + fn get_instruction_pointer(&self) -> usize { self.context.uc_mcontext.gregs[REG_RIP as usize] as usize } - pub fn get_stack_pointer(&self) -> usize { + fn get_stack_pointer(&self) -> usize { self.context.uc_mcontext.gregs[REG_RSP as usize] as usize } - pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { + fn fill_cpu_context(&self, out: &mut super::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.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; + out.flt_save.control_word = fs.cwd; + out.flt_save.status_word = fs.swd; + out.flt_save.tag_word = fs.ftw as u8; + out.flt_save.error_opcode = fs.fop; + out.flt_save.error_offset = fs.rip as u32; + out.flt_save.data_offset = fs.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 = fs.mxcsr; + out.flt_save.mx_csr_mask = fs.mxcr_mask; + + let data = to_u128(&fs.st_space); + for idx in 0..data.len() { + out.flt_save.float_registers[idx] = data[idx]; + } + + let data = to_u128(&fs.xmm_space); + for idx in 0..data.len() { + out.flt_save.xmm_registers[idx] = data[idx]; + } } } } diff --git a/src/crash_context/mod.rs b/src/crash_context/mod.rs index 3b65d9d6..2dc37c08 100644 --- a/src/crash_context/mod.rs +++ b/src/crash_context/mod.rs @@ -1,64 +1,41 @@ -use libc; - // Minidump defines register structures which are different from the raw // structures which we get from the kernel. These are platform specific // functions to juggle the ucontext_t and user structures into minidump format. -#[cfg(target_arch = "x86_64")] -#[path = "crash_context_x86_64.rs"] -pub mod imp; -#[cfg(target_arch = "x86")] -#[path = "crash_context_x86.rs"] -pub mod imp; -// Deactivated for now, as ucontext_t is missing from libc -// #[cfg(target_arch = "arm")] -// #[path = "crash_context_arm.rs"] -// pub mod imp; -#[cfg(target_arch = "arm")] -use crate::minidump_cpu::RawContextCPU; -#[cfg(target_arch = "arm")] -impl CrashContext { - pub fn get_instruction_pointer(&self) -> usize { - 0 - } - - pub fn get_stack_pointer(&self) -> usize { - 0 +cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + mod crash_context_x86_64; + } else if #[cfg(target_arch = "x86")] { + mod crash_context_x86; + } else if #[cfg(target_arch = "aarch64")] { + mod crash_context_aarch64; + } else if #[cfg(target_arch = "arm")] { + mod crash_context_arm; + } else if #[cfg(target_arch = "mips")] { + mod crash_context_mips; } - - pub fn fill_cpu_context(&self, _: &mut RawContextCPU) {} } -#[cfg(target_arch = "aarch64")] -#[path = "crash_context_aarch64.rs"] -pub mod imp; -#[cfg(target_arch = "mips")] -#[path = "crash_context_mips.rs"] -pub mod imp; +use crate::minidump_cpu::RawContextCPU; + +// #[cfg(target_arch = "aarch64")] +// pub type fpstate_t = libc::fpsimd_context; // Currently not part of libc! This will produce an error. +// #[cfg(not(any( +// target_arch = "aarch64", +// target_arch = "mips", +// target_arch = "arm-eabi" +// )))] +// #[cfg(target_arch = "x86")] +// #[allow(non_camel_case_types)] +// pub type fpstate_t = libc::_libc_fpstate; +// #[cfg(target_arch = "x86_64")] +// #[allow(non_camel_case_types)] +// pub type fpstate_t = libc::user_fpregs_struct; -#[cfg(target_arch = "aarch64")] -pub type fpstate_t = libc::fpsimd_context; // Currently not part of libc! This will produce an error. -#[cfg(not(any( - target_arch = "aarch64", - target_arch = "mips", - target_arch = "arm-eabi" -)))] -#[cfg(target_arch = "x86")] -#[allow(non_camel_case_types)] -pub type fpstate_t = libc::_libc_fpstate; -#[cfg(target_arch = "x86_64")] -#[allow(non_camel_case_types)] -pub type fpstate_t = libc::user_fpregs_struct; +pub use exception_handler::CrashContext; -#[repr(C)] -#[derive(Clone)] -pub struct CrashContext { - pub siginfo: nix::sys::signalfd::siginfo, - pub tid: libc::pid_t, // the crashing thread. - pub context: libc::ucontext_t, - // #ifdef this out because FP state is not part of user ABI for Linux ARM. - // In case of MIPS Linux FP state is already part of ucontext_t so - // 'float_state' is not required. - #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] - pub float_state: fpstate_t, +pub trait CpuContext { + fn get_instruction_pointer(&self) -> usize; + fn get_stack_pointer(&self) -> usize; + fn fill_cpu_context(&self, cpu_ctx: &mut RawContextCPU); } diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index d6c307a8..9cfc37e4 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -27,18 +27,21 @@ enum Context { } #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] -fn get_ucontext() -> Result { - let mut context = std::mem::MaybeUninit::::uninit(); - let res = unsafe { libc::getcontext(context.as_mut_ptr()) }; - Errno::result(res)?; - unsafe { Ok(context.assume_init()) } +fn get_ucontext() -> Result { + let mut context = std::mem::MaybeUninit::uninit(); + unsafe { + let res = uctx::getcontext(context.as_mut_ptr()); + Errno::result(res)?; + + Ok(context.assume_init()) + } } #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] fn get_crash_context(tid: Pid) -> CrashContext { let siginfo = unsafe { std::mem::zeroed() }; let context = get_ucontext().expect("Failed to get ucontext"); - let float_state: fpstate_t = unsafe { std::mem::zeroed() }; + let float_state = unsafe { std::mem::zeroed() }; CrashContext { siginfo, tid, @@ -83,6 +86,7 @@ fn test_write_dump_helper(context: Context) { fn test_write_dump() { test_write_dump_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_write_dump_with_context() { @@ -104,8 +108,16 @@ fn test_write_and_read_dump_from_parent_helper(context: Context) { .read_line(&mut buf) .expect("Couldn't read address provided by child"); let mut output = buf.split_whitespace(); - let mmap_addr = usize::from_str(output.next().unwrap()).expect("unable to parse mmap_addr"); - let memory_size = usize::from_str(output.next().unwrap()).expect("unable to parse memory_size"); + let mmap_addr: usize = output + .next() + .unwrap() + .parse() + .expect("unable to parse mmap_addr"); + let memory_size: usize = output + .next() + .unwrap() + .parse() + .expect("unable to parse memory_size"); // Add information about the mapped memory. let mapping = MappingInfo { start_address: mmap_addr, @@ -188,10 +200,12 @@ fn test_write_and_read_dump_from_parent_helper(context: Context) { .get_raw_stream(LinuxDsoDebug) .expect("Couldn't find LinuxDsoDebug"); } + #[test] fn test_write_and_read_dump_from_parent() { test_write_and_read_dump_from_parent_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_write_and_read_dump_from_parent_with_context() { @@ -215,7 +229,11 @@ fn test_write_with_additional_memory_helper(context: Context) { let mut output = buf.split_whitespace(); let memory_addr = usize::from_str_radix(output.next().unwrap().trim_start_matches("0x"), 16) .expect("unable to parse mmap_addr"); - let memory_size = usize::from_str(output.next().unwrap()).expect("unable to parse memory_size"); + let memory_size: usize = output + .next() + .unwrap() + .parse() + .expect("unable to parse memory_size"); let app_memory = AppMemory { ptr: memory_addr, @@ -259,10 +277,12 @@ fn test_write_with_additional_memory_helper(context: Context) { // Verify memory contents. assert_eq!(region.bytes, values); } + #[test] fn test_write_with_additional_memory() { test_write_with_additional_memory_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_write_with_additional_memory_with_context() { @@ -535,10 +555,12 @@ fn test_skip_if_requested_helper(context: Context) { assert!(res.is_err()); } + #[test] fn test_skip_if_requested() { test_skip_if_requested_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_skip_if_requested_with_context() { @@ -599,10 +621,12 @@ fn test_sanitized_stacks_helper(context: Context) { .is_some()); } } + #[test] fn test_sanitized_stacks() { test_sanitized_stacks_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_sanitized_stacks_with_context() { @@ -629,7 +653,11 @@ fn test_write_early_abort_helper(context: Context) { let _ = usize::from_str_radix(output.next().unwrap().trim_start_matches("0x"), 16) .expect("unable to parse mmap_addr"); let memory_addr = 0; - let memory_size = usize::from_str(output.next().unwrap()).expect("unable to parse memory_size"); + let memory_size: usize = output + .next() + .unwrap() + .parse() + .expect("unable to parse memory_size"); let app_memory = AppMemory { ptr: memory_addr, @@ -665,10 +693,12 @@ fn test_write_early_abort_helper(context: Context) { // Should be missing: assert!(dump.get_stream::().is_err()); } + #[test] fn test_write_early_abort() { test_write_early_abort_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_write_early_abort_with_context() { @@ -722,10 +752,12 @@ fn test_named_threads_helper(context: Context) { } assert_eq!(expected, names); } + #[test] fn test_named_threads() { test_named_threads_helper(Context::Without) } + #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] #[test] fn test_named_threads_with_context() { From e10b5549d4265f2b29991e96ec72d17ec9ec4637 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 18 Nov 2021 09:58:12 +0100 Subject: [PATCH 07/21] Refactor layout --- Cargo.toml | 2 +- src/bin/test.rs | 28 +++++------ src/lib.rs | 23 ++++------ src/linux.rs | 15 ++++++ src/{ => linux}/android.rs | 0 src/{ => linux}/app_memory.rs | 0 src/{ => linux}/auxv_reader.rs | 0 .../crash_context/crash_context_aarch64.rs | 0 .../crash_context/crash_context_arm.rs | 0 .../crash_context/crash_context_mips.rs | 0 .../crash_context/crash_context_x86.rs | 0 .../crash_context/crash_context_x86_64.rs | 0 src/{ => linux}/crash_context/mod.rs | 0 src/{ => linux}/dso_debug.rs | 30 ++++++------ .../mod.rs => linux/dumper_cpu_info.rs} | 38 +++++++++------ .../dumper_cpu_info/arm.rs} | 0 .../dumper_cpu_info/x86_mips.rs} | 0 src/{ => linux}/errors.rs | 6 +-- src/{ => linux}/maps_reader.rs | 13 ++---- src/{ => linux}/minidump_writer.rs | 26 ++++++----- .../ptrace_dumper.rs} | 22 +++++---- src/{sections/mod.rs => linux/sections.rs} | 10 +++- src/{ => linux}/sections/app_memory.rs | 15 +++--- src/{ => linux}/sections/exception_stream.rs | 13 +++--- src/{ => linux}/sections/mappings.rs | 21 +++++---- .../sections/memory_list_stream.rs | 7 +-- src/{ => linux}/sections/systeminfo_stream.rs | 9 ++-- .../sections/thread_list_stream.rs | 29 +++++++----- .../sections/thread_names_stream.rs | 11 ++--- .../mod.rs => linux/thread_info.rs} | 46 ++++++++----------- .../thread_info/aarch64.rs} | 0 .../thread_info/arm.rs} | 0 .../thread_info/mips.rs} | 0 .../thread_info/x86.rs} | 0 src/minidump_cpu.rs | 25 ++++++++++ .../{minidump_cpu_aarch64.rs => aarch64.rs} | 0 .../{minidump_cpu_amd64.rs => amd64.rs} | 0 .../{minidump_cpu_arm.rs => arm.rs} | 0 .../{minidump_cpu_mips.rs => mips.rs} | 0 src/minidump_cpu/mod.rs | 26 ----------- .../{minidump_cpu_ppc.rs => ppc.rs} | 0 .../{minidump_cpu_ppc64.rs => ppc64.rs} | 0 .../{minidump_cpu_sparc.rs => sparc.rs} | 0 .../{minidump_cpu_x86.rs => x86.rs} | 0 tests/minidump_writer.rs | 6 +-- tests/ptrace_dumper.rs | 8 ++-- 46 files changed, 220 insertions(+), 209 deletions(-) create mode 100644 src/linux.rs rename src/{ => linux}/android.rs (100%) rename src/{ => linux}/app_memory.rs (100%) rename src/{ => linux}/auxv_reader.rs (100%) rename src/{ => linux}/crash_context/crash_context_aarch64.rs (100%) rename src/{ => linux}/crash_context/crash_context_arm.rs (100%) rename src/{ => linux}/crash_context/crash_context_mips.rs (100%) rename src/{ => linux}/crash_context/crash_context_x86.rs (100%) rename src/{ => linux}/crash_context/crash_context_x86_64.rs (100%) rename src/{ => linux}/crash_context/mod.rs (100%) rename src/{ => linux}/dso_debug.rs (92%) rename src/{dumper_cpu_info/mod.rs => linux/dumper_cpu_info.rs} (57%) rename src/{dumper_cpu_info/cpu_info_arm.rs => linux/dumper_cpu_info/arm.rs} (100%) rename src/{dumper_cpu_info/cpu_info_x86_mips.rs => linux/dumper_cpu_info/x86_mips.rs} (100%) rename src/{ => linux}/errors.rs (98%) rename src/{ => linux}/maps_reader.rs (98%) rename src/{ => linux}/minidump_writer.rs (96%) rename src/{linux_ptrace_dumper.rs => linux/ptrace_dumper.rs} (98%) rename src/{sections/mod.rs => linux/sections.rs} (97%) rename src/{ => linux}/sections/app_memory.rs (54%) rename src/{ => linux}/sections/exception_stream.rs (93%) rename src/{ => linux}/sections/mappings.rs (84%) rename src/{ => linux}/sections/memory_list_stream.rs (69%) rename src/{ => linux}/sections/systeminfo_stream.rs (63%) rename src/{ => linux}/sections/thread_list_stream.rs (93%) rename src/{ => linux}/sections/thread_names_stream.rs (70%) rename src/{thread_info/mod.rs => linux/thread_info.rs} (86%) rename src/{thread_info/thread_info_aarch64.rs => linux/thread_info/aarch64.rs} (100%) rename src/{thread_info/thread_info_arm.rs => linux/thread_info/arm.rs} (100%) rename src/{thread_info/thread_info_mips.rs => linux/thread_info/mips.rs} (100%) rename src/{thread_info/thread_info_x86.rs => linux/thread_info/x86.rs} (100%) create mode 100644 src/minidump_cpu.rs rename src/minidump_cpu/{minidump_cpu_aarch64.rs => aarch64.rs} (100%) rename src/minidump_cpu/{minidump_cpu_amd64.rs => amd64.rs} (100%) rename src/minidump_cpu/{minidump_cpu_arm.rs => arm.rs} (100%) rename src/minidump_cpu/{minidump_cpu_mips.rs => mips.rs} (100%) delete mode 100644 src/minidump_cpu/mod.rs rename src/minidump_cpu/{minidump_cpu_ppc.rs => ppc.rs} (100%) rename src/minidump_cpu/{minidump_cpu_ppc64.rs => ppc64.rs} (100%) rename src/minidump_cpu/{minidump_cpu_sparc.rs => sparc.rs} (100%) rename src/minidump_cpu/{minidump_cpu_x86.rs => x86.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index d0a3966a..c243f519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "minidump_writer_linux" +name = "minidump-writer" version = "0.1.0" authors = ["Martin Sirringhaus"] edition = "2021" diff --git a/src/bin/test.rs b/src/bin/test.rs index 7ae13dc8..bbfe2fe8 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -1,7 +1,9 @@ // This binary shouldn't be under /src, but under /tests, but that is // currently not possible (https://github.com/rust-lang/cargo/issues/4356) -use minidump_writer_linux::linux_ptrace_dumper::{LinuxPtraceDumper, AT_SYSINFO_EHDR}; -use minidump_writer_linux::{linux_ptrace_dumper, LINUX_GATE_LIBRARY_NAME}; +use minidump_writer::{ + ptrace_dumper::{PtraceDumper, AT_SYSINFO_EHDR}, + LINUX_GATE_LIBRARY_NAME, +}; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::unistd::getppid; use std::env; @@ -23,13 +25,13 @@ macro_rules! test { fn test_setup() -> Result<()> { let ppid = getppid(); - linux_ptrace_dumper::LinuxPtraceDumper::new(ppid.as_raw())?; + PtraceDumper::new(ppid.as_raw())?; Ok(()) } fn test_thread_list() -> Result<()> { let ppid = getppid(); - let dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(ppid.as_raw())?; + let dumper = PtraceDumper::new(ppid.as_raw())?; test!(!dumper.threads.is_empty(), "No threads")?; test!( dumper @@ -45,9 +47,9 @@ fn test_thread_list() -> Result<()> { fn test_copy_from_process(stack_var: usize, heap_var: usize) -> Result<()> { let ppid = getppid().as_raw(); - let mut dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(ppid)?; + let mut dumper = PtraceDumper::new(ppid)?; dumper.suspend_threads()?; - let stack_res = LinuxPtraceDumper::copy_from_process(ppid, stack_var as *mut libc::c_void, 1)?; + let stack_res = PtraceDumper::copy_from_process(ppid, stack_var as *mut libc::c_void, 1)?; let expected_stack: libc::c_long = 0x11223344; test!( @@ -55,7 +57,7 @@ fn test_copy_from_process(stack_var: usize, heap_var: usize) -> Result<()> { "stack var not correct" )?; - let heap_res = LinuxPtraceDumper::copy_from_process(ppid, heap_var as *mut libc::c_void, 1)?; + let heap_res = PtraceDumper::copy_from_process(ppid, heap_var as *mut libc::c_void, 1)?; let expected_heap: libc::c_long = 0x55667788; test!( heap_res == expected_heap.to_ne_bytes(), @@ -67,7 +69,7 @@ fn test_copy_from_process(stack_var: usize, heap_var: usize) -> Result<()> { fn test_find_mappings(addr1: usize, addr2: usize) -> Result<()> { let ppid = getppid(); - let dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(ppid.as_raw())?; + let dumper = PtraceDumper::new(ppid.as_raw())?; dumper .find_mapping(addr1) .ok_or("No mapping for addr1 found")?; @@ -84,7 +86,7 @@ fn test_file_id() -> Result<()> { let ppid = getppid().as_raw(); let exe_link = format!("/proc/{}/exe", ppid); let exe_name = std::fs::read_link(&exe_link)?.into_os_string(); - let mut dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(getppid().as_raw())?; + let mut dumper = PtraceDumper::new(getppid().as_raw())?; let mut found_exe = None; for (idx, mapping) in dumper.mappings.iter().enumerate() { if mapping.name.as_ref().map(|x| x.into()).as_ref() == Some(&exe_name) { @@ -101,7 +103,7 @@ fn test_file_id() -> Result<()> { fn test_merged_mappings(path: String, mapped_mem: usize, mem_size: usize) -> Result<()> { // Now check that LinuxPtraceDumper interpreted the mappings properly. - let dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(getppid().as_raw())?; + let dumper = PtraceDumper::new(getppid().as_raw())?; let mut mapping_count = 0; for map in &dumper.mappings { if map.name == Some(path.clone()) { @@ -119,13 +121,13 @@ fn test_merged_mappings(path: String, mapped_mem: usize, mem_size: usize) -> Res fn test_linux_gate_mapping_id() -> Result<()> { let ppid = getppid().as_raw(); - let mut dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(ppid)?; + let mut dumper = PtraceDumper::new(ppid)?; let mut found_linux_gate = false; for mut mapping in dumper.mappings.clone() { if mapping.name.as_deref() == Some(LINUX_GATE_LIBRARY_NAME) { found_linux_gate = true; dumper.suspend_threads()?; - let id = LinuxPtraceDumper::elf_identifier_for_mapping(&mut mapping, ppid)?; + let id = PtraceDumper::elf_identifier_for_mapping(&mut mapping, ppid)?; test!(!id.is_empty(), "id-vec is empty")?; test!(id.iter().any(|&x| x > 0), "all id elements are 0")?; dumper.resume_threads()?; @@ -138,7 +140,7 @@ fn test_linux_gate_mapping_id() -> Result<()> { fn test_mappings_include_linux_gate() -> Result<()> { let ppid = getppid().as_raw(); - let dumper = linux_ptrace_dumper::LinuxPtraceDumper::new(ppid)?; + let dumper = PtraceDumper::new(ppid)?; let linux_gate_loc = dumper.auxv[&AT_SYSINFO_EHDR]; test!(linux_gate_loc != 0, "linux_gate_loc == 0")?; let mut found_linux_gate = false; diff --git a/src/lib.rs b/src/lib.rs index 5c60acc8..de193a2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,12 @@ #![allow(unsafe_code)] -#[cfg(target_os = "android")] -mod android; -pub mod app_memory; -mod auxv_reader; -pub mod crash_context; -mod dso_debug; -mod dumper_cpu_info; -pub mod errors; -pub mod linux_ptrace_dumper; -pub mod maps_reader; +cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "android"))] { + mod linux; + + pub use linux::*; + } +} + pub mod minidump_cpu; pub mod minidump_format; -pub mod minidump_writer; -mod sections; -pub mod thread_info; - -pub use maps_reader::LINUX_GATE_LIBRARY_NAME; diff --git a/src/linux.rs b/src/linux.rs new file mode 100644 index 00000000..3e9dde8a --- /dev/null +++ b/src/linux.rs @@ -0,0 +1,15 @@ +#[cfg(target_os = "android")] +mod android; +pub mod app_memory; +mod auxv_reader; +pub mod crash_context; +mod dso_debug; +mod dumper_cpu_info; +pub mod errors; +pub mod maps_reader; +pub mod minidump_writer; +pub mod ptrace_dumper; +mod sections; +pub mod thread_info; + +pub use maps_reader::LINUX_GATE_LIBRARY_NAME; diff --git a/src/android.rs b/src/linux/android.rs similarity index 100% rename from src/android.rs rename to src/linux/android.rs diff --git a/src/app_memory.rs b/src/linux/app_memory.rs similarity index 100% rename from src/app_memory.rs rename to src/linux/app_memory.rs diff --git a/src/auxv_reader.rs b/src/linux/auxv_reader.rs similarity index 100% rename from src/auxv_reader.rs rename to src/linux/auxv_reader.rs diff --git a/src/crash_context/crash_context_aarch64.rs b/src/linux/crash_context/crash_context_aarch64.rs similarity index 100% rename from src/crash_context/crash_context_aarch64.rs rename to src/linux/crash_context/crash_context_aarch64.rs diff --git a/src/crash_context/crash_context_arm.rs b/src/linux/crash_context/crash_context_arm.rs similarity index 100% rename from src/crash_context/crash_context_arm.rs rename to src/linux/crash_context/crash_context_arm.rs diff --git a/src/crash_context/crash_context_mips.rs b/src/linux/crash_context/crash_context_mips.rs similarity index 100% rename from src/crash_context/crash_context_mips.rs rename to src/linux/crash_context/crash_context_mips.rs diff --git a/src/crash_context/crash_context_x86.rs b/src/linux/crash_context/crash_context_x86.rs similarity index 100% rename from src/crash_context/crash_context_x86.rs rename to src/linux/crash_context/crash_context_x86.rs diff --git a/src/crash_context/crash_context_x86_64.rs b/src/linux/crash_context/crash_context_x86_64.rs similarity index 100% rename from src/crash_context/crash_context_x86_64.rs rename to src/linux/crash_context/crash_context_x86_64.rs diff --git a/src/crash_context/mod.rs b/src/linux/crash_context/mod.rs similarity index 100% rename from src/crash_context/mod.rs rename to src/linux/crash_context/mod.rs diff --git a/src/dso_debug.rs b/src/linux/dso_debug.rs similarity index 92% rename from src/dso_debug.rs rename to src/linux/dso_debug.rs index 781c34ab..d724cc04 100644 --- a/src/dso_debug.rs +++ b/src/linux/dso_debug.rs @@ -1,11 +1,13 @@ -use crate::auxv_reader::AuxvType; -use crate::errors::SectionDsoDebugError; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::minidump_format::*; -use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}; -use libc; -use std::collections::HashMap; -use std::io::Cursor; +use crate::{ + linux::{ + auxv_reader::AuxvType, + errors::SectionDsoDebugError, + ptrace_dumper::PtraceDumper, + sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}, + }, + minidump_format::*, +}; +use std::{collections::HashMap, io::Cursor}; type Result = std::result::Result; @@ -95,7 +97,7 @@ pub fn write_dso_debug_stream( .get(&at_phdr) .ok_or(SectionDsoDebugError::CouldNotFind("AT_PHDR in auxv"))? as usize; - let ph = LinuxPtraceDumper::copy_from_process( + let ph = PtraceDumper::copy_from_process( blamed_thread, phdr as *mut libc::c_void, SIZEOF_PHDR * phnum_max, @@ -145,7 +147,7 @@ pub fn write_dso_debug_stream( // DSOs loaded into the program. If this information is indeed available, // dump it to a MD_LINUX_DSO_DEBUG stream. loop { - let dyn_data = LinuxPtraceDumper::copy_from_process( + let dyn_data = PtraceDumper::copy_from_process( blamed_thread, (dyn_addr as usize + dynamic_length) as *mut libc::c_void, dyn_size, @@ -178,7 +180,7 @@ pub fn write_dso_debug_stream( // See for a more detailed discussion of the how the dynamic // loader communicates with debuggers. - let debug_entry_data = LinuxPtraceDumper::copy_from_process( + let debug_entry_data = PtraceDumper::copy_from_process( blamed_thread, r_debug as *mut libc::c_void, std::mem::size_of::(), @@ -193,7 +195,7 @@ pub fn write_dso_debug_stream( let mut dso_vec = Vec::new(); let mut curr_map = debug_entry.r_map; while curr_map != 0 { - let link_map_data = LinuxPtraceDumper::copy_from_process( + let link_map_data = PtraceDumper::copy_from_process( blamed_thread, curr_map as *mut libc::c_void, std::mem::size_of::(), @@ -219,7 +221,7 @@ pub fn write_dso_debug_stream( for (idx, map) in dso_vec.iter().enumerate() { let mut filename = String::new(); if map.l_name > 0 { - let filename_data = LinuxPtraceDumper::copy_from_process( + let filename_data = PtraceDumper::copy_from_process( blamed_thread, map.l_name as *mut libc::c_void, 256, @@ -258,7 +260,7 @@ pub fn write_dso_debug_stream( }; dirent.location.data_size += dynamic_length as u32; - let dso_debug_data = LinuxPtraceDumper::copy_from_process( + let dso_debug_data = PtraceDumper::copy_from_process( blamed_thread, dyn_addr as *mut libc::c_void, dynamic_length, diff --git a/src/dumper_cpu_info/mod.rs b/src/linux/dumper_cpu_info.rs similarity index 57% rename from src/dumper_cpu_info/mod.rs rename to src/linux/dumper_cpu_info.rs index 248ae4c2..80902b62 100644 --- a/src/dumper_cpu_info/mod.rs +++ b/src/linux/dumper_cpu_info.rs @@ -1,20 +1,30 @@ -#[cfg(any( - target_arch = "x86_64", - target_arch = "x86", - target_arch = "mips", - target_arch = "mips64" -))] -#[path = "cpu_info_x86_mips.rs"] -pub mod imp; -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -#[path = "cpu_info_arm.rs"] -pub mod imp; +cfg_if::cfg_if! { + if #[cfg(any( + target_arch = "x86_64", + target_arch = "x86", + target_arch = "mips", + target_arch = "mips64" + ))] + { + pub mod x86_mips; + pub use x86_mips as imp; + } else if #[cfg(any( + target_arch = "arm", + target_arch = "aarch64", + ))] + { + pub mod arm; + pub use arm as imp; + } +} 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::{ + errors::MemoryWriterError, + linux::sections::write_string_to_location, + minidump_format::{MDOSPlatform, MDRawSystemInfo}, +}; use nix::sys::utsname::uname; use std::io::Cursor; diff --git a/src/dumper_cpu_info/cpu_info_arm.rs b/src/linux/dumper_cpu_info/arm.rs similarity index 100% rename from src/dumper_cpu_info/cpu_info_arm.rs rename to src/linux/dumper_cpu_info/arm.rs diff --git a/src/dumper_cpu_info/cpu_info_x86_mips.rs b/src/linux/dumper_cpu_info/x86_mips.rs similarity index 100% rename from src/dumper_cpu_info/cpu_info_x86_mips.rs rename to src/linux/dumper_cpu_info/x86_mips.rs diff --git a/src/errors.rs b/src/linux/errors.rs similarity index 98% rename from src/errors.rs rename to src/linux/errors.rs index 4a540916..e35e10b0 100644 --- a/src/errors.rs +++ b/src/linux/errors.rs @@ -1,6 +1,4 @@ -use crate::maps_reader::MappingInfo; -use crate::thread_info::Pid; -use goblin; +use crate::{maps_reader::MappingInfo, thread_info::Pid}; use thiserror::Error; #[derive(Debug, Error)] @@ -11,6 +9,7 @@ pub enum InitError { NoAuxvEntryFound(Pid), #[error("crash thread does not reference principal mapping")] PrincipalMappingNotReferenced, + #[cfg(target_os = "android")] #[error("Failed Android specific late init")] AndroidLateInitError(#[from] AndroidError), } @@ -78,6 +77,7 @@ pub enum ThreadInfoError { InvalidProcStatusFile(Pid, String), } +#[cfg(target_os = "android")] #[derive(Debug, Error)] pub enum AndroidError { #[error("Failed to copy memory from process")] diff --git a/src/maps_reader.rs b/src/linux/maps_reader.rs similarity index 98% rename from src/maps_reader.rs rename to src/linux/maps_reader.rs index f81f67de..99bfe6a1 100644 --- a/src/maps_reader.rs +++ b/src/linux/maps_reader.rs @@ -1,12 +1,8 @@ -use crate::auxv_reader::AuxvType; -use crate::errors::MapsReaderError; -use crate::thread_info::Pid; +use crate::linux::{auxv_reader::AuxvType, errors::MapsReaderError, thread_info::Pid}; use byteorder::{NativeEndian, ReadBytesExt}; use goblin::elf; use memmap2::{Mmap, MmapOptions}; -use std::fs::File; -use std::mem::size_of; -use std::path::PathBuf; +use std::{fs::File, mem::size_of, path::PathBuf}; pub const LINUX_GATE_LIBRARY_NAME: &str = "linux-gate.so"; pub const DELETED_SUFFIX: &str = " (deleted)"; @@ -57,6 +53,7 @@ pub enum MappingInfoParsingResult { Success(MappingInfo), } +#[inline] fn is_mapping_a_path(pathname: Option<&str>) -> bool { match pathname { Some(x) => x.contains('/'), @@ -300,7 +297,6 @@ impl MappingInfo { pub fn get_mapping_effective_name_and_path(&self) -> Result<(String, String)> { let mut file_path = self.name.clone().unwrap_or_default(); - let file_name; // Tools such as minidump_stackwalk use the name of the module to look up // symbols produced by dump_syms. dump_syms will prefer to use a module's @@ -313,8 +309,7 @@ impl MappingInfo { Err(_) => { // file_path := /path/to/libname.so // file_name := libname.so - let split: Vec<_> = file_path.rsplitn(2, '/').collect(); - file_name = split.first().unwrap().to_string(); + let file_name = file_path.rsplitn(2, '/').next().unwrap().to_owned(); return Ok((file_path, file_name)); } }; diff --git a/src/minidump_writer.rs b/src/linux/minidump_writer.rs similarity index 96% rename from src/minidump_writer.rs rename to src/linux/minidump_writer.rs index b9805470..d83dd20a 100644 --- a/src/minidump_writer.rs +++ b/src/linux/minidump_writer.rs @@ -1,13 +1,15 @@ use crate::{ - app_memory::AppMemoryList, - crash_context::{CpuContext, CrashContext}, - dso_debug, - errors::{FileWriterError, InitError, MemoryWriterError, WriterError}, - linux_ptrace_dumper::LinuxPtraceDumper, - maps_reader::{MappingInfo, MappingList}, + linux::{ + app_memory::AppMemoryList, + crash_context::{CpuContext, CrashContext}, + dso_debug, + errors::{FileWriterError, InitError, MemoryWriterError, WriterError}, + maps_reader::{MappingInfo, MappingList}, + ptrace_dumper::PtraceDumper, + sections::*, + thread_info::Pid, + }, minidump_format::*, - sections::*, - thread_info::Pid, }; use std::io::{Cursor, Read, Seek, SeekFrom, Write}; @@ -185,7 +187,7 @@ impl MinidumpWriter { /// Generates a minidump and writes to the destination provided. Returns the in-memory /// version of the minidump as well. pub fn dump(&mut self, destination: &mut (impl Write + Seek)) -> Result> { - let mut dumper = LinuxPtraceDumper::new(self.process_id)?; + let mut dumper = PtraceDumper::new(self.process_id)?; dumper.suspend_threads()?; dumper.late_init()?; @@ -209,7 +211,7 @@ impl MinidumpWriter { Ok(buffer.into_inner()) } - fn crash_thread_references_principal_mapping(&self, dumper: &LinuxPtraceDumper) -> bool { + fn crash_thread_references_principal_mapping(&self, dumper: &PtraceDumper) -> bool { if self.crash_context.is_none() || self.principal_mapping.is_none() { return false; } @@ -244,7 +246,7 @@ impl MinidumpWriter { return false; } }; - let stack_copy = match LinuxPtraceDumper::copy_from_process( + let stack_copy = match PtraceDumper::copy_from_process( self.blamed_thread, stack_ptr as *mut libc::c_void, stack_len, @@ -265,7 +267,7 @@ impl MinidumpWriter { fn generate_dump( &mut self, buffer: &mut DumpBuf, - dumper: &mut LinuxPtraceDumper, + dumper: &mut PtraceDumper, destination: &mut (impl Write + Seek), ) -> Result<()> { // A minidump file contains a number of tagged streams. This is the number diff --git a/src/linux_ptrace_dumper.rs b/src/linux/ptrace_dumper.rs similarity index 98% rename from src/linux_ptrace_dumper.rs rename to src/linux/ptrace_dumper.rs index 0b5c4242..a33d023a 100644 --- a/src/linux_ptrace_dumper.rs +++ b/src/linux/ptrace_dumper.rs @@ -1,13 +1,15 @@ // use libc::c_void; #[cfg(target_os = "android")] -use crate::android::late_process_mappings; +use crate::linux::android::late_process_mappings; use crate::{ - auxv_reader::{AuxvType, ProcfsAuxvIter}, - errors::{DumperError, InitError, ThreadInfoError}, - maps_reader::{MappingInfo, MappingInfoParsingResult, DELETED_SUFFIX}, + linux::{ + auxv_reader::{AuxvType, ProcfsAuxvIter}, + errors::{DumperError, InitError, ThreadInfoError}, + maps_reader::{MappingInfo, MappingInfoParsingResult, DELETED_SUFFIX}, + thread_info::{Pid, ThreadInfo}, + LINUX_GATE_LIBRARY_NAME, + }, minidump_format::MDGUID, - thread_info::{Pid, ThreadInfo}, - LINUX_GATE_LIBRARY_NAME, }; use goblin::elf; use nix::sys::{ptrace, wait}; @@ -26,7 +28,7 @@ pub struct Thread { } #[derive(Debug)] -pub struct LinuxPtraceDumper { +pub struct PtraceDumper { pub pid: Pid, threads_suspended: bool, pub threads: Vec, @@ -39,18 +41,18 @@ pub const AT_SYSINFO_EHDR: u32 = 33; #[cfg(target_pointer_width = "64")] pub const AT_SYSINFO_EHDR: u64 = 33; -impl Drop for LinuxPtraceDumper { +impl Drop for PtraceDumper { fn drop(&mut self) { // Always try to resume all threads (e.g. in case of error) let _ = self.resume_threads(); } } -impl LinuxPtraceDumper { +impl PtraceDumper { /// Constructs a dumper for extracting information of a given process /// with a process ID of |pid|. pub fn new(pid: Pid) -> Result { - let mut dumper = LinuxPtraceDumper { + let mut dumper = Self { pid, threads_suspended: false, threads: Vec::new(), diff --git a/src/sections/mod.rs b/src/linux/sections.rs similarity index 97% rename from src/sections/mod.rs rename to src/linux/sections.rs index 7d56d7be..9e29c96b 100644 --- a/src/sections/mod.rs +++ b/src/linux/sections.rs @@ -6,8 +6,14 @@ pub mod systeminfo_stream; pub mod thread_list_stream; pub mod thread_names_stream; -use crate::errors::MemoryWriterError; -use crate::minidump_format::*; +use crate::{ + errors::{self, MemoryWriterError}, + linux::{ + minidump_writer::{self, DumpBuf, MinidumpWriter}, + ptrace_dumper::PtraceDumper, + }, + minidump_format::*, +}; use std::io::{Cursor, Write}; type Result = std::result::Result; diff --git a/src/sections/app_memory.rs b/src/linux/sections/app_memory.rs similarity index 54% rename from src/sections/app_memory.rs rename to src/linux/sections/app_memory.rs index cbc28ba2..36efcd4a 100644 --- a/src/sections/app_memory.rs +++ b/src/linux/sections/app_memory.rs @@ -1,15 +1,12 @@ -use crate::errors::SectionAppMemoryError; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::minidump_format::*; -use crate::minidump_writer::{DumpBuf, MinidumpWriter}; -use crate::sections::MemoryArrayWriter; - -type Result = std::result::Result; +use super::*; /// Write application-provided memory regions. -pub fn write(config: &mut MinidumpWriter, buffer: &mut DumpBuf) -> Result<()> { +pub fn write( + config: &mut MinidumpWriter, + buffer: &mut DumpBuf, +) -> std::result::Result<(), crate::linux::errors::SectionAppMemoryError> { for app_memory in &config.app_memory { - let data_copy = LinuxPtraceDumper::copy_from_process( + let data_copy = PtraceDumper::copy_from_process( config.blamed_thread, app_memory.ptr as *mut libc::c_void, app_memory.length, diff --git a/src/sections/exception_stream.rs b/src/linux/sections/exception_stream.rs similarity index 93% rename from src/sections/exception_stream.rs rename to src/linux/sections/exception_stream.rs index d3c49ece..0e912ec3 100644 --- a/src/sections/exception_stream.rs +++ b/src/linux/sections/exception_stream.rs @@ -1,9 +1,5 @@ -use crate::errors::SectionExceptionStreamError; -use crate::minidump_format::*; -use crate::minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}; -use crate::sections::MemoryWriter; - -type Result = std::result::Result; +use super::*; +use minidump_writer::CrashingThreadContext; #[allow(non_camel_case_types, unused)] #[repr(u32)] @@ -45,7 +41,10 @@ enum MDExceptionCodeLinux { dump requested. */ } -pub fn write(config: &mut MinidumpWriter, buffer: &mut DumpBuf) -> Result { +pub fn write( + config: &mut MinidumpWriter, + buffer: &mut DumpBuf, +) -> std::result::Result { let exception = if let Some(context) = &config.crash_context { let sig_addr; #[cfg(target_arch = "arm")] diff --git a/src/sections/mappings.rs b/src/linux/sections/mappings.rs similarity index 84% rename from src/sections/mappings.rs rename to src/linux/sections/mappings.rs index d95741d0..42dde91e 100644 --- a/src/sections/mappings.rs +++ b/src/linux/sections/mappings.rs @@ -1,11 +1,14 @@ -use crate::errors::SectionMappingsError; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::maps_reader::MappingInfo; -use crate::minidump_format::*; -use crate::minidump_writer::{DumpBuf, MinidumpWriter}; -use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}; +use super::*; +use crate::linux::maps_reader::MappingInfo; -type Result = std::result::Result; +// use crate::errors::SectionMappingsError; +// use crate::linux_ptrace_dumper::LinuxPtraceDumper; +// use crate::maps_reader::MappingInfo; +// use crate::minidump_format::*; +// use crate::minidump_writer::{DumpBuf, MinidumpWriter}; +// use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}; + +type Result = std::result::Result; /// Write information about the mappings in effect. Because we are using the /// minidump format, the information about the mappings is pretty limited. @@ -14,7 +17,7 @@ type Result = std::result::Result; pub fn write( config: &mut MinidumpWriter, buffer: &mut DumpBuf, - dumper: &mut LinuxPtraceDumper, + dumper: &mut PtraceDumper, ) -> Result { let mut modules = Vec::new(); @@ -92,7 +95,7 @@ fn fill_raw_module( let (file_path, _) = mapping .get_mapping_effective_name_and_path() - .map_err(|e| SectionMappingsError::GetEffectivePathError(mapping.clone(), e))?; + .map_err(|e| errors::SectionMappingsError::GetEffectivePathError(mapping.clone(), e))?; let name_header = write_string_to_location(buffer, &file_path)?; Ok(MDRawModule { diff --git a/src/sections/memory_list_stream.rs b/src/linux/sections/memory_list_stream.rs similarity index 69% rename from src/sections/memory_list_stream.rs rename to src/linux/sections/memory_list_stream.rs index 4f090831..572049ea 100644 --- a/src/sections/memory_list_stream.rs +++ b/src/linux/sections/memory_list_stream.rs @@ -1,9 +1,6 @@ -use crate::errors::SectionMemListError; -use crate::minidump_format::*; -use crate::minidump_writer::{DumpBuf, MinidumpWriter}; -use crate::sections::{MemoryArrayWriter, MemoryWriter}; +use super::*; -type Result = std::result::Result; +type Result = std::result::Result; pub fn write(config: &mut MinidumpWriter, buffer: &mut DumpBuf) -> Result { let list_header = diff --git a/src/sections/systeminfo_stream.rs b/src/linux/sections/systeminfo_stream.rs similarity index 63% rename from src/sections/systeminfo_stream.rs rename to src/linux/sections/systeminfo_stream.rs index dabd7793..18af398d 100644 --- a/src/sections/systeminfo_stream.rs +++ b/src/linux/sections/systeminfo_stream.rs @@ -1,10 +1,7 @@ -use crate::dumper_cpu_info::{write_cpu_information, write_os_information}; -use crate::errors::SectionSystemInfoError; -use crate::minidump_format::*; -use crate::minidump_writer::DumpBuf; -use crate::sections::MemoryWriter; +use super::*; +use crate::linux::dumper_cpu_info::{write_cpu_information, write_os_information}; -type Result = std::result::Result; +type Result = std::result::Result; pub fn write(buffer: &mut DumpBuf) -> Result { let mut info_section = MemoryWriter::::alloc(buffer)?; diff --git a/src/sections/thread_list_stream.rs b/src/linux/sections/thread_list_stream.rs similarity index 93% rename from src/sections/thread_list_stream.rs rename to src/linux/sections/thread_list_stream.rs index f4cb3c07..a5646723 100644 --- a/src/sections/thread_list_stream.rs +++ b/src/linux/sections/thread_list_stream.rs @@ -1,15 +1,20 @@ +// use crate::{ +// crash_context::CpuContext, +// errors::SectionThreadListError, +// linux_ptrace_dumper::LinuxPtraceDumper, +// minidump_cpu::RawContextCPU, +// minidump_format::*, +// minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}, +// sections::{MemoryArrayWriter, MemoryWriter}, +// }; +use super::*; use crate::{ - crash_context::CpuContext, - errors::SectionThreadListError, - linux_ptrace_dumper::LinuxPtraceDumper, - minidump_cpu::RawContextCPU, - minidump_format::*, - minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}, - sections::{MemoryArrayWriter, MemoryWriter}, + linux::crash_context::CpuContext, minidump_cpu::RawContextCPU, + minidump_writer::CrashingThreadContext, }; use std::io::Write; -type Result = std::result::Result; +type Result = std::result::Result; // The following kLimit* constants are for when minidump_size_limit_ is set // and the minidump size might exceed it. @@ -36,7 +41,7 @@ enum MaxStackLen { pub fn write( config: &mut MinidumpWriter, buffer: &mut DumpBuf, - dumper: &LinuxPtraceDumper, + dumper: &PtraceDumper, ) -> Result { let num_threads = dumper.threads.len(); // Memory looks like this: @@ -118,7 +123,7 @@ pub fn write( ip_memory_d.memory.data_size = (end_of_range - ip_memory_d.start_of_memory_range) as u32; - let memory_copy = LinuxPtraceDumper::copy_from_process( + let memory_copy = PtraceDumper::copy_from_process( thread.thread_id as i32, ip_memory_d.start_of_memory_range as *mut libc::c_void, ip_memory_d.memory.data_size as usize, @@ -180,7 +185,7 @@ pub fn write( fn fill_thread_stack( config: &mut MinidumpWriter, buffer: &mut DumpBuf, - dumper: &LinuxPtraceDumper, + dumper: &PtraceDumper, thread: &mut MDRawThread, instruction_ptr: usize, stack_ptr: usize, @@ -205,7 +210,7 @@ fn fill_thread_stack( } } - let mut stack_bytes = LinuxPtraceDumper::copy_from_process( + let mut stack_bytes = PtraceDumper::copy_from_process( thread.thread_id.try_into()?, stack as *mut libc::c_void, stack_len, diff --git a/src/sections/thread_names_stream.rs b/src/linux/sections/thread_names_stream.rs similarity index 70% rename from src/sections/thread_names_stream.rs rename to src/linux/sections/thread_names_stream.rs index 9a5526dc..51b23435 100644 --- a/src/sections/thread_names_stream.rs +++ b/src/linux/sections/thread_names_stream.rs @@ -1,13 +1,8 @@ -use crate::errors::SectionThreadNamesError; -use crate::linux_ptrace_dumper::LinuxPtraceDumper; -use crate::minidump_format::*; -use crate::minidump_writer::DumpBuf; -use crate::sections::write_string_to_location; -use crate::sections::{MemoryArrayWriter, MemoryWriter}; +use super::*; -type Result = std::result::Result; +type Result = std::result::Result; -pub fn write(buffer: &mut DumpBuf, dumper: &LinuxPtraceDumper) -> Result { +pub fn write(buffer: &mut DumpBuf, dumper: &PtraceDumper) -> Result { // Only count threads that have a name let num_threads = dumper.threads.iter().filter(|t| t.name.is_some()).count(); // Memory looks like this: diff --git a/src/thread_info/mod.rs b/src/linux/thread_info.rs similarity index 86% rename from src/thread_info/mod.rs rename to src/linux/thread_info.rs index 60f4d328..79cedbbd 100644 --- a/src/thread_info/mod.rs +++ b/src/linux/thread_info.rs @@ -1,35 +1,29 @@ use crate::errors::ThreadInfoError; -use nix::errno::Errno; -use nix::sys::ptrace; -use nix::unistd; -use std::io::{self, BufRead}; -use std::path; +use nix::{errno::Errno, sys::ptrace, unistd}; +use std::{ + io::{self, BufRead}, + path, +}; type Result = std::result::Result; pub type Pid = i32; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[path = "thread_info_x86.rs"] -mod imp; -#[cfg(target_arch = "arm")] -#[path = "thread_info_arm.rs"] -mod imp; -#[cfg(target_arch = "aarch64")] -#[path = "thread_info_aarch64.rs"] -mod imp; -#[cfg(target_arch = "mips")] -#[path = "thread_info_mips.rs"] -mod imp; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub type ThreadInfo = imp::ThreadInfoX86; -#[cfg(target_arch = "arm")] -pub type ThreadInfo = imp::ThreadInfoArm; -#[cfg(target_arch = "aarch64")] -pub type ThreadInfo = imp::ThreadInfoAarch64; -#[cfg(target_arch = "mips")] -pub type ThreadInfo = imp::ThreadInfoMips; +cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + mod x86; + pub type ThreadInfo = x86::ThreadInfoX86; + } else if #[cfg(target_arch = "arm")] { + mod arm; + pub type ThreadInfo = arm::ThreadInfoArm; + } else if #[cfg(target_arch = "aarch64")] { + mod aarch64; + pub type ThreadInfo = aarch64::ThreadInfoAarch64; + } else if #[cfg(target_arch = "mips")] { + mod mips; + pub type ThreadInfo = mips::ThreadInfoMips; + } +} #[derive(Debug)] #[allow(non_camel_case_types)] diff --git a/src/thread_info/thread_info_aarch64.rs b/src/linux/thread_info/aarch64.rs similarity index 100% rename from src/thread_info/thread_info_aarch64.rs rename to src/linux/thread_info/aarch64.rs diff --git a/src/thread_info/thread_info_arm.rs b/src/linux/thread_info/arm.rs similarity index 100% rename from src/thread_info/thread_info_arm.rs rename to src/linux/thread_info/arm.rs diff --git a/src/thread_info/thread_info_mips.rs b/src/linux/thread_info/mips.rs similarity index 100% rename from src/thread_info/thread_info_mips.rs rename to src/linux/thread_info/mips.rs diff --git a/src/thread_info/thread_info_x86.rs b/src/linux/thread_info/x86.rs similarity index 100% rename from src/thread_info/thread_info_x86.rs rename to src/linux/thread_info/x86.rs diff --git a/src/minidump_cpu.rs b/src/minidump_cpu.rs new file mode 100644 index 00000000..104553eb --- /dev/null +++ b/src/minidump_cpu.rs @@ -0,0 +1,25 @@ +cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + pub mod amd64; + pub use amd64 as imp; + pub type RawContextCPU = amd64::MDRawContextAMD64; + } else if #[cfg(target_arch = "x86")] { + pub mod x86; + pub use x86 as imp; + pub type RawContextCPU = amd64::MDRawContextX86; + } else if #[cfg(target_arch = "arm")] { + pub mod arm; + pub use arm as imp; + pub type RawContextCPU = arm::MDRawContextARM; + } else if #[cfg(target_arch = "aarch64")] { + pub mod aarch64; + pub use aarch64 as imp; + + compile_error!("flesh me out"); + //pub type RawContextCPU = aarch64::MDRawContextX86; + } else if #[cfg(target_arch = "mips")] { + compile_error!("flesh me out"); + } else { + compile_error!("unsupported target architecture"); + } +} diff --git a/src/minidump_cpu/minidump_cpu_aarch64.rs b/src/minidump_cpu/aarch64.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_aarch64.rs rename to src/minidump_cpu/aarch64.rs diff --git a/src/minidump_cpu/minidump_cpu_amd64.rs b/src/minidump_cpu/amd64.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_amd64.rs rename to src/minidump_cpu/amd64.rs diff --git a/src/minidump_cpu/minidump_cpu_arm.rs b/src/minidump_cpu/arm.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_arm.rs rename to src/minidump_cpu/arm.rs diff --git a/src/minidump_cpu/minidump_cpu_mips.rs b/src/minidump_cpu/mips.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_mips.rs rename to src/minidump_cpu/mips.rs diff --git a/src/minidump_cpu/mod.rs b/src/minidump_cpu/mod.rs deleted file mode 100644 index ebce0ad5..00000000 --- a/src/minidump_cpu/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -#[cfg(target_arch = "x86_64")] -#[path = "minidump_cpu_amd64.rs"] -pub mod imp; -#[cfg(target_arch = "x86")] -#[path = "minidump_cpu_x86.rs"] -pub mod imp; -#[cfg(target_arch = "arm")] -#[path = "minidump_cpu_arm.rs"] -pub mod imp; -#[cfg(target_arch = "aarch64")] -#[path = "minidump_cpu_aarch64.rs"] -pub mod imp; -#[cfg(target_arch = "mips")] -#[path = "minidump_cpu_mips.rs"] -pub mod imp; - -#[cfg(target_arch = "x86_64")] -pub type RawContextCPU = imp::MDRawContextAMD64; -#[cfg(target_arch = "x86")] -pub type RawContextCPU = imp::MDRawContextX86; -#[cfg(target_arch = "arm")] -pub type RawContextCPU = imp::MDRawContextARM; -#[cfg(target_arch = "aarch64")] -pub type RawContextCPU = imp::MDRawContextX86; -#[cfg(target_arch = "mips")] -pub type RawContextCPU = i32; diff --git a/src/minidump_cpu/minidump_cpu_ppc.rs b/src/minidump_cpu/ppc.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_ppc.rs rename to src/minidump_cpu/ppc.rs diff --git a/src/minidump_cpu/minidump_cpu_ppc64.rs b/src/minidump_cpu/ppc64.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_ppc64.rs rename to src/minidump_cpu/ppc64.rs diff --git a/src/minidump_cpu/minidump_cpu_sparc.rs b/src/minidump_cpu/sparc.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_sparc.rs rename to src/minidump_cpu/sparc.rs diff --git a/src/minidump_cpu/minidump_cpu_x86.rs b/src/minidump_cpu/x86.rs similarity index 100% rename from src/minidump_cpu/minidump_cpu_x86.rs rename to src/minidump_cpu/x86.rs diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index 9cfc37e4..a235ae85 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -1,12 +1,12 @@ use minidump::*; use minidump_common::format::{GUID, MINIDUMP_STREAM_TYPE::*}; -use minidump_writer_linux::{ +use minidump_writer::{ app_memory::AppMemory, crash_context::CrashContext, errors::*, - linux_ptrace_dumper::LinuxPtraceDumper, maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}, minidump_writer::MinidumpWriter, + ptrace_dumper::PtraceDumper, thread_info::Pid, }; use nix::{errno::Errno, sys::signal::Signal}; @@ -448,7 +448,7 @@ fn test_with_deleted_binary() { let pid = child.id() as i32; - let build_id = LinuxPtraceDumper::elf_file_identifier_from_mapped_file(&mem_slice) + let build_id = PtraceDumper::elf_file_identifier_from_mapped_file(&mem_slice) .expect("Failed to get build_id"); let guid = GUID { diff --git a/tests/ptrace_dumper.rs b/tests/ptrace_dumper.rs index d2002686..8d6fb648 100644 --- a/tests/ptrace_dumper.rs +++ b/tests/ptrace_dumper.rs @@ -1,4 +1,4 @@ -use minidump_writer_linux::linux_ptrace_dumper; +use minidump_writer::ptrace_dumper; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use nix::sys::signal::Signal; use std::io::{BufRead, BufReader}; @@ -25,8 +25,7 @@ fn test_thread_list_from_parent() { let num_of_threads = 5; let mut child = start_child_and_wait_for_threads(num_of_threads); let pid = child.id() as i32; - let mut dumper = - linux_ptrace_dumper::LinuxPtraceDumper::new(pid).expect("Couldn't init dumper"); + let mut dumper = ptrace_dumper::PtraceDumper::new(pid).expect("Couldn't init dumper"); assert_eq!(dumper.threads.len(), num_of_threads); dumper.suspend_threads().expect("Could not suspend threads"); @@ -195,8 +194,7 @@ fn test_sanitize_stack_copy() { let heap_addr = usize::from_str_radix(output.next().unwrap().trim_start_matches("0x"), 16) .expect("unable to parse mmap_addr"); - let mut dumper = - linux_ptrace_dumper::LinuxPtraceDumper::new(pid).expect("Couldn't init dumper"); + let mut dumper = ptrace_dumper::PtraceDumper::new(pid).expect("Couldn't init dumper"); assert_eq!(dumper.threads.len(), num_of_threads); dumper.suspend_threads().expect("Could not suspend threads"); let thread_info = dumper From 7695c64b59e1d99f2ce1840586a6c43f79e0af2b Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Fri, 19 Nov 2021 06:41:45 +0100 Subject: [PATCH 08/21] Fixup crash_context --- .../mod.rs => crash_context.rs} | 25 ++++--------------- .../{crash_context_aarch64.rs => aarch64.rs} | 0 .../{crash_context_arm.rs => arm.rs} | 0 .../{crash_context_mips.rs => mips.rs} | 0 .../{crash_context_x86.rs => x86.rs} | 0 .../{crash_context_x86_64.rs => x86_64.rs} | 0 6 files changed, 5 insertions(+), 20 deletions(-) rename src/linux/{crash_context/mod.rs => crash_context.rs} (52%) rename src/linux/crash_context/{crash_context_aarch64.rs => aarch64.rs} (100%) rename src/linux/crash_context/{crash_context_arm.rs => arm.rs} (100%) rename src/linux/crash_context/{crash_context_mips.rs => mips.rs} (100%) rename src/linux/crash_context/{crash_context_x86.rs => x86.rs} (100%) rename src/linux/crash_context/{crash_context_x86_64.rs => x86_64.rs} (100%) diff --git a/src/linux/crash_context/mod.rs b/src/linux/crash_context.rs similarity index 52% rename from src/linux/crash_context/mod.rs rename to src/linux/crash_context.rs index 2dc37c08..8e68574b 100644 --- a/src/linux/crash_context/mod.rs +++ b/src/linux/crash_context.rs @@ -4,34 +4,19 @@ cfg_if::cfg_if! { if #[cfg(target_arch = "x86_64")] { - mod crash_context_x86_64; + mod x86_64; } else if #[cfg(target_arch = "x86")] { - mod crash_context_x86; + mod x86; } else if #[cfg(target_arch = "aarch64")] { - mod crash_context_aarch64; + mod aarch64; } else if #[cfg(target_arch = "arm")] { - mod crash_context_arm; + mod arm; } else if #[cfg(target_arch = "mips")] { - mod crash_context_mips; + mod mips; } } use crate::minidump_cpu::RawContextCPU; - -// #[cfg(target_arch = "aarch64")] -// pub type fpstate_t = libc::fpsimd_context; // Currently not part of libc! This will produce an error. -// #[cfg(not(any( -// target_arch = "aarch64", -// target_arch = "mips", -// target_arch = "arm-eabi" -// )))] -// #[cfg(target_arch = "x86")] -// #[allow(non_camel_case_types)] -// pub type fpstate_t = libc::_libc_fpstate; -// #[cfg(target_arch = "x86_64")] -// #[allow(non_camel_case_types)] -// pub type fpstate_t = libc::user_fpregs_struct; - pub use exception_handler::CrashContext; pub trait CpuContext { diff --git a/src/linux/crash_context/crash_context_aarch64.rs b/src/linux/crash_context/aarch64.rs similarity index 100% rename from src/linux/crash_context/crash_context_aarch64.rs rename to src/linux/crash_context/aarch64.rs diff --git a/src/linux/crash_context/crash_context_arm.rs b/src/linux/crash_context/arm.rs similarity index 100% rename from src/linux/crash_context/crash_context_arm.rs rename to src/linux/crash_context/arm.rs diff --git a/src/linux/crash_context/crash_context_mips.rs b/src/linux/crash_context/mips.rs similarity index 100% rename from src/linux/crash_context/crash_context_mips.rs rename to src/linux/crash_context/mips.rs diff --git a/src/linux/crash_context/crash_context_x86.rs b/src/linux/crash_context/x86.rs similarity index 100% rename from src/linux/crash_context/crash_context_x86.rs rename to src/linux/crash_context/x86.rs diff --git a/src/linux/crash_context/crash_context_x86_64.rs b/src/linux/crash_context/x86_64.rs similarity index 100% rename from src/linux/crash_context/crash_context_x86_64.rs rename to src/linux/crash_context/x86_64.rs From 6cd9fcab11500632ec3a4e8c5d64326c8b47eac8 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 25 Nov 2021 17:52:07 +0100 Subject: [PATCH 09/21] Show result of attach --- src/linux/ptrace_dumper.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/linux/ptrace_dumper.rs b/src/linux/ptrace_dumper.rs index a33d023a..80546777 100644 --- a/src/linux/ptrace_dumper.rs +++ b/src/linux/ptrace_dumper.rs @@ -65,6 +65,8 @@ impl PtraceDumper { // TODO: late_init for chromeos and android pub fn init(&mut self) -> Result<(), InitError> { + unsafe { println!("UID: {} GID: {}", libc::getuid(), libc::getgid()) }; + self.read_auxv()?; self.enumerate_threads()?; self.enumerate_mappings()?; @@ -162,7 +164,8 @@ impl PtraceDumper { // If the thread either disappeared before we could attach to it, or if // it was part of the seccomp sandbox's trusted code, it is OK to // silently drop it from the minidump. - self.threads.retain(|x| Self::suspend_thread(x.tid).is_ok()); + self.threads + .retain(|x| dbg!(Self::suspend_thread(x.tid)).is_ok()); if self.threads.is_empty() { Err(DumperError::SuspendNoThreadsLeft) From 2f70e45ee3cb57f6cb86de7eea4648cd042cef7d Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 9 Dec 2021 08:10:20 +0100 Subject: [PATCH 10/21] Revert debug code --- src/linux/ptrace_dumper.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/linux/ptrace_dumper.rs b/src/linux/ptrace_dumper.rs index 80546777..a33d023a 100644 --- a/src/linux/ptrace_dumper.rs +++ b/src/linux/ptrace_dumper.rs @@ -65,8 +65,6 @@ impl PtraceDumper { // TODO: late_init for chromeos and android pub fn init(&mut self) -> Result<(), InitError> { - unsafe { println!("UID: {} GID: {}", libc::getuid(), libc::getgid()) }; - self.read_auxv()?; self.enumerate_threads()?; self.enumerate_mappings()?; @@ -164,8 +162,7 @@ impl PtraceDumper { // If the thread either disappeared before we could attach to it, or if // it was part of the seccomp sandbox's trusted code, it is OK to // silently drop it from the minidump. - self.threads - .retain(|x| dbg!(Self::suspend_thread(x.tid)).is_ok()); + self.threads.retain(|x| Self::suspend_thread(x.tid).is_ok()); if self.threads.is_empty() { Err(DumperError::SuspendNoThreadsLeft) From 7e6f130a4a6a497c1d6ad823534bb726c232b6a9 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 9 Dec 2021 08:13:55 +0100 Subject: [PATCH 11/21] Remove commented out imports --- src/linux/sections/mappings.rs | 7 ------- src/linux/sections/thread_list_stream.rs | 9 --------- 2 files changed, 16 deletions(-) diff --git a/src/linux/sections/mappings.rs b/src/linux/sections/mappings.rs index 42dde91e..d15be725 100644 --- a/src/linux/sections/mappings.rs +++ b/src/linux/sections/mappings.rs @@ -1,13 +1,6 @@ use super::*; use crate::linux::maps_reader::MappingInfo; -// use crate::errors::SectionMappingsError; -// use crate::linux_ptrace_dumper::LinuxPtraceDumper; -// use crate::maps_reader::MappingInfo; -// use crate::minidump_format::*; -// use crate::minidump_writer::{DumpBuf, MinidumpWriter}; -// use crate::sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}; - type Result = std::result::Result; /// Write information about the mappings in effect. Because we are using the diff --git a/src/linux/sections/thread_list_stream.rs b/src/linux/sections/thread_list_stream.rs index a5646723..6d30e2c1 100644 --- a/src/linux/sections/thread_list_stream.rs +++ b/src/linux/sections/thread_list_stream.rs @@ -1,12 +1,3 @@ -// use crate::{ -// crash_context::CpuContext, -// errors::SectionThreadListError, -// linux_ptrace_dumper::LinuxPtraceDumper, -// minidump_cpu::RawContextCPU, -// minidump_format::*, -// minidump_writer::{CrashingThreadContext, DumpBuf, MinidumpWriter}, -// sections::{MemoryArrayWriter, MemoryWriter}, -// }; use super::*; use crate::{ linux::crash_context::CpuContext, minidump_cpu::RawContextCPU, From 786bc1fc628d9b4229965d3a554066386d4ef49c Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 9 Dec 2021 09:37:22 +0100 Subject: [PATCH 12/21] Prep for submodule --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c243f519..663761f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" [dependencies] byteorder = "1.3.2" cfg-if = "1.0" -exception-handler = { path = "../crash-handling/exception-handler" } +exception-handler = { path = "../exception-handler" } goblin = "0.4" libc = "0.2.74" memmap2 = "0.5" @@ -16,8 +16,8 @@ memoffset = "0.6" nix = "0.23" tempfile = "3.1.0" thiserror = "1.0.21" -uctx = { path = "../crash-handling/uctx" } [dev-dependencies] minidump = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } +uctx = { path = "../uctx" } From a8a0ab361ab5da0c647ea7a56adb4459265630e8 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 8 Mar 2022 10:37:44 +0100 Subject: [PATCH 13/21] Update goblin --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 663761f6..f4a281c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" byteorder = "1.3.2" cfg-if = "1.0" exception-handler = { path = "../exception-handler" } -goblin = "0.4" +goblin = "0.5" libc = "0.2.74" memmap2 = "0.5" memoffset = "0.6" From 03dfae420a44793e305af5c06c7e42521b2e4563 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 8 Mar 2022 10:37:51 +0100 Subject: [PATCH 14/21] Fix docs compilation --- src/linux/sections/exception_stream.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linux/sections/exception_stream.rs b/src/linux/sections/exception_stream.rs index 0e912ec3..da0b1d05 100644 --- a/src/linux/sections/exception_stream.rs +++ b/src/linux/sections/exception_stream.rs @@ -1,5 +1,5 @@ +use super::minidump_writer::CrashingThreadContext; use super::*; -use minidump_writer::CrashingThreadContext; #[allow(non_camel_case_types, unused)] #[repr(u32)] From 040769fd556e5cf9ab29e353e1d9a50723686dbf Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 8 Mar 2022 12:57:21 +0100 Subject: [PATCH 15/21] Fix clippy lints in tests --- src/linux/maps_reader.rs | 38 +++++++++++++++++++++----------------- tests/common/mod.rs | 2 +- tests/minidump_writer.rs | 5 +---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/linux/maps_reader.rs b/src/linux/maps_reader.rs index 99bfe6a1..fc54f3f4 100644 --- a/src/linux/maps_reader.rs +++ b/src/linux/maps_reader.rs @@ -418,10 +418,11 @@ mod tests { let (lines, linux_gate_loc) = get_lines_and_loc(); // Only /usr/bin/cat and [heap] for line in lines { - match MappingInfo::parse_from_line(&line, linux_gate_loc, mappings.last_mut()) { - Ok(MappingInfoParsingResult::Success(map)) => mappings.push(map), - Ok(MappingInfoParsingResult::SkipLine) => continue, - Err(_) => assert!(false), + match MappingInfo::parse_from_line(line, linux_gate_loc, mappings.last_mut()) + .expect("unexpected parse failure") + { + MappingInfoParsingResult::Success(map) => mappings.push(map), + MappingInfoParsingResult::SkipLine => continue, } } assert_eq!(mappings.len(), 23); @@ -434,10 +435,11 @@ mod tests { let (lines, linux_gate_loc) = get_lines_and_loc(); // Only /usr/bin/cat and [heap] for line in lines[0..=6].iter() { - match MappingInfo::parse_from_line(&line, linux_gate_loc, mappings.last_mut()) { - Ok(MappingInfoParsingResult::Success(map)) => mappings.push(map), - Ok(MappingInfoParsingResult::SkipLine) => continue, - Err(_) => assert!(false), + match MappingInfo::parse_from_line(line, linux_gate_loc, mappings.last_mut()) + .expect("unexpected parse failure") + { + MappingInfoParsingResult::Success(map) => mappings.push(map), + MappingInfoParsingResult::SkipLine => continue, } } @@ -575,10 +577,11 @@ mod tests { let linux_gate_loc = 0x7ffe091bf000; let mut mappings: Vec = Vec::new(); for line in lines { - match MappingInfo::parse_from_line(&line, linux_gate_loc, mappings.last_mut()) { - Ok(MappingInfoParsingResult::Success(map)) => mappings.push(map), - Ok(MappingInfoParsingResult::SkipLine) => continue, - Err(_) => assert!(false), + match MappingInfo::parse_from_line(line, linux_gate_loc, mappings.last_mut()) + .expect("unexpected parse failure") + { + MappingInfoParsingResult::Success(map) => mappings.push(map), + MappingInfoParsingResult::SkipLine => continue, } } assert_eq!(mappings.len(), 1); @@ -600,7 +603,7 @@ mod tests { let linux_gate_loc = 0x7ffe091bf000; let mut mappings: Vec = Vec::new(); for line in lines { - match MappingInfo::parse_from_line(&line, linux_gate_loc, mappings.last_mut()) { + match MappingInfo::parse_from_line(line, linux_gate_loc, mappings.last_mut()) { Ok(MappingInfoParsingResult::Success(map)) => mappings.push(map), Ok(MappingInfoParsingResult::SkipLine) => continue, Err(x) => panic!("{:?}", x), @@ -634,10 +637,11 @@ mod tests { let linux_gate_loc = 0x7ffe091bf000; let mut mappings: Vec = Vec::new(); for line in lines { - match MappingInfo::parse_from_line(&line, linux_gate_loc, mappings.last_mut()) { - Ok(MappingInfoParsingResult::Success(map)) => mappings.push(map), - Ok(MappingInfoParsingResult::SkipLine) => continue, - Err(_) => assert!(false), + match MappingInfo::parse_from_line(line, linux_gate_loc, mappings.last_mut()) + .expect("unexpected parse failure") + { + MappingInfoParsingResult::Success(map) => mappings.push(map), + MappingInfoParsingResult::SkipLine => continue, } } assert_eq!(mappings.len(), 4); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 3775bcc3..bb262601 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -86,7 +86,7 @@ pub fn start_child_and_return(command: &str) -> Child { .arg("--bin") .arg("test") .arg("--") - .arg(format!("{}", command)) + .arg(command) .stdout(Stdio::piped()) .spawn() .expect("failed to execute child"); diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index a235ae85..3e568fb2 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -615,10 +615,7 @@ fn test_sanitized_stacks_helper(context: Context) { let start = mem.rva as usize; let end = (mem.rva + mem.data_size) as usize; let slice = &dump_array.as_slice()[start..end]; - assert!(slice - .windows(defaced.len()) - .position(|window| window == defaced) - .is_some()); + assert!(slice.windows(defaced.len()).any(|window| window == defaced)); } } From 1101eff38f8223349178cb30151da84931031080 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 8 Mar 2022 14:37:09 +0100 Subject: [PATCH 16/21] Cleanup more lints --- src/lib.rs | 79 ++++++++++++++++++ src/linux/crash_context/x86_64.rs | 13 +-- src/linux/dso_debug.rs | 2 +- src/linux/dumper_cpu_info/x86_mips.rs | 8 +- src/linux/maps_reader.rs | 17 ++-- src/linux/minidump_writer.rs | 11 ++- src/linux/ptrace_dumper.rs | 99 +++++++++++------------ src/linux/sections.rs | 10 +-- src/linux/sections/exception_stream.rs | 4 +- src/linux/sections/mappings.rs | 11 ++- src/linux/sections/thread_names_stream.rs | 2 +- src/linux/thread_info.rs | 44 +++++----- src/linux/thread_info/x86.rs | 21 ++--- src/minidump_format.rs | 2 +- 14 files changed, 188 insertions(+), 135 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index de193a2e..3bcb07e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,82 @@ +// BEGIN - Embark standard lints v6 for Rust 1.55+ +// do not change or add/remove here, but one can add exceptions after this section +// for more info see: +#![deny(unsafe_code)] +#![warn( + clippy::all, + clippy::await_holding_lock, + clippy::char_lit_as_u8, + clippy::checked_conversions, + clippy::dbg_macro, + clippy::debug_assert_with_mut_call, + clippy::doc_markdown, + clippy::empty_enum, + clippy::enum_glob_use, + clippy::exit, + clippy::expl_impl_clone_on_copy, + clippy::explicit_deref_methods, + clippy::explicit_into_iter_loop, + clippy::fallible_impl_from, + clippy::filter_map_next, + clippy::flat_map_option, + clippy::float_cmp_const, + clippy::fn_params_excessive_bools, + clippy::from_iter_instead_of_collect, + clippy::if_let_mutex, + clippy::implicit_clone, + clippy::imprecise_flops, + clippy::inefficient_to_string, + clippy::invalid_upcast_comparisons, + clippy::large_digit_groups, + clippy::large_stack_arrays, + clippy::large_types_passed_by_value, + clippy::let_unit_value, + clippy::linkedlist, + clippy::lossy_float_literal, + clippy::macro_use_imports, + clippy::manual_ok_or, + clippy::map_err_ignore, + clippy::map_flatten, + clippy::map_unwrap_or, + clippy::match_on_vec_items, + clippy::match_same_arms, + clippy::match_wild_err_arm, + clippy::match_wildcard_for_single_variants, + clippy::mem_forget, + clippy::mismatched_target_os, + clippy::missing_enforced_import_renames, + clippy::mut_mut, + clippy::mutex_integer, + clippy::needless_borrow, + clippy::needless_continue, + clippy::needless_for_each, + clippy::option_option, + clippy::path_buf_push_overwrite, + clippy::ptr_as_ptr, + clippy::rc_mutex, + clippy::ref_option_ref, + clippy::rest_pat_in_fully_bound_structs, + clippy::same_functions_in_if_condition, + clippy::semicolon_if_nothing_returned, + clippy::single_match_else, + clippy::string_add_assign, + clippy::string_add, + clippy::string_lit_as_bytes, + clippy::string_to_string, + clippy::todo, + clippy::trait_duplication_in_bounds, + clippy::unimplemented, + clippy::unnested_or_patterns, + clippy::unused_self, + clippy::useless_transmute, + clippy::verbose_file_reads, + clippy::zero_sized_map_values, + future_incompatible, + nonstandard_style, + rust_2018_idioms +)] +// END - Embark standard lints v6 for Rust 1.55+ +// crate-specific exceptions: #![allow(unsafe_code)] cfg_if::cfg_if! { diff --git a/src/linux/crash_context/x86_64.rs b/src/linux/crash_context/x86_64.rs index 87bccc77..879005ca 100644 --- a/src/linux/crash_context/x86_64.rs +++ b/src/linux/crash_context/x86_64.rs @@ -1,6 +1,6 @@ use crate::minidump_cpu::imp::*; -use crate::thread_info::to_u128; +use crate::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, @@ -61,15 +61,8 @@ impl super::CpuContext for super::CrashContext { out.flt_save.mx_csr = fs.mxcsr; out.flt_save.mx_csr_mask = fs.mxcr_mask; - let data = to_u128(&fs.st_space); - for idx in 0..data.len() { - out.flt_save.float_registers[idx] = data[idx]; - } - - let data = to_u128(&fs.xmm_space); - for idx in 0..data.len() { - out.flt_save.xmm_registers[idx] = data[idx]; - } + copy_u32_registers(&mut out.flt_save.float_registers, &fs.st_space); + copy_u32_registers(&mut out.flt_save.xmm_registers, &fs.xmm_space); } } } diff --git a/src/linux/dso_debug.rs b/src/linux/dso_debug.rs index d724cc04..aa2703c5 100644 --- a/src/linux/dso_debug.rs +++ b/src/linux/dso_debug.rs @@ -211,7 +211,7 @@ pub fn write_dso_debug_stream( } let mut linkmap_rva = u32::MAX; - if dso_vec.len() > 0 { + if !dso_vec.is_empty() { // If we have at least one DSO, create an array of MDRawLinkMap // entries in the minidump file. let mut linkmap = MemoryArrayWriter::::alloc_array(buffer, dso_vec.len())?; diff --git a/src/linux/dumper_cpu_info/x86_mips.rs b/src/linux/dumper_cpu_info/x86_mips.rs index ea9cfe07..cc38ffa6 100644 --- a/src/linux/dumper_cpu_info/x86_mips.rs +++ b/src/linux/dumper_cpu_info/x86_mips.rs @@ -46,7 +46,7 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { let cpuinfo_file = std::fs::File::open(path::PathBuf::from("/proc/cpuinfo"))?; - let mut vendor_id = String::new(); + let mut vendor_id = None; for line in BufReader::new(cpuinfo_file).lines() { let line = line?; // Expected format: + ':' @@ -83,8 +83,8 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { } // special case for vendor_id - if field == vendor_id_name && value.is_some() && !value.unwrap().is_empty() { - vendor_id = value.unwrap().to_string(); + if field == vendor_id_name { + vendor_id = value.filter(|v| !v.is_empty()).map(|v| (*v).to_owned()); } } } @@ -104,7 +104,7 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { sys_info.processor_revision = (cpu_info_table[1].value << 8 | cpu_info_table[2].value) as u16; } - if !vendor_id.is_empty() { + if let Some(vendor_id) = vendor_id { let mut slice = vendor_id.as_bytes(); for id_part in sys_info.cpu.vendor_id.iter_mut() { let (int_bytes, rest) = slice.split_at(std::mem::size_of::()); diff --git a/src/linux/maps_reader.rs b/src/linux/maps_reader.rs index fc54f3f4..f31bca3f 100644 --- a/src/linux/maps_reader.rs +++ b/src/linux/maps_reader.rs @@ -181,7 +181,7 @@ impl MappingInfo { } pub fn get_mmap(name: &Option, offset: usize) -> Result { - if !MappingInfo::is_mapped_file_safe_to_open(&name) { + if !MappingInfo::is_mapped_file_safe_to_open(name) { return Err(MapsReaderError::NotSafeToOpenMapping( name.clone().unwrap_or_default(), )); @@ -304,14 +304,13 @@ impl MappingInfo { // filesystem name of the module. // Just use the filesystem name if no SONAME is present. - let file_name = match self.elf_file_so_name() { - Ok(name) => name, - Err(_) => { - // file_path := /path/to/libname.so - // file_name := libname.so - let file_name = file_path.rsplitn(2, '/').next().unwrap().to_owned(); - return Ok((file_path, file_name)); - } + let file_name = if let Ok(name) = self.elf_file_so_name() { + name + } else { + // file_path := /path/to/libname.so + // file_name := libname.so + let file_name = file_path.rsplit('/').next().unwrap().to_owned(); + return Ok((file_path, file_name)); }; if self.executable && self.offset != 0 { diff --git a/src/linux/minidump_writer.rs b/src/linux/minidump_writer.rs index d83dd20a..39abd9b5 100644 --- a/src/linux/minidump_writer.rs +++ b/src/linux/minidump_writer.rs @@ -11,7 +11,7 @@ use crate::{ }, minidump_format::*, }; -use std::io::{Cursor, Read, Seek, SeekFrom, Write}; +use std::io::{Cursor, Seek, SeekFrom, Write}; pub type DumpBuf = Cursor>; @@ -297,7 +297,7 @@ impl MinidumpWriter { // we should have a mostly-intact dump dir_section.write_to_file(buffer, None)?; - let dirent = thread_list_stream::write(self, buffer, &dumper)?; + let dirent = thread_list_stream::write(self, buffer, dumper)?; // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; @@ -305,7 +305,7 @@ impl MinidumpWriter { // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; - let _ = app_memory::write(self, buffer)?; + app_memory::write(self, buffer)?; // Write section to file dir_section.write_to_file(buffer, None)?; @@ -411,14 +411,13 @@ impl MinidumpWriter { Ok(()) } + #[allow(clippy::unused_self)] fn write_file( &self, buffer: &mut DumpBuf, filename: &str, ) -> std::result::Result { - let mut file = std::fs::File::open(std::path::PathBuf::from(filename))?; - let mut content = Vec::new(); - file.read_to_end(&mut content)?; + let content = std::fs::read(filename)?; let section = MemoryArrayWriter::::alloc_from_array(buffer, &content)?; Ok(section.location()) diff --git a/src/linux/ptrace_dumper.rs b/src/linux/ptrace_dumper.rs index a33d023a..61c37c98 100644 --- a/src/linux/ptrace_dumper.rs +++ b/src/linux/ptrace_dumper.rs @@ -71,6 +71,7 @@ impl PtraceDumper { Ok(()) } + #[cfg_attr(not(target_os = "android"), allow(clippy::unused_self))] pub fn late_init(&mut self) -> Result<(), InitError> { #[cfg(target_os = "android")] { @@ -213,7 +214,7 @@ impl PtraceDumper { .ok(); (tid, name) }) - .for_each(|(tid, name)| self.threads.push(Thread { tid, name })) + .for_each(|(tid, name)| self.threads.push(Thread { tid, name })); } Ok(()) } @@ -271,8 +272,7 @@ impl PtraceDumper { let line = line.map_err(errmap)?; match MappingInfo::parse_from_line(&line, linux_gate_loc, self.mappings.last_mut()) { Ok(MappingInfoParsingResult::Success(map)) => self.mappings.push(map), - Ok(MappingInfoParsingResult::SkipLine) => continue, - Err(_) => continue, + Ok(MappingInfoParsingResult::SkipLine) | Err(_) => continue, } } @@ -351,12 +351,12 @@ impl PtraceDumper { let defaced; #[cfg(target_pointer_width = "64")] { - defaced = 0x0defaced0defacedusize.to_ne_bytes() + defaced = 0x0defaced0defacedusize.to_ne_bytes(); } #[cfg(target_pointer_width = "32")] { - defaced = 0x0defacedusize.to_ne_bytes() - }; + defaced = 0x0defacedusize.to_ne_bytes(); + } // the bitfield length is 2^test_bits long. let test_bits = 11; // byte length of the corresponding array. @@ -443,28 +443,24 @@ impl PtraceDumper { Ok(()) } - // Find the mapping which the given memory address falls in. + /// Find the mapping which the given memory address falls in. + #[inline] pub fn find_mapping(&self, address: usize) -> Option<&MappingInfo> { - for map in &self.mappings { - if address >= map.start_address && address - map.start_address < map.size { - return Some(&map); - } - } - None + self.mappings + .iter() + .find(|map| address >= map.start_address && address - map.start_address < map.size) } - // Find the mapping which the given memory address falls in. Uses the - // unadjusted mapping address range from the kernel, rather than the - // biased range. + /// Find the mapping which the given memory address falls in. + /// + /// Uses the unadjusted mapping address range from the kernel, rather than + /// the biased range. + #[inline] pub fn find_mapping_no_bias(&self, address: usize) -> Option<&MappingInfo> { - for map in &self.mappings { - if address >= map.system_mapping_info.start_address + self.mappings.iter().find(|map| { + address >= map.system_mapping_info.start_address && address < map.system_mapping_info.end_address - { - return Some(&map); - } - } - None + }) } fn parse_build_id<'data>( @@ -490,41 +486,40 @@ impl PtraceDumper { pub fn elf_file_identifier_from_mapped_file(mem_slice: &[u8]) -> Result, DumperError> { let elf_obj = elf::Elf::parse(mem_slice)?; - match Self::parse_build_id(&elf_obj, mem_slice) { + if let Some(build_id) = Self::parse_build_id(&elf_obj, mem_slice) { // Look for a build id note first. - Some(build_id) => Ok(build_id.to_vec()), + Ok(build_id.to_vec()) + } else { // Fall back on hashing the first page of the text section. - None => { - // Attempt to locate the .text section of an ELF binary and generate - // a simple hash by XORing the first page worth of bytes into |result|. - for section in elf_obj.section_headers { - if section.sh_type != elf::section_header::SHT_PROGBITS { - continue; - } - if section.sh_flags & u64::from(elf::section_header::SHF_ALLOC) != 0 { - if section.sh_flags & u64::from(elf::section_header::SHF_EXECINSTR) != 0 { - let text_section = &mem_slice[section.sh_offset as usize..] - [..section.sh_size as usize]; - // Only provide mem::size_of(MDGUID) bytes to keep identifiers produced by this - // function backwards-compatible. - let max_len = std::cmp::min(text_section.len(), 4096); - let mut result = vec![0u8; std::mem::size_of::()]; - let mut offset = 0; - while offset < max_len { - for idx in 0..std::mem::size_of::() { - if offset + idx >= text_section.len() { - break; - } - result[idx] ^= text_section[offset + idx]; - } - offset += std::mem::size_of::(); + // Attempt to locate the .text section of an ELF binary and generate + // a simple hash by XORing the first page worth of bytes into |result|. + for section in elf_obj.section_headers { + if section.sh_type != elf::section_header::SHT_PROGBITS { + continue; + } + if section.sh_flags & elf::section_header::SHF_ALLOC as u64 != 0 + && section.sh_flags & elf::section_header::SHF_EXECINSTR as u64 != 0 + { + let text_section = + &mem_slice[section.sh_offset as usize..][..section.sh_size as usize]; + // Only provide mem::size_of(MDGUID) bytes to keep identifiers produced by this + // function backwards-compatible. + let max_len = std::cmp::min(text_section.len(), 4096); + let mut result = vec![0u8; std::mem::size_of::()]; + let mut offset = 0; + while offset < max_len { + for idx in 0..std::mem::size_of::() { + if offset + idx >= text_section.len() { + break; } - return Ok(result); + result[idx] ^= text_section[offset + idx]; } + offset += std::mem::size_of::(); } + return Ok(result); } - Err(DumperError::NoBuildIDFound) } + Err(DumperError::NoBuildIDFound) } } @@ -561,7 +556,7 @@ impl PtraceDumper { } } let new_name = MappingInfo::handle_deleted_file_in_mapping( - &mapping.name.as_ref().unwrap_or(&String::new()), + mapping.name.as_deref().unwrap_or(""), pid, )?; diff --git a/src/linux/sections.rs b/src/linux/sections.rs index 9e29c96b..af1ef1b6 100644 --- a/src/linux/sections.rs +++ b/src/linux/sections.rs @@ -34,7 +34,7 @@ where // Get position of this value (e.g. before we add ourselves there) let position = buffer.position(); let size = std::mem::size_of::(); - let bytes = unsafe { std::slice::from_raw_parts(&val as *const T as *const u8, size) }; + let bytes = unsafe { std::slice::from_raw_parts((&val as *const T).cast(), size) }; buffer.write_all(bytes)?; Ok(MemoryWriter { @@ -62,7 +62,7 @@ where // was determined by `alloc()` into the buffer buffer.set_position(self.position as u64); let bytes = unsafe { - std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::()) + std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) }; let res = buffer.write_all(bytes); @@ -99,7 +99,7 @@ where let position = buffer.position(); for val in array { let bytes = unsafe { - std::slice::from_raw_parts(val as *const T as *const u8, std::mem::size_of::()) + std::slice::from_raw_parts((val as *const T).cast(), std::mem::size_of::()) }; buffer.write_all(bytes)?; } @@ -121,7 +121,7 @@ where // Filling out the buffer with default-values let val: T = Default::default(); let bytes = unsafe { - std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::()) + std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) }; buffer.write_all(bytes)?; } @@ -147,7 +147,7 @@ where // was determined by `alloc()` into the buffer buffer.set_position(self.position as u64 + (std::mem::size_of::() * index) as u64); let bytes = unsafe { - std::slice::from_raw_parts(&val as *const T as *const u8, std::mem::size_of::()) + std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) }; let res = buffer.write_all(bytes); diff --git a/src/linux/sections/exception_stream.rs b/src/linux/sections/exception_stream.rs index da0b1d05..4cddc3e8 100644 --- a/src/linux/sections/exception_stream.rs +++ b/src/linux/sections/exception_stream.rs @@ -94,8 +94,8 @@ pub fn write( }; let thread_context = match config.crashing_thread_context { - CrashingThreadContext::CrashContextPlusAddress((ctx, _)) => ctx, - CrashingThreadContext::CrashContext(ctx) => ctx, + CrashingThreadContext::CrashContextPlusAddress((ctx, _)) + | CrashingThreadContext::CrashContext(ctx) => ctx, CrashingThreadContext::None => MDLocationDescriptor { data_size: 0, rva: 0, diff --git a/src/linux/sections/mappings.rs b/src/linux/sections/mappings.rs index d15be725..642e9736 100644 --- a/src/linux/sections/mappings.rs +++ b/src/linux/sections/mappings.rs @@ -43,7 +43,7 @@ pub fn write( for user in &config.user_mapping_list { // GUID was provided by caller. let module = fill_raw_module(buffer, &user.mapping, &user.identifier)?; - modules.push(module) + modules.push(module); } let list_header = MemoryWriter::::alloc_with_val(buffer, modules.len() as u32)?; @@ -66,10 +66,9 @@ fn fill_raw_module( mapping: &MappingInfo, identifier: &[u8], ) -> Result { - let cv_record: MDLocationDescriptor; - if identifier.is_empty() { + let cv_record = if identifier.is_empty() { // Just zeroes - cv_record = Default::default(); + Default::default() } else { let cv_signature = MD_CVINFOELF_SIGNATURE; let array_size = std::mem::size_of_val(&cv_signature) + identifier.len(); @@ -83,8 +82,8 @@ fn fill_raw_module( { sig_section.set_value_at(buffer, *val, index)?; } - cv_record = sig_section.location(); - } + sig_section.location() + }; let (file_path, _) = mapping .get_mapping_effective_name_and_path() diff --git a/src/linux/sections/thread_names_stream.rs b/src/linux/sections/thread_names_stream.rs index 51b23435..2e97f3cf 100644 --- a/src/linux/sections/thread_names_stream.rs +++ b/src/linux/sections/thread_names_stream.rs @@ -20,7 +20,7 @@ pub fn write(buffer: &mut DumpBuf, dumper: &PtraceDumper) -> Result Vec { - let mut res = Vec::new(); - for chunk in slice.chunks_exact(4) { - let value = u128::from_ne_bytes( - chunk - .iter() - .map(|x| x.to_ne_bytes().to_vec()) - .flatten() - .collect::>() - .as_slice() - .try_into() // Make slice into fixed size array - .unwrap(), // Which has to work as we know the numbers work out - ); - res.push(value) - } - res +#[inline] +pub fn to_u128(slice: &[u32]) -> &[u128] { + unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), slice.len().saturating_div(4)) } +} + +#[inline] +pub fn copy_registers(dst: &mut [u128], src: &[u128]) { + let to_copy = std::cmp::min(dst.len(), src.len()); + dst[..to_copy].copy_from_slice(&src[..to_copy]); +} + +#[inline] +pub fn copy_u32_registers(dst: &mut [u128], src: &[u32]) { + copy_registers(dst, to_u128(src)); } trait CommonThreadInfo { @@ -71,13 +69,13 @@ trait CommonThreadInfo { tgid = l .get(6..) .ok_or_else(|| ThreadInfoError::InvalidProcStatusFile(tid, l.clone()))? - .parse::()? + .parse::()?; } "PPid:\t" => { ppid = l .get(6..) .ok_or_else(|| ThreadInfoError::InvalidProcStatusFile(tid, l.clone()))? - .parse::()? + .parse::()?; } _ => continue, } @@ -102,13 +100,13 @@ trait CommonThreadInfo { flag: Option, pid: nix::unistd::Pid, ) -> Result { - let mut data = std::mem::MaybeUninit::uninit(); + let mut data = std::mem::MaybeUninit::::uninit(); let res = unsafe { libc::ptrace( request as ptrace::RequestType, libc::pid_t::from(pid), flag.unwrap_or(NT_Elf::NT_NONE), - data.as_mut_ptr() as *const _ as *const libc::c_void, + data.as_mut_ptr(), ) }; Errno::result(res)?; @@ -125,9 +123,9 @@ trait CommonThreadInfo { flag: Option, pid: nix::unistd::Pid, ) -> Result { - let mut data = std::mem::MaybeUninit::uninit(); + let mut data = std::mem::MaybeUninit::::uninit(); let io = libc::iovec { - iov_base: data.as_mut_ptr() as *mut libc::c_void, + iov_base: data.as_mut_ptr().cast(), iov_len: std::mem::size_of::(), }; let res = unsafe { @@ -135,7 +133,7 @@ trait CommonThreadInfo { request as ptrace::RequestType, libc::pid_t::from(pid), flag.unwrap_or(NT_Elf::NT_NONE), - &io as *const _ as *const libc::c_void, + (&io as *const libc::iovec).cast::(), ) }; Errno::result(res)?; diff --git a/src/linux/thread_info/x86.rs b/src/linux/thread_info/x86.rs index d6fdfe2c..04db7b4d 100644 --- a/src/linux/thread_info/x86.rs +++ b/src/linux/thread_info/x86.rs @@ -3,7 +3,7 @@ use crate::errors::ThreadInfoError; use crate::minidump_cpu::imp::*; use crate::minidump_cpu::RawContextCPU; #[cfg(target_arch = "x86_64")] -use crate::thread_info::to_u128; +use crate::thread_info::copy_u32_registers; use core::mem::size_of_val; use libc; use libc::user; @@ -100,18 +100,18 @@ impl ThreadInfoX86 { let debug_offset = memoffset::offset_of!(user, u_debugreg); let elem_offset = size_of_val(&dregs[0]); - for idx in 0..NUM_DEBUG_REGISTERS { + for (idx, dreg) in dregs.iter_mut().enumerate() { let chunk = Self::peek_user( tid, (debug_offset + idx * elem_offset) as ptrace::AddressType, )?; #[cfg(target_arch = "x86_64")] { - dregs[idx] = chunk as u64; // libc / ptrace is very messy wrt int types used... + *dreg = chunk as u64; // libc / ptrace is very messy wrt int types used... } #[cfg(target_arch = "x86")] { - dregs[idx] = chunk as i32; // libc / ptrace is very messy wrt int types used... + *dreg = chunk as i32; // libc / ptrace is very messy wrt int types used... } } @@ -197,17 +197,8 @@ impl ThreadInfoX86 { out.flt_save.mx_csr = self.fpregs.mxcsr; out.flt_save.mx_csr_mask = self.fpregs.mxcr_mask; - let data = to_u128(&self.fpregs.st_space); - for idx in 0..data.len() { - out.flt_save.float_registers[idx] = data[idx]; - } - - let data = to_u128(&self.fpregs.xmm_space); - for idx in 0..data.len() { - out.flt_save.xmm_registers[idx] = data[idx]; - } - // my_memcpy(&out.flt_save.float_registers, &self.fpregs.st_space, 8 * 16); - // my_memcpy(&out.flt_save.xmm_registers, &self.fpregs.xmm_space, 16 * 16); + copy_u32_registers(&mut out.flt_save.float_registers, &self.fpregs.st_space); + copy_u32_registers(&mut out.flt_save.xmm_registers, &self.fpregs.xmm_space); } #[cfg(target_arch = "x86")] diff --git a/src/minidump_format.rs b/src/minidump_format.rs index cd6910c8..a14026b3 100644 --- a/src/minidump_format.rs +++ b/src/minidump_format.rs @@ -67,7 +67,7 @@ pub const MD_HEADER_SIGNATURE: u32 = 0x504d444d; /* 'PMDM' */ pub const MD_HEADER_VERSION: u32 = 0x0000a793; /* 42899 */ /* MINIDUMP_VERSION */ -/// The name of a thread, found in the ThreadNamesStream. +/// The name of a thread, found in the [`MDStreamType::ThreadNamesStream`]. #[repr(C, packed)] #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct MDRawThreadName { From 04d22cfd030bf1df2705cf250f13b4a3f0771656 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Wed, 9 Mar 2022 18:41:38 +0100 Subject: [PATCH 17/21] Giant refactor to use minidump types There was a _ton_ of duplication of minidump types between this crate and minidump-common, so this refactors the code to remove basically all types that minidump-common already had, and changed the minidump_writer code to use scroll pwrite instead of relying on repr(C) and byte transmutes --- Cargo.toml | 16 +- src/linux/crash_context.rs | 2 +- src/linux/crash_context/x86_64.rs | 39 +- src/linux/dso_debug.rs | 8 +- src/linux/dumper_cpu_info.rs | 40 +- src/linux/dumper_cpu_info/arm.rs | 44 +-- src/linux/dumper_cpu_info/x86_mips.rs | 150 ++++---- src/linux/errors.rs | 2 + src/linux/minidump_writer.rs | 40 +- src/linux/ptrace_dumper.rs | 8 +- src/linux/sections.rs | 257 ++++++++----- src/linux/sections/app_memory.rs | 2 +- src/linux/sections/mappings.rs | 4 +- src/linux/sections/systeminfo_stream.rs | 13 +- src/linux/sections/thread_list_stream.rs | 10 +- src/linux/thread_info/x86.rs | 49 ++- src/minidump_cpu.rs | 5 +- src/minidump_cpu/amd64.rs | 179 --------- src/minidump_format.rs | 461 ++--------------------- tests/minidump_writer.rs | 4 +- 20 files changed, 416 insertions(+), 917 deletions(-) delete mode 100644 src/minidump_cpu/amd64.rs diff --git a/Cargo.toml b/Cargo.toml index f4a281c3..14bd0e9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,16 +8,24 @@ license = "MIT" [dependencies] byteorder = "1.3.2" cfg-if = "1.0" -exception-handler = { path = "../exception-handler" } +exception-handler = { path = "../crash-handling/exception-handler" } goblin = "0.5" libc = "0.2.74" memmap2 = "0.5" memoffset = "0.6" +minidump = "*" +minidump-common = "*" nix = "0.23" +scroll = "0.11" tempfile = "3.1.0" thiserror = "1.0.21" [dev-dependencies] -minidump = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } -minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "9652b3b" } -uctx = { path = "../uctx" } +uctx = { path = "../crash-handling/uctx" } +debugid = "0.7.3" + +[patch.crates-io] +#minidump = { git = "https://github.com/EmbarkStudios/rust-minidump", rev = "228c5d0" } +#minidump-common = { git = "https://github.com/EmbarkStudios/rust-minidump", rev = "228c5d0" } +minidump = { path = "../rust-minidump/minidump" } +minidump-common = { path = "../rust-minidump/minidump-common" } diff --git a/src/linux/crash_context.rs b/src/linux/crash_context.rs index 8e68574b..ce70a954 100644 --- a/src/linux/crash_context.rs +++ b/src/linux/crash_context.rs @@ -16,7 +16,7 @@ cfg_if::cfg_if! { } } -use crate::minidump_cpu::RawContextCPU; +use crate::minidump_cpu::{FloatStateCPU, RawContextCPU}; pub use exception_handler::CrashContext; pub trait CpuContext { diff --git a/src/linux/crash_context/x86_64.rs b/src/linux/crash_context/x86_64.rs index 879005ca..f699e469 100644 --- a/src/linux/crash_context/x86_64.rs +++ b/src/linux/crash_context/x86_64.rs @@ -1,5 +1,3 @@ -use crate::minidump_cpu::imp::*; - use crate::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, @@ -16,7 +14,8 @@ impl super::CpuContext for super::CrashContext { } fn fill_cpu_context(&self, out: &mut super::RawContextCPU) { - out.context_flags = MD_CONTEXT_AMD64_FULL; + out.context_flags = + crate::minidump_format::format::ContextFlagsAmd64::CONTEXT_AMD64_FULL.bits(); { let gregs = &self.context.uc_mcontext.gregs; @@ -50,19 +49,29 @@ impl super::CpuContext for super::CrashContext { { let fs = &self.float_state; - out.flt_save.control_word = fs.cwd; - out.flt_save.status_word = fs.swd; - out.flt_save.tag_word = fs.ftw as u8; - out.flt_save.error_opcode = fs.fop; - out.flt_save.error_offset = fs.rip as u32; - out.flt_save.data_offset = fs.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 = fs.mxcsr; - out.flt_save.mx_csr_mask = fs.mxcr_mask; - copy_u32_registers(&mut out.flt_save.float_registers, &fs.st_space); - copy_u32_registers(&mut out.flt_save.xmm_registers, &fs.xmm_space); + let mut float_save = super::FloatStateCPU { + 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); + + use scroll::Pwrite; + // TODO: handle errors + out.float_save + .pwrite_with(float_save, 0, scroll::Endian::Little) + .unwrap(); } } } diff --git a/src/linux/dso_debug.rs b/src/linux/dso_debug.rs index aa2703c5..d842a926 100644 --- a/src/linux/dso_debug.rs +++ b/src/linux/dso_debug.rs @@ -3,11 +3,11 @@ use crate::{ auxv_reader::AuxvType, errors::SectionDsoDebugError, ptrace_dumper::PtraceDumper, - sections::{write_string_to_location, MemoryArrayWriter, MemoryWriter}, + sections::{write_string_to_location, Buffer, MemoryArrayWriter, MemoryWriter}, }, minidump_format::*, }; -use std::{collections::HashMap, io::Cursor}; +use std::collections::HashMap; type Result = std::result::Result; @@ -73,7 +73,7 @@ pub struct RDebug { } pub fn write_dso_debug_stream( - buffer: &mut Cursor>, + buffer: &mut Buffer, blamed_thread: i32, auxv: &HashMap, ) -> Result { @@ -265,7 +265,7 @@ pub fn write_dso_debug_stream( dyn_addr as *mut libc::c_void, dynamic_length, )?; - MemoryArrayWriter::::alloc_from_array(buffer, &dso_debug_data)?; + MemoryArrayWriter::write_bytes(buffer, &dso_debug_data); Ok(dirent) } diff --git a/src/linux/dumper_cpu_info.rs b/src/linux/dumper_cpu_info.rs index 80902b62..bbe22e7c 100644 --- a/src/linux/dumper_cpu_info.rs +++ b/src/linux/dumper_cpu_info.rs @@ -20,36 +20,26 @@ cfg_if::cfg_if! { pub use imp::write_cpu_information; -use crate::{ - errors::MemoryWriterError, - linux::sections::write_string_to_location, - minidump_format::{MDOSPlatform, MDRawSystemInfo}, -}; +use crate::minidump_format::PlatformId; use nix::sys::utsname::uname; -use std::io::Cursor; -type Result = std::result::Result; - -pub fn write_os_information( - buffer: &mut Cursor>, - 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(" "); - - let location = write_string_to_location(buffer, &merged)?; - sys_info.csd_version_rva = location.rva; + info.machine() + ); - Ok(()) + ( + if cfg!(target_os = "android") { + PlatformId::Android + } else { + PlatformId::Linux + }, + vers, + ) } diff --git a/src/linux/dumper_cpu_info/arm.rs b/src/linux/dumper_cpu_info/arm.rs index ab7da7ae..7d5b1ad5 100644 --- a/src/linux/dumper_cpu_info/arm.rs +++ b/src/linux/dumper_cpu_info/arm.rs @@ -90,30 +90,26 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { #[cfg(target_arch = "arm")] { cpu_features_entries = [ - CpuFeaturesEntry::new("swp", MDCPUInformationARMElfHwCaps::Swp as u32), - CpuFeaturesEntry::new("half", MDCPUInformationARMElfHwCaps::Half as u32), - CpuFeaturesEntry::new("thumb", MDCPUInformationARMElfHwCaps::Thumb as u32), - CpuFeaturesEntry::new("bit26", MDCPUInformationARMElfHwCaps::Bit26 as u32), - CpuFeaturesEntry::new("fastmult", MDCPUInformationARMElfHwCaps::FastMult as u32), - CpuFeaturesEntry::new("fpa", MDCPUInformationARMElfHwCaps::Fpa as u32), - CpuFeaturesEntry::new("vfp", MDCPUInformationARMElfHwCaps::Vfp as u32), - CpuFeaturesEntry::new("edsp", MDCPUInformationARMElfHwCaps::Edsp as u32), - CpuFeaturesEntry::new("java", MDCPUInformationARMElfHwCaps::Java as u32), - CpuFeaturesEntry::new("iwmmxt", MDCPUInformationARMElfHwCaps::Iwmmxt as u32), - CpuFeaturesEntry::new("crunch", MDCPUInformationARMElfHwCaps::Crunch as u32), - CpuFeaturesEntry::new("thumbee", MDCPUInformationARMElfHwCaps::Thumbee as u32), - CpuFeaturesEntry::new("neon", MDCPUInformationARMElfHwCaps::Neon as u32), - CpuFeaturesEntry::new("vfpv3", MDCPUInformationARMElfHwCaps::Vfpv3 as u32), - CpuFeaturesEntry::new("vfpv3d16", MDCPUInformationARMElfHwCaps::Vfpv3d16 as u32), - CpuFeaturesEntry::new("tls", MDCPUInformationARMElfHwCaps::Tls as u32), - CpuFeaturesEntry::new("vfpv4", MDCPUInformationARMElfHwCaps::Vfpv4 as u32), - CpuFeaturesEntry::new("idiva", MDCPUInformationARMElfHwCaps::Idiva as u32), - CpuFeaturesEntry::new("idivt", MDCPUInformationARMElfHwCaps::Idivt as u32), - CpuFeaturesEntry::new( - "idiv", - MDCPUInformationARMElfHwCaps::Idiva as u32 - | MDCPUInformationARMElfHwCaps::Idivt as u32, - ), + CpuFeaturesEntry::new("swp", MDCPUInformationARMElfHwCaps::HWCAP_SWP), + CpuFeaturesEntry::new("half", MDCPUInformationARMElfHwCaps::HWCAP_HALF), + CpuFeaturesEntry::new("thumb", MDCPUInformationARMElfHwCaps::HWCAP_THUMB), + CpuFeaturesEntry::new("bit26", MDCPUInformationARMElfHwCaps::HWCAP_26BIT), + CpuFeaturesEntry::new("fastmult", MDCPUInformationARMElfHwCaps::HWCAP_FAST_MULT), + CpuFeaturesEntry::new("fpa", MDCPUInformationARMElfHwCaps::HWCAP_FPA), + CpuFeaturesEntry::new("vfp", MDCPUInformationARMElfHwCaps::HWCAP_VFP), + CpuFeaturesEntry::new("edsp", MDCPUInformationARMElfHwCaps::HWCAP_EDSP), + CpuFeaturesEntry::new("java", MDCPUInformationARMElfHwCaps::HWCAP_JAVA), + CpuFeaturesEntry::new("iwmmxt", MDCPUInformationARMElfHwCaps::HWCAP_IWMMXT), + CpuFeaturesEntry::new("crunch", MDCPUInformationARMElfHwCaps::HWCAP_CRUNCH), + CpuFeaturesEntry::new("thumbee", MDCPUInformationARMElfHwCaps::HWCAP_THUMBEE), + CpuFeaturesEntry::new("neon", MDCPUInformationARMElfHwCaps::HWCAP_NEON), + CpuFeaturesEntry::new("vfpv3", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3), + CpuFeaturesEntry::new("vfpv3d16", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3D16), + CpuFeaturesEntry::new("tls", MDCPUInformationARMElfHwCaps::HWCAP_TLS), + CpuFeaturesEntry::new("vfpv4", MDCPUInformationARMElfHwCaps::HWCAP_VFPv4), + CpuFeaturesEntry::new("idiva", MDCPUInformationARMElfHwCaps::HWCAP_IDIVA), + CpuFeaturesEntry::new("idivt", MDCPUInformationARMElfHwCaps::HWCAP_IDIVT), + CpuFeaturesEntry::new("idiv", HWCAP_IDIV), ]; } #[cfg(target_arch = "aarch64")] diff --git a/src/linux/dumper_cpu_info/x86_mips.rs b/src/linux/dumper_cpu_info/x86_mips.rs index cc38ffa6..05e7fc95 100644 --- a/src/linux/dumper_cpu_info/x86_mips.rs +++ b/src/linux/dumper_cpu_info/x86_mips.rs @@ -5,48 +5,28 @@ use std::path; type Result = std::result::Result; -struct CpuInfoEntry { - info_name: &'static str, - value: i32, - found: bool, -} - -impl CpuInfoEntry { - fn new(info_name: &'static str, value: i32, found: bool) -> Self { - CpuInfoEntry { - info_name, - value, - found, - } - } -} - pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { - let vendor_id_name = "vendor_id"; - let mut cpu_info_table = [ - CpuInfoEntry::new("processor", -1, false), - #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] - CpuInfoEntry::new("model", 0, false), - #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] - CpuInfoEntry::new("stepping", 0, false), - #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] - CpuInfoEntry::new("cpu family", 0, false), - ]; - // processor_architecture should always be set, do this first - if cfg!(target_arch = "mips") { - sys_info.processor_architecture = MDCPUArchitecture::Mips as u16; + sys_info.processor_architecture = if cfg!(target_arch = "mips") { + MDCPUArchitecture::PROCESSOR_ARCHITECTURE_MIPS } else if cfg!(target_arch = "mips64") { - sys_info.processor_architecture = MDCPUArchitecture::Mips64 as u16; + MDCPUArchitecture::PROCESSOR_ARCHITECTURE_MIPS64 } else if cfg!(target_arch = "x86") { - sys_info.processor_architecture = MDCPUArchitecture::X86 as u16; + MDCPUArchitecture::PROCESSOR_ARCHITECTURE_INTEL } else { - sys_info.processor_architecture = MDCPUArchitecture::Amd64 as u16; - } + MDCPUArchitecture::PROCESSOR_ARCHITECTURE_AMD64 + } as u16; let cpuinfo_file = std::fs::File::open(path::PathBuf::from("/proc/cpuinfo"))?; + let mut processor = None; + // x86/_64 specific let mut vendor_id = None; + let mut model = None; + let mut stepping = None; + let mut family = None; + // + for line in BufReader::new(cpuinfo_file).lines() { let line = line?; // Expected format: + ':' @@ -58,63 +38,71 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { continue; } - let split: Vec<_> = line.split(':').map(|x| x.trim()).collect(); - let field = split[0]; - let value = split.get(1); // Option, might be missing + let mut liter = line.split(':').map(|x| x.trim()); + let field = liter.next().unwrap(); // guaranteed to have at least one item + let value = if let Some(val) = liter.next() { + val + } else { + continue; + }; - let mut is_first_entry = true; - for mut entry in cpu_info_table.iter_mut() { - if !is_first_entry && entry.found { - // except for the 'processor' field, ignore repeated values. - continue; - } - is_first_entry = false; - if field == entry.info_name { - if let Some(val) = value { - if let Ok(v) = val.parse() { - entry.value = v; - entry.found = true; - } else { - continue; - } - } else { - continue; + let entry = match field { + "processor" => &mut processor, + "model" => &mut model, + "stepping" => &mut stepping, + "cpu family" => &mut family, + "vendor_id" => { + if vendor_id.is_none() && !value.is_empty() { + vendor_id = Some(value.to_owned()); } + continue; } + _ => continue, + }; - // special case for vendor_id - if field == vendor_id_name { - vendor_id = value.filter(|v| !v.is_empty()).map(|v| (*v).to_owned()); - } + if entry.is_some() && field != "processor" { + continue; + } + + if let Ok(v) = value.parse::() { + *entry = Some(v); } } - // make sure we got everything we wanted - if !cpu_info_table.iter().all(|x| x.found) { - return Err(CpuInfoError::NotAllProcEntriesFound); - } - // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, - // assuming this is the highest id, change it to the number of CPUs - // by adding one. - cpu_info_table[0].value += 1; - sys_info.number_of_processors = cpu_info_table[0].value as u8; // TODO: might not work on special machines with LOTS of CPUs + // This holds the highest processor id which start from 0 so add 1 to get the actual count + // This field is only a u8 which means it will not work great in high (artificially or otherwise) + // contexts + sys_info.number_of_processors = std::cmp::max( + (processor.ok_or(CpuInfoError::NotAllProcEntriesFound)? + 1) as u8, + u8::MAX, + ); + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] { - sys_info.processor_level = cpu_info_table[3].value as u16; - sys_info.processor_revision = - (cpu_info_table[1].value << 8 | cpu_info_table[2].value) as u16; - } - if let Some(vendor_id) = vendor_id { - let mut slice = vendor_id.as_bytes(); - for id_part in sys_info.cpu.vendor_id.iter_mut() { - let (int_bytes, rest) = slice.split_at(std::mem::size_of::()); - slice = rest; - *id_part = match int_bytes.try_into() { - Ok(x) => u32::from_ne_bytes(x), - Err(_) => { - continue; - } - }; + sys_info.processor_level = family.ok_or(CpuInfoError::NotAllProcEntriesFound)? as u16; + sys_info.processor_revision = (model.ok_or(CpuInfoError::NotAllProcEntriesFound)? << 8 + | stepping.ok_or(CpuInfoError::NotAllProcEntriesFound)?) + as u16; + + if let Some(vendor_id) = vendor_id { + let mut slice = vendor_id.as_bytes(); + + // SAFETY: CPU_INFORMATION is a block of bytes, which is actually + // a union, including the X86 information that we actually want to + // set + let cpu_info: &mut MDCPUInformation = + unsafe { &mut *sys_info.cpu.data.as_mut_ptr().cast() }; + + for id_part in cpu_info.vendor_id.iter_mut() { + let (int_bytes, rest) = slice.split_at(std::mem::size_of::()); + slice = rest; + *id_part = match int_bytes.try_into() { + Ok(x) => u32::from_ne_bytes(x), + Err(_) => { + continue; + } + }; + } } } diff --git a/src/linux/errors.rs b/src/linux/errors.rs index e35e10b0..2ce25037 100644 --- a/src/linux/errors.rs +++ b/src/linux/errors.rs @@ -126,6 +126,8 @@ pub enum MemoryWriterError { IOError(#[from] std::io::Error), #[error("Failed integer conversion")] TryFromIntError(#[from] std::num::TryFromIntError), + #[error("Failed to write to buffer")] + Scroll(#[from] scroll::Error), } #[derive(Debug, Error)] diff --git a/src/linux/minidump_writer.rs b/src/linux/minidump_writer.rs index 39abd9b5..c2a1e4ec 100644 --- a/src/linux/minidump_writer.rs +++ b/src/linux/minidump_writer.rs @@ -11,9 +11,9 @@ use crate::{ }, minidump_format::*, }; -use std::io::{Cursor, Seek, SeekFrom, Write}; +use std::io::{Seek, SeekFrom, Write}; -pub type DumpBuf = Cursor>; +pub type DumpBuf = Buffer; #[derive(Debug)] pub struct DirSection<'a, W> @@ -37,17 +37,18 @@ where index_length: u32, destination: &'a mut W, ) -> std::result::Result { - let dir_section = + let section = MemoryArrayWriter::::alloc_array(buffer, index_length as usize)?; Ok(DirSection { curr_idx: 0, - section: dir_section, + section, destination_start_offset: destination.seek(SeekFrom::Current(0))?, destination, last_position_written_to_file: 0, }) } + #[inline] fn position(&self) -> u32 { self.section.position } @@ -66,16 +67,15 @@ where let idx_pos = self.section.location_of_index(self.curr_idx); self.curr_idx += 1; - self.destination.seek(std::io::SeekFrom::Start( + self.destination.seek(SeekFrom::Start( self.destination_start_offset + idx_pos.rva as u64, ))?; let start = idx_pos.rva as usize; let end = (idx_pos.rva + idx_pos.data_size) as usize; - self.destination.write_all(&buffer.get_ref()[start..end])?; + self.destination.write_all(&buffer[start..end])?; // Reset file-position - self.destination - .seek(std::io::SeekFrom::Start(curr_file_pos))?; + self.destination.seek(SeekFrom::Start(curr_file_pos))?; Ok(()) } @@ -93,7 +93,7 @@ where } let start_pos = self.last_position_written_to_file as usize; - self.destination.write_all(&buffer.get_ref()[start_pos..])?; + self.destination.write_all(&buffer[start_pos..])?; self.last_position_written_to_file = buffer.position(); Ok(()) } @@ -201,14 +201,14 @@ impl MinidumpWriter { } } - let mut buffer = Cursor::new(Vec::new()); + let mut buffer = Buffer::with_capacity(4 * 1024); self.generate_dump(&mut buffer, &mut dumper, destination)?; // dumper would resume threads in drop() automatically, // but in case there is an error, we want to catch it dumper.resume_threads()?; - Ok(buffer.into_inner()) + Ok(buffer.into()) } fn crash_thread_references_principal_mapping(&self, dumper: &PtraceDumper) -> bool { @@ -282,7 +282,6 @@ impl MinidumpWriter { signature: MD_HEADER_SIGNATURE, version: MD_HEADER_VERSION, stream_count: num_writers, - // header.get()->stream_directory_rva = dir.position(); stream_directory_rva: dir_section.position(), checksum: 0, /* Can be 0. In fact, that's all that's * been found in minidump files. */ @@ -298,27 +297,21 @@ impl MinidumpWriter { dir_section.write_to_file(buffer, None)?; let dirent = thread_list_stream::write(self, buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = mappings::write(self, buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; app_memory::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, None)?; let dirent = memory_list_stream::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = exception_stream::write(self, buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = systeminfo_stream::write(buffer)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, "/proc/cpuinfo") { @@ -328,7 +321,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/status", self.blamed_thread)) @@ -339,7 +331,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self @@ -352,7 +343,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/cmdline", self.blamed_thread)) @@ -363,7 +353,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/environ", self.blamed_thread)) @@ -374,7 +363,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/auxv", self.blamed_thread)) { @@ -384,7 +372,6 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = match self.write_file(buffer, &format!("/proc/{}/maps", self.blamed_thread)) { @@ -394,16 +381,13 @@ impl MinidumpWriter { }, Err(_) => Default::default(), }; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = dso_debug::write_dso_debug_stream(buffer, self.blamed_thread, &dumper.auxv) .unwrap_or_default(); - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; let dirent = thread_names_stream::write(buffer, dumper)?; - // Write section to file dir_section.write_to_file(buffer, Some(dirent))?; // If you add more directory entries, don't forget to update kNumWriters, @@ -419,7 +403,7 @@ impl MinidumpWriter { ) -> std::result::Result { let content = std::fs::read(filename)?; - let section = MemoryArrayWriter::::alloc_from_array(buffer, &content)?; + let section = MemoryArrayWriter::write_bytes(buffer, &content); Ok(section.location()) } } diff --git a/src/linux/ptrace_dumper.rs b/src/linux/ptrace_dumper.rs index 61c37c98..3f192ed5 100644 --- a/src/linux/ptrace_dumper.rs +++ b/src/linux/ptrace_dumper.rs @@ -9,7 +9,7 @@ use crate::{ thread_info::{Pid, ThreadInfo}, LINUX_GATE_LIBRARY_NAME, }, - minidump_format::MDGUID, + minidump_format::GUID, }; use goblin::elf; use nix::sys::{ptrace, wait}; @@ -505,16 +505,16 @@ impl PtraceDumper { // Only provide mem::size_of(MDGUID) bytes to keep identifiers produced by this // function backwards-compatible. let max_len = std::cmp::min(text_section.len(), 4096); - let mut result = vec![0u8; std::mem::size_of::()]; + let mut result = vec![0u8; std::mem::size_of::()]; let mut offset = 0; while offset < max_len { - for idx in 0..std::mem::size_of::() { + for idx in 0..std::mem::size_of::() { if offset + idx >= text_section.len() { break; } result[idx] ^= text_section[offset + idx]; } - offset += std::mem::size_of::(); + offset += std::mem::size_of::(); } return Ok(result); } diff --git a/src/linux/sections.rs b/src/linux/sections.rs index af1ef1b6..b7850ac0 100644 --- a/src/linux/sections.rs +++ b/src/linux/sections.rs @@ -14,12 +14,87 @@ use crate::{ }, minidump_format::*, }; -use std::io::{Cursor, Write}; +use scroll::ctx::{SizeWith, TryIntoCtx}; -type Result = std::result::Result; +type WriteResult = std::result::Result; + +macro_rules! size { + ($t:ty) => { + <$t>::size_with(&scroll::Endian::Little) + }; +} + +pub struct Buffer { + inner: Vec, +} + +impl Buffer { + pub fn with_capacity(cap: usize) -> Self { + Self { + inner: Vec::with_capacity(cap), + } + } + + #[inline] + pub fn position(&self) -> u64 { + self.inner.len() as u64 + } + + #[inline] + #[must_use] + fn reserve(&mut self, len: usize) -> usize { + let mark = self.inner.len(); + self.inner.resize(self.inner.len() + len, 0); + mark + } + + #[inline] + fn write(&mut self, val: N) -> Result + where + N: TryIntoCtx + SizeWith, + E: From, + { + self.write_at(self.inner.len(), val) + } + + fn write_at(&mut self, offset: usize, val: N) -> Result + where + N: TryIntoCtx + SizeWith, + E: From, + { + let to_write = size!(N); + let remainder = self.inner.len() - offset; + if remainder < to_write { + self.inner + .resize(self.inner.len() + to_write - remainder, 0); + } + + let dst = &mut self.inner[offset..offset + to_write]; + val.try_into_ctx(dst, scroll::Endian::Little) + } + + #[inline] + pub fn write_all(&mut self, buffer: &[u8]) { + self.inner.extend_from_slice(buffer); + } +} + +impl From for Vec { + fn from(b: Buffer) -> Self { + b.inner + } +} + +impl std::ops::Deref for Buffer { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} #[derive(Debug, PartialEq)] -pub struct MemoryWriter { +pub struct MemoryWriter { pub position: MDRVA, pub size: usize, phantom: std::marker::PhantomData, @@ -27,157 +102,159 @@ pub struct MemoryWriter { impl MemoryWriter where - T: Default + Sized, + T: TryIntoCtx + SizeWith, { /// Create a slot for a type T in the buffer, we can fill right now with real values. - pub fn alloc_with_val(buffer: &mut Cursor>, val: T) -> Result { - // Get position of this value (e.g. before we add ourselves there) + pub fn alloc_with_val(buffer: &mut Buffer, val: T) -> WriteResult { + // Mark the position as we may overwrite later let position = buffer.position(); - let size = std::mem::size_of::(); - let bytes = unsafe { std::slice::from_raw_parts((&val as *const T).cast(), size) }; - buffer.write_all(bytes)?; + let size = buffer.write(val)?; - Ok(MemoryWriter { + Ok(Self { position: position as u32, size, - phantom: std::marker::PhantomData:: {}, + phantom: std::marker::PhantomData, }) } /// Create a slot for a type T in the buffer, we can fill later with real values. - /// This function fills it with `Default::default()`, which is less performant than - /// using uninitialized memory, but safe. - pub fn alloc(buffer: &mut Cursor>) -> Result { - // Filling out the buffer with default-values - let val: T = Default::default(); - Self::alloc_with_val(buffer, val) + pub fn alloc(buffer: &mut Buffer) -> WriteResult { + let size = size!(T); + let position = buffer.reserve(size) as u32; + + Ok(Self { + position: position as u32, + size, + phantom: std::marker::PhantomData, + }) } /// Write actual values in the buffer-slot we got during `alloc()` - pub fn set_value(&mut self, buffer: &mut Cursor>, val: T) -> Result<()> { - // Save whereever the current cursor stands in the buffer - let curr_pos = buffer.position(); - - // Write the actual value we want at our position that - // was determined by `alloc()` into the buffer - buffer.set_position(self.position as u64); - let bytes = unsafe { - std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) - }; - let res = buffer.write_all(bytes); - - // Resetting whereever we were before updating this - // regardless of the write-result - buffer.set_position(curr_pos); - - res?; - Ok(()) + #[inline] + pub fn set_value(&mut self, buffer: &mut Buffer, val: T) -> WriteResult<()> { + Ok(buffer.write_at(self.position as usize, val).map(|_sz| ())?) } + #[inline] pub fn location(&self) -> MDLocationDescriptor { MDLocationDescriptor { - data_size: std::mem::size_of::() as u32, + data_size: size!(T) as u32, rva: self.position, } } } #[derive(Debug, PartialEq)] -pub struct MemoryArrayWriter { +pub struct MemoryArrayWriter { pub position: MDRVA, array_size: usize, phantom: std::marker::PhantomData, } +impl MemoryArrayWriter { + #[inline] + pub fn write_bytes(buffer: &mut Buffer, slice: &[u8]) -> Self { + let position = buffer.position(); + buffer.write_all(slice); + + Self { + position: position as u32, + array_size: slice.len(), + phantom: std::marker::PhantomData, + } + } +} + +impl MemoryArrayWriter +where + T: TryIntoCtx + SizeWith + Copy, +{ + pub fn alloc_from_array(buffer: &mut Buffer, array: &[T]) -> WriteResult { + let array_size = array.len(); + let position = buffer.reserve(array_size * size!(T)); + + for (idx, val) in array.iter().enumerate() { + buffer.write_at(position + idx * size!(T), *val)?; + } + + Ok(Self { + position: position as u32, + array_size, + phantom: std::marker::PhantomData, + }) + } +} + impl MemoryArrayWriter where - T: Default + Sized, + T: TryIntoCtx + SizeWith, { /// Create a slot for a type T in the buffer, we can fill in the values in one go. - pub fn alloc_from_array(buffer: &mut Cursor>, array: &[T]) -> Result { - // Get position of this value (e.g. before we add ourselves there) - let position = buffer.position(); - for val in array { - let bytes = unsafe { - std::slice::from_raw_parts((val as *const T).cast(), std::mem::size_of::()) - }; - buffer.write_all(bytes)?; + pub fn alloc_from_iter( + buffer: &mut Buffer, + iter: impl IntoIterator, + ) -> WriteResult + where + I: std::iter::ExactSizeIterator, + { + let iter = iter.into_iter(); + let array_size = iter.len(); + let size = size!(T); + let position = buffer.reserve(array_size * size); + + for (idx, val) in iter.enumerate() { + buffer.write_at(position + idx * size, val)?; } - Ok(MemoryArrayWriter { + Ok(Self { position: position as u32, - array_size: array.len(), - phantom: std::marker::PhantomData:: {}, + array_size, + phantom: std::marker::PhantomData, }) } /// Create a slot for a type T in the buffer, we can fill later with real values. /// This function fills it with `Default::default()`, which is less performant than /// using uninitialized memory, but safe. - pub fn alloc_array(buffer: &mut Cursor>, array_size: usize) -> Result { - // Get position of this value (e.g. before we add ourselves there) - let position = buffer.position(); - for _ in 0..array_size { - // Filling out the buffer with default-values - let val: T = Default::default(); - let bytes = unsafe { - std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) - }; - buffer.write_all(bytes)?; - } + pub fn alloc_array(buffer: &mut Buffer, array_size: usize) -> WriteResult { + let position = buffer.reserve(array_size * size!(T)); - Ok(MemoryArrayWriter { + Ok(Self { position: position as u32, array_size, - phantom: std::marker::PhantomData:: {}, + phantom: std::marker::PhantomData, }) } /// Write actual values in the buffer-slot we got during `alloc()` - pub fn set_value_at( - &mut self, - buffer: &mut Cursor>, - val: T, - index: usize, - ) -> Result<()> { - // Save whereever the current cursor stands in the buffer - let curr_pos = buffer.position(); - - // Write the actual value we want at our position that - // was determined by `alloc()` into the buffer - buffer.set_position(self.position as u64 + (std::mem::size_of::() * index) as u64); - let bytes = unsafe { - std::slice::from_raw_parts((&val as *const T).cast(), std::mem::size_of::()) - }; - let res = buffer.write_all(bytes); - - // Resetting whereever we were before updating this - // regardless of the write-result - buffer.set_position(curr_pos); - - res?; - Ok(()) + #[inline] + pub fn set_value_at(&mut self, buffer: &mut Buffer, val: T, index: usize) -> WriteResult<()> { + Ok(buffer + .write_at(self.position as usize + size!(T) * index, val) + .map(|_sz| ())?) } + #[inline] pub fn location(&self) -> MDLocationDescriptor { MDLocationDescriptor { - data_size: (self.array_size * std::mem::size_of::()) as u32, + data_size: (self.array_size * size!(T)) as u32, rva: self.position, } } + #[inline] pub fn location_of_index(&self, idx: usize) -> MDLocationDescriptor { MDLocationDescriptor { - data_size: std::mem::size_of::() as u32, - rva: self.position + (std::mem::size_of::() * idx) as u32, + data_size: size!(T) as u32, + rva: self.position + (size!(T) * idx) as u32, } } } pub fn write_string_to_location( - buffer: &mut Cursor>, + buffer: &mut Buffer, text: &str, -) -> Result { +) -> WriteResult { let letters: Vec = text.encode_utf16().collect(); // First write size of the string (x letters in u16, times the size of u16) diff --git a/src/linux/sections/app_memory.rs b/src/linux/sections/app_memory.rs index 36efcd4a..824e0cf5 100644 --- a/src/linux/sections/app_memory.rs +++ b/src/linux/sections/app_memory.rs @@ -12,7 +12,7 @@ pub fn write( app_memory.length, )?; - let section = MemoryArrayWriter::::alloc_from_array(buffer, &data_copy)?; + let section = MemoryArrayWriter::write_bytes(buffer, &data_copy); let desc = MDMemoryDescriptor { start_of_memory_range: app_memory.ptr as u64, memory: section.location(), diff --git a/src/linux/sections/mappings.rs b/src/linux/sections/mappings.rs index 642e9736..6fb875fc 100644 --- a/src/linux/sections/mappings.rs +++ b/src/linux/sections/mappings.rs @@ -54,7 +54,7 @@ pub fn write( }; if !modules.is_empty() { - let mapping_list = MemoryArrayWriter::::alloc_from_array(buffer, &modules)?; + let mapping_list = MemoryArrayWriter::::alloc_from_iter(buffer, modules)?; dirent.location.data_size += mapping_list.location().data_size; } @@ -70,7 +70,7 @@ fn fill_raw_module( // Just zeroes Default::default() } else { - let cv_signature = MD_CVINFOELF_SIGNATURE; + let cv_signature = minidump_common::format::CvSignature::Elf as u32; let array_size = std::mem::size_of_val(&cv_signature) + identifier.len(); let mut sig_section = MemoryArrayWriter::::alloc_array(buffer, array_size)?; diff --git a/src/linux/sections/systeminfo_stream.rs b/src/linux/sections/systeminfo_stream.rs index 18af398d..5fc68eff 100644 --- a/src/linux/sections/systeminfo_stream.rs +++ b/src/linux/sections/systeminfo_stream.rs @@ -1,5 +1,5 @@ use super::*; -use crate::linux::dumper_cpu_info::{write_cpu_information, write_os_information}; +use crate::linux::dumper_cpu_info::{os_information, write_cpu_information}; type Result = std::result::Result; @@ -9,9 +9,16 @@ pub fn write(buffer: &mut DumpBuf) -> Result { stream_type: MDStreamType::SystemInfoStream as u32, location: info_section.location(), }; - let mut info: MDRawSystemInfo = Default::default(); + + let (platform_id, os_version) = os_information(); + let os_version_loc = write_string_to_location(buffer, &os_version)?; + + // SAFETY: POD + let mut info = unsafe { std::mem::zeroed::() }; + info.platform_id = platform_id as u32; + info.csd_version_rva = os_version_loc.rva; + write_cpu_information(&mut info)?; - write_os_information(buffer, &mut info)?; info_section.set_value(buffer, info)?; Ok(dirent) diff --git a/src/linux/sections/thread_list_stream.rs b/src/linux/sections/thread_list_stream.rs index 6d30e2c1..24fff508 100644 --- a/src/linux/sections/thread_list_stream.rs +++ b/src/linux/sections/thread_list_stream.rs @@ -3,7 +3,6 @@ use crate::{ linux::crash_context::CpuContext, minidump_cpu::RawContextCPU, minidump_writer::CrashingThreadContext, }; -use std::io::Write; type Result = std::result::Result; @@ -66,7 +65,12 @@ pub fn write( for (idx, item) in dumper.threads.clone().iter().enumerate() { let mut thread = MDRawThread { thread_id: item.tid.try_into()?, - ..Default::default() + suspend_count: 0, + priority_class: 0, + priority: 0, + teb: 0, + stack: MDMemoryDescriptor::default(), + thread_context: MDLocationDescriptor::default(), }; // We have a different source of information for the crashing thread. If @@ -230,7 +234,7 @@ fn fill_thread_stack( data_size: stack_bytes.len() as u32, rva: buffer.position() as u32, }; - buffer.write_all(&stack_bytes)?; + buffer.write_all(&stack_bytes); thread.stack.start_of_memory_range = stack as u64; thread.stack.memory = stack_location; config.memory_blocks.push(thread.stack.clone()); diff --git a/src/linux/thread_info/x86.rs b/src/linux/thread_info/x86.rs index 04db7b4d..944a4e47 100644 --- a/src/linux/thread_info/x86.rs +++ b/src/linux/thread_info/x86.rs @@ -1,15 +1,12 @@ use super::{CommonThreadInfo, NT_Elf, Pid}; use crate::errors::ThreadInfoError; -use crate::minidump_cpu::imp::*; use crate::minidump_cpu::RawContextCPU; #[cfg(target_arch = "x86_64")] use crate::thread_info::copy_u32_registers; use core::mem::size_of_val; -use libc; -use libc::user; +use libc::{self, user}; use memoffset; -use nix::sys::ptrace; -use nix::unistd; +use nix::{sys::ptrace, unistd}; type Result = std::result::Result; @@ -144,7 +141,9 @@ impl ThreadInfoX86 { #[cfg(target_arch = "x86_64")] pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { - out.context_flags = MD_CONTEXT_AMD64_FULL | MD_CONTEXT_AMD64_SEGMENTS; + out.context_flags = crate::minidump_format::format::ContextFlagsAmd64::CONTEXT_AMD64_FULL + .bits() + | crate::minidump_format::format::ContextFlagsAmd64::CONTEXT_AMD64_SEGMENTS.bits(); out.cs = self.regs.cs as u16; // TODO: This is u64, do we loose information by doing this? @@ -186,19 +185,31 @@ impl ThreadInfoX86 { out.rip = self.regs.rip; - out.flt_save.control_word = self.fpregs.cwd; - out.flt_save.status_word = self.fpregs.swd; - out.flt_save.tag_word = self.fpregs.ftw as u8; // TODO: This is u16, do we loose information by doing this? - out.flt_save.error_opcode = self.fpregs.fop; - out.flt_save.error_offset = self.fpregs.rip as u32; // TODO: This is u64, do we loose information by doing this? - out.flt_save.error_selector = 0; // We don't have this. - out.flt_save.data_offset = self.fpregs.rdp as u32; // TODO: This is u64, do we loose information by doing this? - out.flt_save.data_selector = 0; // We don't have this. - out.flt_save.mx_csr = self.fpregs.mxcsr; - out.flt_save.mx_csr_mask = self.fpregs.mxcr_mask; - - copy_u32_registers(&mut out.flt_save.float_registers, &self.fpregs.st_space); - copy_u32_registers(&mut out.flt_save.xmm_registers, &self.fpregs.xmm_space); + { + let fs = self.fpregs; + let mut float_save = crate::minidump_cpu::FloatStateCPU { + 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); + + use scroll::Pwrite; + // TODO: handle errors + out.float_save + .pwrite_with(float_save, 0, scroll::Endian::Little) + .unwrap(); + } } #[cfg(target_arch = "x86")] diff --git a/src/minidump_cpu.rs b/src/minidump_cpu.rs index 104553eb..7bd08c06 100644 --- a/src/minidump_cpu.rs +++ b/src/minidump_cpu.rs @@ -1,8 +1,7 @@ cfg_if::cfg_if! { if #[cfg(target_arch = "x86_64")] { - pub mod amd64; - pub use amd64 as imp; - pub type RawContextCPU = amd64::MDRawContextAMD64; + pub type RawContextCPU = minidump_common::format::CONTEXT_AMD64; + pub type FloatStateCPU = minidump_common::format::XMM_SAVE_AREA32; } else if #[cfg(target_arch = "x86")] { pub mod x86; pub use x86 as imp; diff --git a/src/minidump_cpu/amd64.rs b/src/minidump_cpu/amd64.rs deleted file mode 100644 index 3924d792..00000000 --- a/src/minidump_cpu/amd64.rs +++ /dev/null @@ -1,179 +0,0 @@ -#[repr(C)] -pub struct MDXmmSaveArea32AMD64 { - pub control_word: u16, - pub status_word: u16, - pub tag_word: u8, - pub reserved1: u8, - pub error_opcode: u16, - pub error_offset: u32, - pub error_selector: u16, - pub reserved2: u16, - pub data_offset: u32, - pub data_selector: u16, - pub reserved3: u16, - pub mx_csr: u32, - pub mx_csr_mask: u32, - pub float_registers: [u128; 8], - pub xmm_registers: [u128; 16], - pub reserved4: [u8; 96], -} - -// The std library doesn't provide "Default" for all -// array-lengths. Only up to 32. So we have to implement -// our own default, because of `reserved4: [u8; 96]` -impl Default for MDXmmSaveArea32AMD64 { - #[inline] - fn default() -> Self { - MDXmmSaveArea32AMD64 { - control_word: 0, - status_word: 0, - tag_word: 0, - reserved1: 0, - error_opcode: 0, - error_offset: 0, - error_selector: 0, - reserved2: 0, - data_offset: 0, - data_selector: 0, - reserved3: 0, - mx_csr: 0, - mx_csr_mask: 0, - float_registers: [0; 8], - xmm_registers: [0; 16], - reserved4: [0; 96], - } - } -} - -const MD_CONTEXT_AMD64_VR_COUNT: usize = 26; - -#[repr(C)] -#[derive(Default)] -pub struct MDRawContextAMD64 { - /* - * Register parameter home addresses. - */ - pub p1_home: u64, - pub p2_home: u64, - pub p3_home: u64, - pub p4_home: u64, - pub p5_home: u64, - pub p6_home: u64, - - /* The next field determines the layout of the structure, and which parts - * of it are populated */ - pub context_flags: u32, - pub mx_csr: u32, - - /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ - pub cs: u16, - - /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */ - pub ds: u16, - pub es: u16, - pub fs: u16, - pub gs: u16, - - /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */ - pub ss: u16, - pub eflags: u32, - - /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ - pub dr0: u64, - pub dr1: u64, - pub dr2: u64, - pub dr3: u64, - pub dr6: u64, - pub dr7: u64, - - /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */ - pub rax: u64, - pub rcx: u64, - pub rdx: u64, - pub rbx: u64, - - /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ - pub rsp: u64, - - /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */ - pub rbp: u64, - pub rsi: u64, - pub rdi: u64, - pub r8: u64, - pub r9: u64, - pub r10: u64, - pub r11: u64, - pub r12: u64, - pub r13: u64, - pub r14: u64, - pub r15: u64, - - /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ - pub rip: u64, - - /* The next set of registers are included with - * MD_CONTEXT_AMD64_FLOATING_POINT - */ - pub flt_save: MDXmmSaveArea32AMD64, - // union { - // MDXmmSaveArea32AMD64 flt_save; - // struct { - // uint128_struct header[2]; - // uint128_struct legacy[8]; - // uint128_struct xmm0; - // uint128_struct xmm1; - // uint128_struct xmm2; - // uint128_struct xmm3; - // uint128_struct xmm4; - // uint128_struct xmm5; - // uint128_struct xmm6; - // uint128_struct xmm7; - // uint128_struct xmm8; - // uint128_struct xmm9; - // uint128_struct xmm10; - // uint128_struct xmm11; - // uint128_struct xmm12; - // uint128_struct xmm13; - // uint128_struct xmm14; - // uint128_struct xmm15; - // } sse_registers; - // }; - pub vector_register: [u128; MD_CONTEXT_AMD64_VR_COUNT], - pub vector_control: u64, - - /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ - pub debug_control: u64, - pub last_branch_to_rip: u64, - pub last_branch_from_rip: u64, - pub last_exception_to_rip: u64, - pub last_exception_from_rip: u64, -} - -/* For (MDRawContextAMD64).context_flags. These values indicate the type of -* context stored in the structure. The high 24 bits identify the CPU, the -* low 8 bits identify the type of context saved. */ -pub const MD_CONTEXT_AMD64: u32 = 0x00100000; /* CONTEXT_AMD64 */ -pub const MD_CONTEXT_AMD64_CONTROL: u32 = MD_CONTEXT_AMD64 | 0x00000001; -/* CONTEXT_CONTROL */ -pub const MD_CONTEXT_AMD64_INTEGER: u32 = MD_CONTEXT_AMD64 | 0x00000002; -/* CONTEXT_INTEGER */ -pub const MD_CONTEXT_AMD64_SEGMENTS: u32 = MD_CONTEXT_AMD64 | 0x00000004; -/* CONTEXT_SEGMENTS */ -pub const MD_CONTEXT_AMD64_FLOATING_POINT: u32 = MD_CONTEXT_AMD64 | 0x00000008; -/* CONTEXT_FLOATING_POINT */ -pub const MD_CONTEXT_AMD64_DEBUG_REGISTERS: u32 = MD_CONTEXT_AMD64 | 0x00000010; -/* CONTEXT_DEBUG_REGISTERS */ -pub const MD_CONTEXT_AMD64_XSTATE: u32 = MD_CONTEXT_AMD64 | 0x00000040; -/* CONTEXT_XSTATE */ - -/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it -* I think it really means CONTEXT_FLOATING_POINT. -*/ - -pub const MD_CONTEXT_AMD64_FULL: u32 = - MD_CONTEXT_AMD64_CONTROL | MD_CONTEXT_AMD64_INTEGER | MD_CONTEXT_AMD64_FLOATING_POINT; -/* CONTEXT_FULL */ - -pub const MD_CONTEXT_AMD64_ALL: u32 = - MD_CONTEXT_AMD64_FULL | MD_CONTEXT_AMD64_SEGMENTS | MD_CONTEXT_AMD64_DEBUG_REGISTERS; -/* CONTEXT_ALL */ diff --git a/src/minidump_format.rs b/src/minidump_format.rs index a14026b3..8ffa40fc 100644 --- a/src/minidump_format.rs +++ b/src/minidump_format.rs @@ -1,437 +1,40 @@ -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDGUID { - data1: u32, - data2: u16, - data3: u16, - data4: [u8; 8], -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq, Clone, Copy)] -pub struct MDVSFixedFileInfo { - pub signature: u32, - pub struct_version: u32, - pub file_version_hi: u32, - pub file_version_lo: u32, - pub product_version_hi: u32, - pub product_version_lo: u32, - pub file_flags_mask: u32, /* Identifies valid bits in fileFlags */ - pub file_flags: u32, - pub file_os: u32, - pub file_type: u32, - pub file_subtype: u32, - pub file_date_hi: u32, - pub file_date_lo: u32, -} +pub use minidump_common::format::{ + self, ArmElfHwCaps as MDCPUInformationARMElfHwCaps, PlatformId, + ProcessorArchitecture as MDCPUArchitecture, GUID, MINIDUMP_DIRECTORY as MDRawDirectory, + MINIDUMP_EXCEPTION as MDException, MINIDUMP_EXCEPTION_STREAM as MDRawExceptionStream, + MINIDUMP_HEADER as MDRawHeader, MINIDUMP_LOCATION_DESCRIPTOR as MDLocationDescriptor, + MINIDUMP_MEMORY_DESCRIPTOR as MDMemoryDescriptor, MINIDUMP_MODULE as MDRawModule, + MINIDUMP_SIGNATURE as MD_HEADER_SIGNATURE, MINIDUMP_STREAM_TYPE as MDStreamType, + MINIDUMP_SYSTEM_INFO as MDRawSystemInfo, MINIDUMP_THREAD as MDRawThread, + MINIDUMP_THREAD_NAME as MDRawThreadName, MINIDUMP_VERSION as MD_HEADER_VERSION, + VS_FIXEDFILEINFO as MDVSFixedFileInfo, +}; /* An MDRVA is an offset into the minidump file. The beginning of the * MDRawHeader is at offset 0. */ pub type MDRVA = u32; -#[repr(C)] -#[derive(Debug, Default, Clone, Copy, PartialEq)] -pub struct MDLocationDescriptor { - pub data_size: u32, - pub rva: MDRVA, -} - -#[repr(C)] -#[derive(Debug, Default, Clone, PartialEq)] -pub struct MDMemoryDescriptor { - /* The base address of the memory range on the host that produced the - * minidump. */ - pub start_of_memory_range: u64, - pub memory: MDLocationDescriptor, -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawHeader { - pub signature: u32, - pub version: u32, - pub stream_count: u32, - pub stream_directory_rva: MDRVA, /* A |stream_count|-sized array of - * MDRawDirectory structures. */ - pub checksum: u32, /* Can be 0. In fact, that's all that's - * been found in minidump files. */ - pub time_date_stamp: u32, /* time_t */ - pub flags: u64, -} - -/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the - * low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the - * documentation, the high 16 bits are implementation-specific. */ -pub const MD_HEADER_SIGNATURE: u32 = 0x504d444d; /* 'PMDM' */ -/* MINIDUMP_SIGNATURE */ -pub const MD_HEADER_VERSION: u32 = 0x0000a793; /* 42899 */ -/* MINIDUMP_VERSION */ - -/// The name of a thread, found in the [`MDStreamType::ThreadNamesStream`]. -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct MDRawThreadName { - /// The id of the thread. - pub thread_id: u32, - /// Where the name of the thread is stored (yes, the legendary RVA64 is real!!). - pub thread_name_rva: u64, -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawThread { - pub thread_id: u32, - pub suspend_count: u32, - pub priority_class: u32, - pub priority: u32, - pub teb: u64, /* Thread environment block */ - pub stack: MDMemoryDescriptor, - pub thread_context: MDLocationDescriptor, /* MDRawContext[CPU] */ -} - pub type MDRawThreadList = Vec; -/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to - * be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC). - * This doesn't occur on systems that don't tail-pad in this manner. Define - * this macro to be the usable size of the MDRawModule struct, and use it in - * place of sizeof(MDRawModule). */ -// pub const MD_MODULE_SIZE: usize = 108; -// NOTE: We use "packed" here instead, to size_of::() == 108 -// "packed" should be safe here, as we don't address reserved{0,1} at all -// and padding should happen only at the tail -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default, PartialEq)] -pub struct MDRawModule { - pub base_of_image: u64, - pub size_of_image: u32, - pub checksum: u32, /* 0 if unknown */ - pub time_date_stamp: u32, /* time_t */ - pub module_name_rva: MDRVA, /* MDString, pathname or filename */ - pub version_info: MDVSFixedFileInfo, - - /* The next field stores a CodeView record and is populated when a module's - * debug information resides in a PDB file. It identifies the PDB file. */ - pub cv_record: MDLocationDescriptor, - - /* The next field is populated when a module's debug information resides - * in a DBG file. It identifies the DBG file. This field is effectively - * obsolete with modules built by recent toolchains. */ - pub misc_record: MDLocationDescriptor, - - /* Alignment problem: reserved0 and reserved1 are defined by the platform - * SDK as 64-bit quantities. However, that results in a structure whose - * alignment is unpredictable on different CPUs and ABIs. If the ABI - * specifies full alignment of 64-bit quantities in structures (as ppc - * does), there will be padding between miscRecord and reserved0. If - * 64-bit quantities can be aligned on 32-bit boundaries (as on x86), - * this padding will not exist. (Note that the structure up to this point - * contains 1 64-bit member followed by 21 32-bit members.) - * As a workaround, reserved0 and reserved1 are instead defined here as - * four 32-bit quantities. This should be harmless, as there are - * currently no known uses for these fields. */ - pub reserved0: [u32; 2], - pub reserved1: [u32; 2], -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq, Clone)] -pub struct MDRawDirectory { - pub stream_type: u32, - pub location: MDLocationDescriptor, -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDException { - pub exception_code: u32, /* Windows: MDExceptionCodeWin, - * Mac OS X: MDExceptionMac, - * Linux: MDExceptionCodeLinux. */ - pub exception_flags: u32, /* Windows: 1 if noncontinuable, - Mac OS X: MDExceptionCodeMac. */ - pub exception_record: u64, /* Address (in the minidump-producing host's - * memory) of another MDException, for - * nested exceptions. */ - pub exception_address: u64, /* The address that caused the exception. - * Mac OS X: exception subcode (which is - * typically the address). */ - pub number_parameters: u32, /* Number of valid elements in - * exception_information. */ - pub __align: u32, - pub exception_information: [u64; 15], -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawExceptionStream { - pub thread_id: u32, /* Thread in which the exception - * occurred. Corresponds to - * (MDRawThread).thread_id. */ - pub __align: u32, - pub exception_record: MDException, - pub thread_context: MDLocationDescriptor, /* MDRawContext[CPU] */ -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDCPUInformation { - pub vendor_id: [u32; 3], /* cpuid 0: ebx, edx, ecx */ - pub version_information: u32, /* cpuid 1: eax */ - pub feature_information: u32, /* cpuid 1: edx */ - pub amd_extended_cpu_features: u32, /* cpuid 0x80000001, ebx */ -} - -#[cfg(any(target_arch = "arm", target_arch = "aarch64"))] -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDCPUInformation { - pub cpuid: u32, - pub elf_hwcaps: u32, /* linux specific, 0 otherwise */ - _padding: [u32; 4], -} - -#[cfg(target_arch = "mips")] -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDCPUInformation { - pub cpuid: [u64; 2], - _padding: [u32; 2], -} - -/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps. - * This matches the Linux kernel definitions from */ -#[repr(u32)] -pub enum MDCPUInformationARMElfHwCaps { - Swp = 1 << 0, - Half = 1 << 1, - Thumb = 1 << 2, - Bit26 = 1 << 3, - FastMult = 1 << 4, - Fpa = 1 << 5, - Vfp = 1 << 6, - Edsp = 1 << 7, - Java = 1 << 8, - Iwmmxt = 1 << 9, - Crunch = 1 << 10, - Thumbee = 1 << 11, - Neon = 1 << 12, - Vfpv3 = 1 << 13, - Vfpv3d16 = 1 << 14, - Tls = 1 << 15, - Vfpv4 = 1 << 16, - Idiva = 1 << 17, - Idivt = 1 << 18, -} - -#[repr(C)] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawSystemInfo { - /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO - * structure as returned by GetSystemInfo */ - pub processor_architecture: u16, - pub processor_level: u16, /* x86: 5 = 586, 6 = 686, ... */ - /* ARM: 6 = ARMv6, 7 = ARMv7 ... */ - pub processor_revision: u16, /* x86: 0xMMSS, where MM=model, - * SS=stepping */ - /* ARM: 0 */ - pub number_of_processors: u8, - pub product_type: u8, /* Windows: VER_NT_* from WinNT.h */ - - /* The next 5 fields are from the OSVERSIONINFO structure as returned - * by GetVersionEx */ - pub major_version: u32, - pub minor_version: u32, - pub build_number: u32, - pub platform_id: u32, - pub csd_version_rva: MDRVA, /* MDString further identifying the - * host OS. - * Windows: name of the installed OS - * service pack. - * Mac OS X: the Apple OS build number - * (sw_vers -buildVersion). - * Linux: uname -srvmo */ - - pub suite_mask: u16, /* Windows: VER_SUITE_* from WinNT.h */ - pub reserved2: u16, - - pub cpu: MDCPUInformation, -} - -#[cfg(target_pointer_width = "64")] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawLinkMap { - pub addr: u64, - pub name: MDRVA, - pub ld: u64, -} - -#[cfg(target_pointer_width = "64")] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawDebug { - pub version: u32, - pub map: MDRVA, /* array of MDRawLinkMap64 */ - pub dso_count: u32, - pub brk: u64, - pub ldbase: u64, - pub dynamic: u64, -} - -#[cfg(target_pointer_width = "32")] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawLinkMap { - pub addr: u32, - pub name: MDRVA, - pub ld: u32, -} - -#[cfg(target_pointer_width = "32")] -#[derive(Debug, Default, PartialEq)] -pub struct MDRawDebug { - pub version: u32, - pub map: MDRVA, /* array of MDRawLinkMap32 */ - pub dso_count: u32, - pub brk: u32, - pub ldbase: u32, - pub dynamic: u32, -} - -/* For (MDRawSystemInfo).processor_architecture: */ -#[repr(u16)] -pub enum MDCPUArchitecture { - X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ - Mips = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ - Alpha = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ - Ppc = 3, /* PROCESSOR_ARCHITECTURE_PPC */ - Shx = 4, /* PROCESSOR_ARCHITECTURE_SHX - * (Super-H) */ - Arm = 5, /* PROCESSOR_ARCHITECTURE_ARM */ - Ia64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ - Alpha64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ - Msil = 8, /* PROCESSOR_ARCHITECTURE_MSIL - * (Microsoft Intermediate Language) */ - Amd64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ - X86Win64 = 10, - /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ - Arm64 = 12, /* PROCESSOR_ARCHITECTURE_ARM64 */ - Sparc = 0x8001, /* Breakpad-defined value for SPARC */ - Ppc64 = 0x8002, /* Breakpad-defined value for PPC64 */ - Arm64Old = 0x8003, /* Breakpad-defined value for ARM64 */ - Mips64 = 0x8004, /* Breakpad-defined value for MIPS64 */ - Unknown = 0xffff, /* PROCESSOR_ARCHITECTURE_UNKNOWN */ -} - -/* For (MDRawSystemInfo).platform_id: */ -#[repr(u32)] -pub enum MDOSPlatform { - Win32s = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ - Win32Windows = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ - Win32Nt = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ - Win32Ce = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH - * (Windows CE, Windows Mobile, "Handheld") */ - /* The following values are Breakpad-defined. */ - Unix = 0x8000, /* Generic Unix-ish */ - MacOsX = 0x8101, /* Mac OS X/Darwin */ - Ios = 0x8102, /* iOS */ - Linux = 0x8201, /* Linux */ - Solaris = 0x8202, /* Solaris */ - Android = 0x8203, /* Android */ - Ps3 = 0x8204, /* PS3 */ - Nacl = 0x8205, /* Native Client (NaCl) */ - Fuchsia = 0x8206, /* Fuchsia */ -} - -/* - * Modern ELF toolchains insert a "build id" into the ELF headers that - * usually contains a hash of some ELF headers + sections to uniquely - * identify a binary. - * - * https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/compiling-build-id.html - * https://sourceware.org/binutils/docs-2.26/ld/Options.html#index-g_t_002d_002dbuild_002did-292 - */ -pub const MD_CVINFOELF_SIGNATURE: u32 = 0x4270454c; /* cvSignature = 'BpEL' */ -/* Signature is followed by the bytes of the - * build id from GNU_BUILD_ID ELF note. - * This is variable-length, but usually 20 bytes - * as the binutils ld default is a SHA-1 hash. */ - -/* For (MDRawHeader).flags: */ -pub enum MDType { - /* MD_NORMAL is the standard type of minidump. It includes full - * streams for the thread list, module list, exception, system info, - * and miscellaneous info. A memory list stream is also present, - * pointing to the same stack memory contained in the thread list, - * as well as a 256-byte region around the instruction address that - * was executing when the exception occurred. Stack memory is from - * 4 bytes below a thread's stack pointer up to the top of the - * memory region encompassing the stack. */ - Normal = 0x00000000, - WithDataSegs = 0x00000001, - WithFullMemory = 0x00000002, - WithHandleData = 0x00000004, - FilterMemory = 0x00000008, - ScanMemory = 0x00000010, - WithUnloadedModules = 0x00000020, - WithIndirectlyReferencedMemory = 0x00000040, - FilterModulePaths = 0x00000080, - WithProcessThreadData = 0x00000100, - WithPrivateReadWriteMemory = 0x00000200, - WithoutOptionalData = 0x00000400, - WithFullMemoryInfo = 0x00000800, - WithThreadInfo = 0x00001000, - WithCodeSegs = 0x00002000, - WithoutAuxilliarySegs = 0x00004000, - WithFullAuxilliaryState = 0x00008000, - WithPrivateWriteCopyMemory = 0x00010000, - IgnoreInaccessibleMemory = 0x00020000, - WithTokenInformation = 0x00040000, -} - -/* For (MDRawDirectory).stream_type */ -#[repr(u32)] -pub enum MDStreamType { - UnusedStream = 0, - ReservedStream0 = 1, - ReservedStream1 = 2, - ThreadListStream = 3, /* MDRawThreadList */ - ModuleListStream = 4, /* MDRawModuleList */ - MemoryListStream = 5, /* MDRawMemoryList */ - ExceptionStream = 6, /* MDRawExceptionStream */ - SystemInfoStream = 7, /* MDRawSystemInfo */ - ThreadExListStream = 8, - Memory64ListStream = 9, - CommentStreamA = 10, - CommentStreamW = 11, - HandleDataStream = 12, - FunctionTableStream = 13, - UnloadedModuleListStream = 14, - MiscInfoStream = 15, /* MDRawMiscInfo */ - MemoryInfoListStream = 16, /* MDRawMemoryInfoList */ - ThreadInfoListStream = 17, - HandleOperationListStream = 18, - TokenStream = 19, - JavascriptDataStream = 20, - SystemMemoryInfoStream = 21, - ProcessVmCountersStream = 22, - IptTraceStream = 23, - ThreadNamesStream = 24, - LastReservedStream = 0x0000ffff, - - /* Breakpad extension types. 0x4767 = "Gg" */ - BreakpadInfoStream = 0x47670001, /* MDRawBreakpadInfo */ - AssertionInfoStream = 0x47670002, /* MDRawAssertionInfo */ - /* These are additional minidump stream values which are specific to - * the linux breakpad implementation. */ - LinuxCpuInfo = 0x47670003, /* /proc/cpuinfo */ - LinuxProcStatus = 0x47670004, /* /proc/$x/status */ - LinuxLsbRelease = 0x47670005, /* /etc/lsb-release */ - LinuxCmdLine = 0x47670006, /* /proc/$x/cmdline */ - LinuxEnviron = 0x47670007, /* /proc/$x/environ */ - LinuxAuxv = 0x47670008, /* /proc/$x/auxv */ - LinuxMaps = 0x47670009, /* /proc/$x/maps */ - LinuxDsoDebug = 0x4767000A, /* MDRawDebug{32,64} */ - - /* Crashpad extension types. 0x4350 = "CP" - * See Crashpad's minidump/minidump_extensions.h. */ - CrashpadInfoStream = 0x43500001, /* MDRawCrashpadInfo */ +cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + pub use format::X86CpuInfo as MDCPUInformation; + } else if #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { + pub use format::ARMCpuInfo as MDCPUInformation; + } else if #[cfg(target_arch = "mips")] { + pub struct MDCPUInformation { + pub cpuid: [u64; 2], + _padding: [u32; 2], + } + } +} + +cfg_if::cfg_if! { + if #[cfg(target_pointer_width = "64")] { + pub use format::LINK_MAP_64 as MDRawLinkMap; + pub use format::DSO_DEBUG_64 as MDRawDebug; + } else if #[cfg(target_pointer_width = "32")] { + pub use format::LINK_MAP_32 as MDRawLinkMap; + pub use format::DSO_DEBUG_32 as MDRawDebug; + } } diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index 3e568fb2..c2752af3 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -170,7 +170,7 @@ fn test_write_and_read_dump_from_parent_helper(context: Context) { assert_eq!(module.code_file(), "a fake mapping"); assert_eq!( module.debug_identifier(), - Some("33221100554477668899AABBCCDDEEFF0".into()) + Some("33221100554477668899AABBCCDDEEFF0".parse().unwrap()) ); let _: MinidumpException = dump.get_stream().expect("Couldn't find MinidumpException"); @@ -511,7 +511,7 @@ fn test_with_deleted_binary() { assert_eq!(main_module.code_file(), binary_copy.to_string_lossy()); assert_eq!( main_module.debug_identifier(), - Some(std::borrow::Cow::from(filtered.as_str())) + Some(filtered.parse().unwrap()) ); } From 0dc99fc07d63e8c62019bb992cdbcb3407c09911 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 10 Mar 2022 07:27:01 +0100 Subject: [PATCH 18/21] Fixup --- Cargo.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 14bd0e9a..ab8cce96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,24 +8,24 @@ license = "MIT" [dependencies] byteorder = "1.3.2" cfg-if = "1.0" -exception-handler = { path = "../crash-handling/exception-handler" } +exception-handler = { path = "../exception-handler" } goblin = "0.5" libc = "0.2.74" memmap2 = "0.5" memoffset = "0.6" -minidump = "*" -minidump-common = "*" +minidump-common = "0.9" nix = "0.23" scroll = "0.11" tempfile = "3.1.0" thiserror = "1.0.21" [dev-dependencies] -uctx = { path = "../crash-handling/uctx" } debugid = "0.7.3" +minidump = "0.9" +uctx = { path = "../uctx" } [patch.crates-io] -#minidump = { git = "https://github.com/EmbarkStudios/rust-minidump", rev = "228c5d0" } -#minidump-common = { git = "https://github.com/EmbarkStudios/rust-minidump", rev = "228c5d0" } -minidump = { path = "../rust-minidump/minidump" } -minidump-common = { path = "../rust-minidump/minidump-common" } +minidump = { git = "https://github.com/luser/rust-minidump", rev = "b8e6b18c3164c124c12d9ce9819e4cb9809b5e09" } +minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "b8e6b18c3164c124c12d9ce9819e4cb9809b5e09" } +#minidump = { path = "../rust-minidump/minidump" } +#minidump-common = { path = "../rust-minidump/minidump-common" } From 31e1bca905665bc99cea93434348ef7911a2032e Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 10 Mar 2022 16:23:21 +0100 Subject: [PATCH 19/21] Replace x86_64 CrashContext with crash_context::CrashContext --- Cargo.toml | 14 +++-- src/linux.rs | 1 - src/linux/crash_context.rs | 26 -------- src/linux/crash_context/x86_64.rs | 77 ------------------------ src/linux/minidump_writer.rs | 10 +-- src/linux/sections/thread_list_stream.rs | 10 ++- src/linux/thread_info/x86.rs | 18 +++--- tests/minidump_writer.rs | 6 +- 8 files changed, 27 insertions(+), 135 deletions(-) delete mode 100644 src/linux/crash_context.rs delete mode 100644 src/linux/crash_context/x86_64.rs diff --git a/Cargo.toml b/Cargo.toml index ab8cce96..38c109c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,6 @@ license = "MIT" [dependencies] byteorder = "1.3.2" cfg-if = "1.0" -exception-handler = { path = "../exception-handler" } goblin = "0.5" libc = "0.2.74" memmap2 = "0.5" @@ -19,13 +18,16 @@ scroll = "0.11" tempfile = "3.1.0" thiserror = "1.0.21" +[dependencies.crash-context] +git = "https://github.com/EmbarkStudios/crash-handling" +branch = "impl" +#path = "../crash-handling/crash-context" +features = ["fill-minidump"] + [dev-dependencies] debugid = "0.7.3" minidump = "0.9" -uctx = { path = "../uctx" } [patch.crates-io] -minidump = { git = "https://github.com/luser/rust-minidump", rev = "b8e6b18c3164c124c12d9ce9819e4cb9809b5e09" } -minidump-common = { git = "https://github.com/luser/rust-minidump", rev = "b8e6b18c3164c124c12d9ce9819e4cb9809b5e09" } -#minidump = { path = "../rust-minidump/minidump" } -#minidump-common = { path = "../rust-minidump/minidump-common" } +minidump = { git = "https://github.com/EmbarkStudios/rust-minidump", branch = "master" } +minidump-common = { git = "https://github.com/EmbarkStudios/rust-minidump", branch = "master" } diff --git a/src/linux.rs b/src/linux.rs index 3e9dde8a..8f8c649b 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -2,7 +2,6 @@ mod android; pub mod app_memory; mod auxv_reader; -pub mod crash_context; mod dso_debug; mod dumper_cpu_info; pub mod errors; diff --git a/src/linux/crash_context.rs b/src/linux/crash_context.rs deleted file mode 100644 index ce70a954..00000000 --- a/src/linux/crash_context.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Minidump defines register structures which are different from the raw -// structures which we get from the kernel. These are platform specific -// functions to juggle the ucontext_t and user structures into minidump format. - -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86_64")] { - mod x86_64; - } else if #[cfg(target_arch = "x86")] { - mod x86; - } else if #[cfg(target_arch = "aarch64")] { - mod aarch64; - } else if #[cfg(target_arch = "arm")] { - mod arm; - } else if #[cfg(target_arch = "mips")] { - mod mips; - } -} - -use crate::minidump_cpu::{FloatStateCPU, RawContextCPU}; -pub use exception_handler::CrashContext; - -pub trait CpuContext { - fn get_instruction_pointer(&self) -> usize; - fn get_stack_pointer(&self) -> usize; - fn fill_cpu_context(&self, cpu_ctx: &mut RawContextCPU); -} diff --git a/src/linux/crash_context/x86_64.rs b/src/linux/crash_context/x86_64.rs deleted file mode 100644 index f699e469..00000000 --- a/src/linux/crash_context/x86_64.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::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, -}; - -impl super::CpuContext for super::CrashContext { - fn get_instruction_pointer(&self) -> usize { - self.context.uc_mcontext.gregs[REG_RIP as usize] as usize - } - - fn get_stack_pointer(&self) -> usize { - self.context.uc_mcontext.gregs[REG_RSP as usize] as usize - } - - fn fill_cpu_context(&self, out: &mut super::RawContextCPU) { - out.context_flags = - crate::minidump_format::format::ContextFlagsAmd64::CONTEXT_AMD64_FULL.bits(); - - { - let gregs = &self.context.uc_mcontext.gregs; - out.cs = (gregs[REG_CSGSFS as usize] & 0xffff) as u16; - - out.fs = ((gregs[REG_CSGSFS as usize] >> 32) & 0xffff) as u16; - out.gs = ((gregs[REG_CSGSFS as usize] >> 16) & 0xffff) as u16; - - out.eflags = gregs[REG_EFL as usize] as u32; - - 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.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; - - out.rip = gregs[REG_RIP as usize] as u64; - } - - { - let fs = &self.float_state; - - let mut float_save = super::FloatStateCPU { - 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); - - use scroll::Pwrite; - // TODO: handle errors - out.float_save - .pwrite_with(float_save, 0, scroll::Endian::Little) - .unwrap(); - } - } -} diff --git a/src/linux/minidump_writer.rs b/src/linux/minidump_writer.rs index c2a1e4ec..86bbeaba 100644 --- a/src/linux/minidump_writer.rs +++ b/src/linux/minidump_writer.rs @@ -1,7 +1,6 @@ use crate::{ linux::{ app_memory::AppMemoryList, - crash_context::{CpuContext, CrashContext}, dso_debug, errors::{FileWriterError, InitError, MemoryWriterError, WriterError}, maps_reader::{MappingInfo, MappingList}, @@ -11,6 +10,7 @@ use crate::{ }, minidump_format::*, }; +use crash_context::{CpuContext, CrashContext}; use std::io::{Seek, SeekFrom, Write}; pub type DumpBuf = Buffer; @@ -229,12 +229,8 @@ impl MinidumpWriter { .system_mapping_info .end_address; - let pc = self - .crash_context - .as_ref() - .unwrap() - .get_instruction_pointer(); - let stack_pointer = self.crash_context.as_ref().unwrap().get_stack_pointer(); + let pc = self.crash_context.as_ref().unwrap().instruction_pointer(); + let stack_pointer = self.crash_context.as_ref().unwrap().stack_pointer(); if pc >= low_addr && pc < high_addr { return true; diff --git a/src/linux/sections/thread_list_stream.rs b/src/linux/sections/thread_list_stream.rs index 24fff508..3d6ac0ef 100644 --- a/src/linux/sections/thread_list_stream.rs +++ b/src/linux/sections/thread_list_stream.rs @@ -1,8 +1,6 @@ use super::*; -use crate::{ - linux::crash_context::CpuContext, minidump_cpu::RawContextCPU, - minidump_writer::CrashingThreadContext, -}; +use crate::{minidump_cpu::RawContextCPU, minidump_writer::CrashingThreadContext}; +use crash_context::CpuContext; type Result = std::result::Result; @@ -79,8 +77,8 @@ pub fn write( // unhelpful. if config.crash_context.is_some() && thread.thread_id == config.blamed_thread as u32 { let crash_context = config.crash_context.as_ref().unwrap(); - let instruction_ptr = crash_context.get_instruction_pointer() as usize; - let stack_pointer = crash_context.get_stack_pointer() as usize; + let instruction_ptr = crash_context.instruction_pointer(); + let stack_pointer = crash_context.stack_pointer(); fill_thread_stack( config, buffer, diff --git a/src/linux/thread_info/x86.rs b/src/linux/thread_info/x86.rs index 944a4e47..a680946f 100644 --- a/src/linux/thread_info/x86.rs +++ b/src/linux/thread_info/x86.rs @@ -145,15 +145,16 @@ impl ThreadInfoX86 { .bits() | crate::minidump_format::format::ContextFlagsAmd64::CONTEXT_AMD64_SEGMENTS.bits(); - out.cs = self.regs.cs as u16; // TODO: This is u64, do we loose information by doing this? + // TODO: These are all u64, do we lose information by doing this? + out.cs = self.regs.cs as u16; - out.ds = self.regs.ds as u16; // TODO: This is u64, do we loose information by doing this? - out.es = self.regs.es as u16; // TODO: This is u64, do we loose information by doing this? - out.fs = self.regs.fs as u16; // TODO: This is u64, do we loose information by doing this? - out.gs = self.regs.gs as u16; // TODO: This is u64, do we loose information by doing this? + out.ds = self.regs.ds as u16; + out.es = self.regs.es as u16; + out.fs = self.regs.fs as u16; + out.gs = self.regs.gs as u16; - out.ss = self.regs.ss as u16; // TODO: This is u64, do we loose information by doing this? - out.eflags = self.regs.eflags as u32; // TODO: This is u64, do we loose information by doing this? + out.ss = self.regs.ss as u16; + out.eflags = self.regs.eflags as u32; out.dr0 = self.dregs[0]; out.dr1 = self.dregs[1]; @@ -205,10 +206,9 @@ impl ThreadInfoX86 { copy_u32_registers(&mut float_save.xmm_registers, &fs.xmm_space); use scroll::Pwrite; - // TODO: handle errors out.float_save .pwrite_with(float_save, 0, scroll::Endian::Little) - .unwrap(); + .expect("this is impossible"); } } diff --git a/tests/minidump_writer.rs b/tests/minidump_writer.rs index c2752af3..4f4d907b 100644 --- a/tests/minidump_writer.rs +++ b/tests/minidump_writer.rs @@ -1,8 +1,8 @@ +use crash_context::CrashContext; use minidump::*; use minidump_common::format::{GUID, MINIDUMP_STREAM_TYPE::*}; use minidump_writer::{ app_memory::AppMemory, - crash_context::CrashContext, errors::*, maps_reader::{MappingEntry, MappingInfo, SystemMappingInfo}, minidump_writer::MinidumpWriter, @@ -27,10 +27,10 @@ enum Context { } #[cfg(not(any(target_arch = "mips", target_arch = "arm")))] -fn get_ucontext() -> Result { +fn get_ucontext() -> Result { let mut context = std::mem::MaybeUninit::uninit(); unsafe { - let res = uctx::getcontext(context.as_mut_ptr()); + let res = crash_context::crash_context_getcontext(context.as_mut_ptr()); Errno::result(res)?; Ok(context.assume_init()) From cf2984d666b77c6eb3e3e9b25ec8d97922f357d1 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Thu, 10 Mar 2022 16:23:43 +0100 Subject: [PATCH 20/21] Port x86 CrashContext --- src/linux/crash_context/x86.rs | 50 ----------- src/linux/thread_info/x86.rs | 110 ++++++++++-------------- src/minidump_cpu.rs | 5 +- src/minidump_cpu/x86.rs | 151 --------------------------------- 4 files changed, 47 insertions(+), 269 deletions(-) delete mode 100644 src/linux/crash_context/x86.rs delete mode 100644 src/minidump_cpu/x86.rs diff --git a/src/linux/crash_context/x86.rs b/src/linux/crash_context/x86.rs deleted file mode 100644 index 181deeae..00000000 --- a/src/linux/crash_context/x86.rs +++ /dev/null @@ -1,50 +0,0 @@ -use super::CrashContext; -use crate::minidump_cpu::imp::*; -use crate::minidump_cpu::RawContextCPU; -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, -}; -impl CrashContext { - pub fn get_instruction_pointer(&self) -> usize { - self.context.uc_mcontext.gregs[REG_EIP as usize] as usize - } - - pub fn get_stack_pointer(&self) -> usize { - self.context.uc_mcontext.gregs[REG_ESP as usize] as usize - } - - pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { - out.context_flags = MD_CONTEXT_X86_FULL | MD_CONTEXT_X86_FLOATING_POINT; - - 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; - - 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.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.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; - - // 8 registers * 10 bytes per register. - // my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); - } -} diff --git a/src/linux/thread_info/x86.rs b/src/linux/thread_info/x86.rs index a680946f..bd5ab6cc 100644 --- a/src/linux/thread_info/x86.rs +++ b/src/linux/thread_info/x86.rs @@ -214,7 +214,7 @@ impl ThreadInfoX86 { #[cfg(target_arch = "x86")] pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { - out.context_flags = MD_CONTEXT_X86_ALL; + out.context_flags = crate::minidump_format::format::ContextFlagsX86::CONTEXT_X86_ALL.bits(); out.dr0 = self.dregs[0] as u32; out.dr3 = self.dregs[3] as u32; @@ -252,74 +252,54 @@ impl ThreadInfoX86 { out.float_save.data_offset = self.fpregs.foo as u32; out.float_save.data_selector = self.fpregs.fos as u32; - // 8 registers * 10 bytes per register. - // my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); - out.float_save.register_area = self - .fpregs - .st_space - .iter() - .map(|x| x.to_ne_bytes().to_vec()) - .flatten() - .take(MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE) - .collect::>() - .as_slice() - .try_into() // Make slice into fixed size array - .unwrap(); // Which has to work as we know the numbers work out - - // This matches the Intel fpsave format. - let mut idx = 0; - for val in &(self.fpregs.cwd as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpregs.swd as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpregs.twd as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpxregs.fop as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpxregs.fip as u32).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpxregs.fcs as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpregs.foo as u32).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpregs.fos as u16).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; - } - for val in &(self.fpxregs.mxcsr as u32).to_ne_bytes() { - out.extended_registers[idx] = *val; - idx += 1; + use scroll::Pwrite; + { + let ra = &mut out.float_save.register_area; + // 8 registers * 10 bytes per register. + for (idx, block) in self.fpregs.st_space.iter().enumerate() { + let offset = idx * std::mem::size_of::(); + if offset >= ra.len() { + break; + } + + ra.pwrite_with(block, offset, scroll::Endian::Little) + .expect("checked"); + } } - // my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); - idx = 32; - for val in &self.fpxregs.st_space { - for byte in &val.to_ne_bytes() { - out.extended_registers[idx] = *byte; - idx += 1; + #[allow(unused_assignments)] + { + let mut offset = 0; + macro_rules! write_er { + ($reg:expr) => { + offset += out + .extended_registers + .pwrite_with($reg, offset, scroll::Endian::Little) + .unwrap() + }; } - } - // my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); - idx = 160; - for val in &self.fpxregs.xmm_space { - for byte in &val.to_ne_bytes() { - out.extended_registers[idx] = *byte; - idx += 1; + // This matches the Intel fpsave format. + write_er!(self.fpregs.cwd as u16); + write_er!(self.fpregs.swd as u16); + write_er!(self.fpregs.twd as u16); + write_er!(self.fpxregs.fop); + write_er!(self.fpxregs.fip); + write_er!(self.fpxregs.fcs); + write_er!(self.fpregs.foo); + write_er!(self.fpregs.fos); + write_er!(self.fpxregs.mxcsr); + + offset = 32; + + for val in &self.fpxregs.st_space { + write_er!(val); + } + + debug_assert_eq!(offset, 160); + + for val in &self.fpxregs.xmm_space { + write_er!(val); } } } diff --git a/src/minidump_cpu.rs b/src/minidump_cpu.rs index 7bd08c06..68474738 100644 --- a/src/minidump_cpu.rs +++ b/src/minidump_cpu.rs @@ -3,9 +3,8 @@ cfg_if::cfg_if! { pub type RawContextCPU = minidump_common::format::CONTEXT_AMD64; pub type FloatStateCPU = minidump_common::format::XMM_SAVE_AREA32; } else if #[cfg(target_arch = "x86")] { - pub mod x86; - pub use x86 as imp; - pub type RawContextCPU = amd64::MDRawContextX86; + pub type RawContextCPU = minidump_common::format::CONTEXT_X86; + pub type FloatStateCPU = minidump_common::format::FLOATING_SAVE_AREA_X86; } else if #[cfg(target_arch = "arm")] { pub mod arm; pub use arm as imp; diff --git a/src/minidump_cpu/x86.rs b/src/minidump_cpu/x86.rs deleted file mode 100644 index b0b073ff..00000000 --- a/src/minidump_cpu/x86.rs +++ /dev/null @@ -1,151 +0,0 @@ -pub const MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE: usize = 80; - -#[repr(C)] -#[derive(Debug, PartialEq)] -pub struct MDFloatingSaveAreaX86 { - pub control_word: u32, - pub status_word: u32, - pub tag_word: u32, - pub error_offset: u32, - pub error_selector: u32, - pub data_offset: u32, - pub data_selector: u32, - - /* register_area contains eight 80-bit (x87 "long double") quantities for - * floating-point registers %st0 (%mm0) through %st7 (%mm7). */ - pub register_area: [u8; MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE], - pub cr0_npx_state: u32, -} - -// The std library doesn't provide "Default" for all -// array-lengths. Only up to 32. So we have to implement -// our own default, because of `reserved4: [u8; 96]` -impl Default for MDFloatingSaveAreaX86 { - #[inline] - fn default() -> Self { - MDFloatingSaveAreaX86 { - control_word: 0, - status_word: 0, - tag_word: 0, - error_offset: 0, - error_selector: 0, - data_offset: 0, - data_selector: 0, - register_area: [0; MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE], - cr0_npx_state: 0, - } - } -} - -const MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE: usize = 512; -/* MAXIMUM_SUPPORTED_EXTENSION */ - -#[repr(C)] -#[derive(Debug, PartialEq)] -pub struct MDRawContextX86 { - /* The next field determines the layout of the structure, and which parts - * of it are populated */ - pub context_flags: u32, - - /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */ - pub dr0: u32, - pub dr1: u32, - pub dr2: u32, - pub dr3: u32, - pub dr6: u32, - pub dr7: u32, - - /* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */ - pub float_save: MDFloatingSaveAreaX86, - - /* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */ - pub gs: u32, - pub fs: u32, - pub es: u32, - pub ds: u32, - /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */ - pub edi: u32, - pub esi: u32, - pub ebx: u32, - pub edx: u32, - pub ecx: u32, - pub eax: u32, - - /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */ - pub ebp: u32, - pub eip: u32, - pub cs: u32, /* WinNT.h says "must be sanitized" */ - pub eflags: u32, /* WinNT.h says "must be sanitized" */ - pub esp: u32, - pub ss: u32, - - /* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS. - * It contains vector (MMX/SSE) registers. It it laid out in the - * format used by the fxsave and fsrstor instructions, so it includes - * a copy of the x87 floating-point registers as well. See FXSAVE in - * "Intel Architecture Software Developer's Manual, Volume 2." */ - pub extended_registers: [u8; MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE], -} - -impl Default for MDRawContextX86 { - #[inline] - fn default() -> Self { - MDRawContextX86 { - context_flags: 0, - dr0: 0, - dr1: 0, - dr2: 0, - dr3: 0, - dr6: 0, - dr7: 0, - float_save: Default::default(), - gs: 0, - fs: 0, - es: 0, - ds: 0, - edi: 0, - esi: 0, - ebx: 0, - edx: 0, - ecx: 0, - eax: 0, - ebp: 0, - eip: 0, - cs: 0, - eflags: 0, - esp: 0, - ss: 0, - extended_registers: [0; MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE], - } - } -} - -/* For (MDRawContextX86).context_flags. These values indicate the type of - * context stored in the structure. The high 24 bits identify the CPU, the - * low 8 bits identify the type of context saved. */ -pub const MD_CONTEXT_X86: u32 = 0x00010000; -/* CONTEXT_i386, CONTEXT_i486: identifies CPU */ -pub const MD_CONTEXT_X86_CONTROL: u32 = MD_CONTEXT_X86 | 0x00000001; -/* CONTEXT_CONTROL */ -pub const MD_CONTEXT_X86_INTEGER: u32 = MD_CONTEXT_X86 | 0x00000002; -/* CONTEXT_INTEGER */ -pub const MD_CONTEXT_X86_SEGMENTS: u32 = MD_CONTEXT_X86 | 0x00000004; -/* CONTEXT_SEGMENTS */ -pub const MD_CONTEXT_X86_FLOATING_POINT: u32 = MD_CONTEXT_X86 | 0x00000008; -/* CONTEXT_FLOATING_POINT */ -pub const MD_CONTEXT_X86_DEBUG_REGISTERS: u32 = MD_CONTEXT_X86 | 0x00000010; -/* CONTEXT_DEBUG_REGISTERS */ -pub const MD_CONTEXT_X86_EXTENDED_REGISTERS: u32 = MD_CONTEXT_X86 | 0x00000020; -/* CONTEXT_EXTENDED_REGISTERS */ -pub const MD_CONTEXT_X86_XSTATE: u32 = MD_CONTEXT_X86 | 0x00000040; -/* CONTEXT_XSTATE */ - -pub const MD_CONTEXT_X86_FULL: u32 = - MD_CONTEXT_X86_CONTROL | MD_CONTEXT_X86_INTEGER | MD_CONTEXT_X86_SEGMENTS; -/* CONTEXT_FULL */ - -pub const MD_CONTEXT_X86_ALL: u32 = MD_CONTEXT_X86_FULL - | MD_CONTEXT_X86_FLOATING_POINT - | MD_CONTEXT_X86_DEBUG_REGISTERS - | MD_CONTEXT_X86_EXTENDED_REGISTERS; -/* CONTEXT_ALL */ From 49d769bbcfe17a2af6c28b15043fff656b8ddf47 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Mon, 14 Mar 2022 10:38:09 +0100 Subject: [PATCH 21/21] Flesh out aarch64 --- Cargo.toml | 10 +-- src/linux/crash_context/aarch64.rs | 11 --- src/linux/dumper_cpu_info/arm.rs | 116 +++++++++++++++---------- src/linux/thread_info.rs | 14 +-- src/linux/thread_info/aarch64.rs | 133 +++++++++++++++++++++++------ src/linux/thread_info/arm.rs | 5 +- src/linux/thread_info/x86.rs | 7 +- src/minidump_cpu.rs | 7 +- src/minidump_cpu/aarch64.rs | 12 --- src/minidump_cpu/mips.rs | 1 - src/minidump_cpu/ppc.rs | 0 src/minidump_cpu/ppc64.rs | 0 src/minidump_cpu/sparc.rs | 0 13 files changed, 198 insertions(+), 118 deletions(-) delete mode 100644 src/linux/crash_context/aarch64.rs delete mode 100644 src/minidump_cpu/aarch64.rs delete mode 100644 src/minidump_cpu/mips.rs delete mode 100644 src/minidump_cpu/ppc.rs delete mode 100644 src/minidump_cpu/ppc64.rs delete mode 100644 src/minidump_cpu/sparc.rs diff --git a/Cargo.toml b/Cargo.toml index 38c109c5..7f5f8966 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,21 +12,21 @@ goblin = "0.5" libc = "0.2.74" memmap2 = "0.5" memoffset = "0.6" -minidump-common = "0.9" +minidump-common = "0.10" nix = "0.23" scroll = "0.11" tempfile = "3.1.0" thiserror = "1.0.21" [dependencies.crash-context] -git = "https://github.com/EmbarkStudios/crash-handling" -branch = "impl" -#path = "../crash-handling/crash-context" +#git = "https://github.com/EmbarkStudios/crash-handling" +#branch = "impl" +path = "../crash-handling/crash-context" features = ["fill-minidump"] [dev-dependencies] debugid = "0.7.3" -minidump = "0.9" +minidump = "0.10" [patch.crates-io] minidump = { git = "https://github.com/EmbarkStudios/rust-minidump", branch = "master" } diff --git a/src/linux/crash_context/aarch64.rs b/src/linux/crash_context/aarch64.rs deleted file mode 100644 index e6fb3f9e..00000000 --- a/src/linux/crash_context/aarch64.rs +++ /dev/null @@ -1,11 +0,0 @@ -use super::CrashContext; - -impl CrashContext { - pub fn get_instruction_pointer(&self) -> usize { - self.context.uc_mcontext.sp as usize - } - - pub fn get_stack_pointer(&self) -> usize { - self.context.uc_mcontext.pc as usize - } -} diff --git a/src/linux/dumper_cpu_info/arm.rs b/src/linux/dumper_cpu_info/arm.rs index 7d5b1ad5..67568516 100644 --- a/src/linux/dumper_cpu_info/arm.rs +++ b/src/linux/dumper_cpu_info/arm.rs @@ -86,43 +86,36 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { // The ELF hwcaps are listed in the "Features" entry as textual tags. // This table is used to rebuild them. - let cpu_features_entries; #[cfg(target_arch = "arm")] - { - cpu_features_entries = [ - CpuFeaturesEntry::new("swp", MDCPUInformationARMElfHwCaps::HWCAP_SWP), - CpuFeaturesEntry::new("half", MDCPUInformationARMElfHwCaps::HWCAP_HALF), - CpuFeaturesEntry::new("thumb", MDCPUInformationARMElfHwCaps::HWCAP_THUMB), - CpuFeaturesEntry::new("bit26", MDCPUInformationARMElfHwCaps::HWCAP_26BIT), - CpuFeaturesEntry::new("fastmult", MDCPUInformationARMElfHwCaps::HWCAP_FAST_MULT), - CpuFeaturesEntry::new("fpa", MDCPUInformationARMElfHwCaps::HWCAP_FPA), - CpuFeaturesEntry::new("vfp", MDCPUInformationARMElfHwCaps::HWCAP_VFP), - CpuFeaturesEntry::new("edsp", MDCPUInformationARMElfHwCaps::HWCAP_EDSP), - CpuFeaturesEntry::new("java", MDCPUInformationARMElfHwCaps::HWCAP_JAVA), - CpuFeaturesEntry::new("iwmmxt", MDCPUInformationARMElfHwCaps::HWCAP_IWMMXT), - CpuFeaturesEntry::new("crunch", MDCPUInformationARMElfHwCaps::HWCAP_CRUNCH), - CpuFeaturesEntry::new("thumbee", MDCPUInformationARMElfHwCaps::HWCAP_THUMBEE), - CpuFeaturesEntry::new("neon", MDCPUInformationARMElfHwCaps::HWCAP_NEON), - CpuFeaturesEntry::new("vfpv3", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3), - CpuFeaturesEntry::new("vfpv3d16", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3D16), - CpuFeaturesEntry::new("tls", MDCPUInformationARMElfHwCaps::HWCAP_TLS), - CpuFeaturesEntry::new("vfpv4", MDCPUInformationARMElfHwCaps::HWCAP_VFPv4), - CpuFeaturesEntry::new("idiva", MDCPUInformationARMElfHwCaps::HWCAP_IDIVA), - CpuFeaturesEntry::new("idivt", MDCPUInformationARMElfHwCaps::HWCAP_IDIVT), - CpuFeaturesEntry::new("idiv", HWCAP_IDIV), - ]; - } - #[cfg(target_arch = "aarch64")] - { - // No hwcaps on aarch64. - cpu_features_entries = []; - } + let cpu_features_entries = [ + CpuFeaturesEntry::new("swp", MDCPUInformationARMElfHwCaps::HWCAP_SWP), + CpuFeaturesEntry::new("half", MDCPUInformationARMElfHwCaps::HWCAP_HALF), + CpuFeaturesEntry::new("thumb", MDCPUInformationARMElfHwCaps::HWCAP_THUMB), + CpuFeaturesEntry::new("bit26", MDCPUInformationARMElfHwCaps::HWCAP_26BIT), + CpuFeaturesEntry::new("fastmult", MDCPUInformationARMElfHwCaps::HWCAP_FAST_MULT), + CpuFeaturesEntry::new("fpa", MDCPUInformationARMElfHwCaps::HWCAP_FPA), + CpuFeaturesEntry::new("vfp", MDCPUInformationARMElfHwCaps::HWCAP_VFP), + CpuFeaturesEntry::new("edsp", MDCPUInformationARMElfHwCaps::HWCAP_EDSP), + CpuFeaturesEntry::new("java", MDCPUInformationARMElfHwCaps::HWCAP_JAVA), + CpuFeaturesEntry::new("iwmmxt", MDCPUInformationARMElfHwCaps::HWCAP_IWMMXT), + CpuFeaturesEntry::new("crunch", MDCPUInformationARMElfHwCaps::HWCAP_CRUNCH), + CpuFeaturesEntry::new("thumbee", MDCPUInformationARMElfHwCaps::HWCAP_THUMBEE), + CpuFeaturesEntry::new("neon", MDCPUInformationARMElfHwCaps::HWCAP_NEON), + CpuFeaturesEntry::new("vfpv3", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3), + CpuFeaturesEntry::new("vfpv3d16", MDCPUInformationARMElfHwCaps::HWCAP_VFPv3D16), + CpuFeaturesEntry::new("tls", MDCPUInformationARMElfHwCaps::HWCAP_TLS), + CpuFeaturesEntry::new("vfpv4", MDCPUInformationARMElfHwCaps::HWCAP_VFPv4), + CpuFeaturesEntry::new("idiva", MDCPUInformationARMElfHwCaps::HWCAP_IDIVA), + CpuFeaturesEntry::new("idivt", MDCPUInformationARMElfHwCaps::HWCAP_IDIVT), + CpuFeaturesEntry::new("idiv", HWCAP_IDIV), + ]; // processor_architecture should always be set, do this first if cfg!(target_arch = "aarch64") { - sys_info.processor_architecture = MDCPUArchitecture::Arm64Old as u16; + sys_info.processor_architecture = + MDCPUArchitecture::PROCESSOR_ARCHITECTURE_ARM64_OLD as u16; } else { - sys_info.processor_architecture = MDCPUArchitecture::Arm as u16; + sys_info.processor_architecture = MDCPUArchitecture::PROCESSOR_ARCHITECTURE_ARM as u16; } // /proc/cpuinfo is not readable under various sandboxed environments @@ -135,8 +128,9 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { sys_info.number_of_processors = 0; sys_info.processor_level = 1; // There is no ARMv1 sys_info.processor_revision = 42; - sys_info.cpu.cpuid = 0; - sys_info.cpu.elf_hwcaps = 0; + + //sys_info.cpu.cpuid = 0; + //sys_info.cpu.elf_hwcaps = 0; // Counting the number of CPUs involves parsing two sysfs files, // because the content of /proc/cpuinfo will only mirror the number @@ -170,6 +164,8 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { } }; + let mut cpuid = 0; + for line in BufReader::new(cpuinfo_file).lines() { let line = line?; // Expected format: + ':' @@ -207,7 +203,7 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { }; result &= (1 << entry.bit_length) - 1; result <<= entry.bit_lshift; - sys_info.cpu.cpuid |= result as u32; + cpuid |= result as u32; } if cfg!(target_arch = "arm") { @@ -242,20 +238,50 @@ pub fn write_cpu_information(sys_info: &mut MDRawSystemInfo) -> Result<()> { } } - // Rebuild the ELF hwcaps from the 'Features' field. - if field == "Features" { - if let Some(val) = value { - // Parse each space-separated tag. - for tag in val.split_whitespace() { - for entry in &cpu_features_entries { - if entry.tag == tag { - sys_info.cpu.elf_hwcaps |= entry.hwcaps; - break; + let elf_hwcaps = { + let mut elf_hwcaps = 0; + #[cfg(target_arch = "arm")] + { + // Rebuild the ELF hwcaps from the 'Features' field. + if field == "Features" { + if let Some(val) = value { + // Parse each space-separated tag. + for tag in val.split_whitespace() { + for entry in &cpu_features_entries { + if entry.tag == tag { + elf_hwcaps |= entry.hwcaps; + break; + } + } } } } } - } + + elf_hwcaps + }; + + // The sys_info.cpu field is just a byte array, but in arm's case it is + // actually + // minidump_common::format::ARMCpuInfo { + // pub cpuid: u32, + // pub elf_hwcaps: u32, + // } + use scroll::Pwrite; + sys_info + .cpu + .data + .pwrite_with(cpuid, 0, scroll::Endian::Little) + .expect("impossible"); + sys_info + .cpu + .data + .pwrite_with( + elf_hwcaps, + std::mem::size_of::(), + scroll::Endian::Little, + ) + .expect("impossible"); } Ok(()) } diff --git a/src/linux/thread_info.rs b/src/linux/thread_info.rs index 94d529a8..a438becf 100644 --- a/src/linux/thread_info.rs +++ b/src/linux/thread_info.rs @@ -30,7 +30,7 @@ cfg_if::cfg_if! { enum NT_Elf { NT_NONE = 0, NT_PRSTATUS = 1, - NT_PRFPREG = 2, + NT_PRFPREGSET = 2, //NT_PRPSINFO = 3, //NT_TASKSTRUCT = 4, //NT_AUXV = 6, @@ -81,13 +81,14 @@ trait CommonThreadInfo { } } if ppid == -1 || tgid == -1 { - return Err(ThreadInfoError::InvalidPid( + Err(ThreadInfoError::InvalidPid( format!("/proc/{}/status", tid), ppid, tgid, - )); + )) + } else { + Ok((ppid, tgid)) } - Ok((ppid, tgid)) } /// SLIGHTLY MODIFIED COPY FROM CRATE nix @@ -163,7 +164,8 @@ trait CommonThreadInfo { } } impl ThreadInfo { - pub fn create(pid: Pid, tid: Pid) -> std::result::Result { - Self::create_impl(pid, tid) + pub fn create(_pid: Pid, tid: Pid) -> std::result::Result { + let (ppid, tgid) = Self::get_ppid_and_tgid(tid)?; + Self::create_impl(tid, ppid, tgid) } } diff --git a/src/linux/thread_info/aarch64.rs b/src/linux/thread_info/aarch64.rs index cca218f4..878ed7cb 100644 --- a/src/linux/thread_info/aarch64.rs +++ b/src/linux/thread_info/aarch64.rs @@ -1,48 +1,129 @@ -use super::Pid; +use super::{CommonThreadInfo, Pid}; use crate::errors::ThreadInfoError; -use crate::minidump_cpu::imp::{MDARM64RegisterNumbers, MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT}; -use libc; +use crate::minidump_cpu::RawContextCPU; +use nix::sys::ptrace; + +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. + */ +pub enum MDARM64RegisterNumbers { + Fp = 29, + Lr = 30, + Sp = 31, + Pc = 32, +} + +/// https://github.com/rust-lang/libc/pull/2719 +#[derive(Debug)] +#[allow(non_camel_case_types)] +pub struct user_fpsimd_struct { + pub vregs: [u128; 32], + pub fpsr: u32, + pub fpcr: u32, +} type Result = std::result::Result; #[cfg(target_arch = "aarch64")] #[derive(Debug)] pub struct ThreadInfoAarch64 { - pub stack_pointer: libc::c_ulonglong, + pub stack_pointer: usize, 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: user_fpsimd_struct, } +impl CommonThreadInfo for ThreadInfoAarch64 {} + impl ThreadInfoAarch64 { - pub fn get_instruction_pointer(&self) -> libc::c_ulonglong { - self.regs.pc + pub fn get_instruction_pointer(&self) -> usize { + self.regs.pc as usize + } + + // nix currently doesn't support PTRACE_GETFPREGS, so we have to do it ourselves + fn getfpregs(pid: Pid) -> Result { + Self::ptrace_get_data_via_io::( + ptrace::Request::PTRACE_GETREGSET, + Some(super::NT_Elf::NT_PRFPREGSET), + nix::unistd::Pid::from_raw(pid), + ) + .or_else(|_err| { + // TODO: nix restricts PTRACE_GETFPREGS to arm android for some reason + let mut data = std::mem::MaybeUninit::::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() }) + }) + } + + fn getregs(pid: Pid) -> Result { + Self::ptrace_get_data_via_io::( + ptrace::Request::PTRACE_GETREGSET, + Some(super::NT_Elf::NT_PRSTATUS), + nix::unistd::Pid::from_raw(pid), + ) + .or_else(|_err| { + // TODO: nix restricts PTRACE_GETREGS to arm android for some reason + let mut data = std::mem::MaybeUninit::::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() }) + }) } pub fn fill_cpu_context(&self, out: &mut RawContextCPU) { - // out->context_flags = MD_CONTEXT_ARM64_FULL_OLD; + out.context_flags = + minidump_common::format::ContextFlagsArm64Old::CONTEXT_ARM64_FULL_OLD.bits() as u64; + + /// This is the number of general purpose registers _not_ counting + /// the stack pointer + const GP_REG_COUNT: usize = 31; + /// The number of floating point registers in the floating point save area + const FP_REG_COUNT: usize = 32; + out.cpsr = self.regs.pstate as u32; - for idx in 0..MDARM64RegisterNumbers::MD_CONTEXT_ARM64_REG_SP { - 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.iregs[..GP_REG_COUNT].copy_from_slice(&self.regs.regs[..GP_REG_COUNT]); + out.iregs[MDARM64RegisterNumbers::Sp as usize] = self.regs.sp; + // Note that in breakpad this was the last member of the iregs field + // which was 33 in length, but in rust-minidump it is its own separate + // field instead + out.pc = self.regs.pc; + out.float_save.fpsr = self.fpregs.fpsr; out.float_save.fpcr = self.fpregs.fpcr; + out.float_save.regs[..FP_REG_COUNT].copy_from_slice(&self.fpregs.vregs[..FP_REG_COUNT]); + } + + pub fn create_impl(tid: Pid, ppid: Pid, tgid: Pid) -> Result { + let regs = Self::getregs(tid)?; + let fpregs = Self::getfpregs(tid)?; + + let stack_pointer = regs.regs[13] as usize; - // 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::>() - .as_slice() - .try_into() // Make slice into fixed size array - .unwrap(); // Which has to work as we know the numbers work out + Ok(Self { + stack_pointer, + tgid, + ppid, + regs, + fpregs, + }) } } diff --git a/src/linux/thread_info/arm.rs b/src/linux/thread_info/arm.rs index a66670ce..4ac955df 100644 --- a/src/linux/thread_info/arm.rs +++ b/src/linux/thread_info/arm.rs @@ -97,14 +97,13 @@ impl ThreadInfoArm { } } - pub fn create_impl(_pid: Pid, tid: Pid) -> Result { - let (ppid, tgid) = Self::get_ppid_and_tgid(tid)?; + pub fn create_impl(tid: Pid, ppid: Pid, tgid: Pid) -> Result { let regs = Self::getregs(tid)?; let fpregs = Self::getfpregs(tid)?; let stack_pointer = regs.uregs[13] as usize; - Ok(ThreadInfoArm { + Ok(Self { stack_pointer, tgid, ppid, diff --git a/src/linux/thread_info/x86.rs b/src/linux/thread_info/x86.rs index bd5ab6cc..eab420b7 100644 --- a/src/linux/thread_info/x86.rs +++ b/src/linux/thread_info/x86.rs @@ -42,7 +42,7 @@ impl ThreadInfoX86 { fn getfpregset(pid: Pid) -> Result { Self::ptrace_get_data_via_io::( ptrace::Request::PTRACE_GETREGSET, - Some(NT_Elf::NT_PRFPREG), + Some(NT_Elf::NT_PRFPREGSET), nix::unistd::Pid::from_raw(pid), ) } @@ -75,8 +75,7 @@ impl ThreadInfoX86 { ) } - pub fn create_impl(_pid: Pid, tid: Pid) -> Result { - let (ppid, tgid) = Self::get_ppid_and_tgid(tid)?; + pub fn create_impl(tid: Pid, ppid: Pid, tgid: Pid) -> Result { let regs = Self::getregset(tid).or_else(|_| ptrace::getregs(unistd::Pid::from_raw(tid)))?; let fpregs = Self::getfpregset(tid).or_else(|_| Self::getfpregs(tid))?; #[cfg(target_arch = "x86")] @@ -117,7 +116,7 @@ impl ThreadInfoX86 { #[cfg(target_arch = "x86")] let stack_pointer = regs.esp as usize; - Ok(ThreadInfoX86 { + Ok(Self { stack_pointer, tgid, ppid, diff --git a/src/minidump_cpu.rs b/src/minidump_cpu.rs index 68474738..51884ebd 100644 --- a/src/minidump_cpu.rs +++ b/src/minidump_cpu.rs @@ -10,11 +10,8 @@ cfg_if::cfg_if! { pub use arm as imp; pub type RawContextCPU = arm::MDRawContextARM; } else if #[cfg(target_arch = "aarch64")] { - pub mod aarch64; - pub use aarch64 as imp; - - compile_error!("flesh me out"); - //pub type RawContextCPU = aarch64::MDRawContextX86; + pub type RawContextCPU = minidump_common::format::CONTEXT_ARM64_OLD; + pub type FloatStateCPU = minidump_common::format::FLOATING_SAVE_AREA_ARM64_OLD; } else if #[cfg(target_arch = "mips")] { compile_error!("flesh me out"); } else { diff --git a/src/minidump_cpu/aarch64.rs b/src/minidump_cpu/aarch64.rs deleted file mode 100644 index c35e2e3c..00000000 --- a/src/minidump_cpu/aarch64.rs +++ /dev/null @@ -1,12 +0,0 @@ -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. - */ -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, -} diff --git a/src/minidump_cpu/mips.rs b/src/minidump_cpu/mips.rs deleted file mode 100644 index 8b137891..00000000 --- a/src/minidump_cpu/mips.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/minidump_cpu/ppc.rs b/src/minidump_cpu/ppc.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/minidump_cpu/ppc64.rs b/src/minidump_cpu/ppc64.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/minidump_cpu/sparc.rs b/src/minidump_cpu/sparc.rs deleted file mode 100644 index e69de29b..00000000