summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/mozannotation_server
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:34:42 +0000
commitda4c7e7ed675c3bf405668739c3012d140856109 (patch)
treecdd868dba063fecba609a1d819de271f0d51b23e /toolkit/crashreporter/mozannotation_server
parentAdding upstream version 125.0.3. (diff)
downloadfirefox-da4c7e7ed675c3bf405668739c3012d140856109.tar.xz
firefox-da4c7e7ed675c3bf405668739c3012d140856109.zip
Adding upstream version 126.0.upstream/126.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/crashreporter/mozannotation_server')
-rw-r--r--toolkit/crashreporter/mozannotation_server/Cargo.toml11
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/errors.rs74
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/lib.rs137
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/process_reader.rs18
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs314
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs214
-rw-r--r--toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs193
7 files changed, 77 insertions, 884 deletions
diff --git a/toolkit/crashreporter/mozannotation_server/Cargo.toml b/toolkit/crashreporter/mozannotation_server/Cargo.toml
index 3a5834a645..bd3fb283bf 100644
--- a/toolkit/crashreporter/mozannotation_server/Cargo.toml
+++ b/toolkit/crashreporter/mozannotation_server/Cargo.toml
@@ -8,17 +8,10 @@ license = "MPL-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-goblin = { version = "0.7", features = ["elf32", "elf64", "pe32", "pe64"] }
-memoffset = "0.8"
mozannotation_client = { path = "../mozannotation_client/" }
+process_reader = { path = "../process_reader/" }
thin-vec = { version = "0.2.7", features = ["gecko-ffi"] }
thiserror = "1.0.38"
[target."cfg(any(target_os = \"linux\", target_os = \"android\"))".dependencies]
-libc = "0.2"
-
-[target."cfg(target_os = \"windows\")".dependencies]
-winapi = { version = "0.3", features = ["minwindef", "memoryapi", "psapi"] }
-
-[target."cfg(target_os = \"macos\")".dependencies]
-mach2 = { version = "0.4" }
+memoffset = "0.8"
diff --git a/toolkit/crashreporter/mozannotation_server/src/errors.rs b/toolkit/crashreporter/mozannotation_server/src/errors.rs
index 037d432e5e..b8103ad4e4 100644
--- a/toolkit/crashreporter/mozannotation_server/src/errors.rs
+++ b/toolkit/crashreporter/mozannotation_server/src/errors.rs
@@ -5,77 +5,13 @@
use thiserror::Error;
#[derive(Debug, Error)]
-pub enum RetrievalError {
- #[error("The process handle/PID was invalid")]
- InvalidProcessHandle,
- #[error("Could not find the address of the annotations vector")]
- AnnotationTableNotFound(#[from] FindAnnotationsAddressError),
+pub enum AnnotationsRetrievalError {
+ #[error("Address was out of bounds")]
+ InvalidAddress,
#[error("Corrupt or wrong annotation table")]
InvalidAnnotationTable,
#[error("The data read from the target process is invalid")]
InvalidData,
- #[cfg(any(target_os = "linux", target_os = "android"))]
- #[error("Could not attach to the target process")]
- AttachError(#[from] PtraceError),
- #[error("Could not read from the target process address space")]
- ReadFromProcessError(#[from] ReadError),
- #[error("waitpid() failed when attaching to the process")]
- WaitPidError,
-}
-
-#[derive(Debug, Error)]
-pub enum FindAnnotationsAddressError {
- #[error("Could not convert address {0}")]
- ConvertAddressError(#[from] std::num::TryFromIntError),
- #[error("goblin failed to parse a module")]
- GoblinError(#[from] goblin::error::Error),
- #[error("Address was out of bounds")]
- InvalidAddress,
- #[error("IO error for file {0}")]
- IOError(#[from] std::io::Error),
- #[error("Could not find the address of the annotations vector")]
- NotFound,
- #[error("Could not parse address {0}")]
- ParseAddressError(#[from] std::num::ParseIntError),
- #[error("Could not parse a line in /proc/<pid>/maps")]
- ProcMapsParseError,
- #[cfg(any(target_os = "linux", target_os = "android"))]
- #[error("Program header was not found")]
- ProgramHeaderNotFound,
- #[cfg(target_os = "windows")]
- #[error("Section was not found")]
- SectionNotFound,
- #[cfg(target_os = "windows")]
- #[error("Cannot enumerate the target process's modules")]
- EnumProcessModulesError,
- #[error("Could not read memory from the target process")]
- ReadError(#[from] ReadError),
- #[cfg(target_os = "macos")]
- #[error("Failure when requesting the task information")]
- TaskInfoError,
- #[cfg(target_os = "macos")]
- #[error("The task dyld information format is unknown or invalid")]
- ImageFormatError,
-}
-
-#[derive(Debug, Error)]
-pub enum ReadError {
- #[cfg(any(target_os = "linux", target_os = "android"))]
- #[error("ptrace-specific error")]
- PtraceError(#[from] PtraceError),
- #[cfg(target_os = "windows")]
- #[error("ReadProcessMemory failed")]
- ReadProcessMemoryError,
- #[cfg(target_os = "macos")]
- #[error("mach call failed")]
- MachError,
-}
-
-#[cfg(any(target_os = "linux", target_os = "android"))]
-#[derive(Debug, Error)]
-pub enum PtraceError {
- #[error("Could not read from the target process address space")]
- ReadError(#[source] std::io::Error),
- #[error("Could not trace the process")]
- TraceError(#[source] std::io::Error),
+ #[error("Could not execute operation on the target process")]
+ ProcessReaderError(#[from] process_reader::error::ProcessReaderError),
}
diff --git a/toolkit/crashreporter/mozannotation_server/src/lib.rs b/toolkit/crashreporter/mozannotation_server/src/lib.rs
index 6ed5b3cc41..27682247f8 100644
--- a/toolkit/crashreporter/mozannotation_server/src/lib.rs
+++ b/toolkit/crashreporter/mozannotation_server/src/lib.rs
@@ -3,12 +3,18 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
mod errors;
-mod process_reader;
use crate::errors::*;
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use memoffset::offset_of;
+use process_reader::error::ProcessReaderError;
use process_reader::ProcessReader;
+#[cfg(any(target_os = "windows", target_os = "macos"))]
+use mozannotation_client::ANNOTATION_SECTION;
use mozannotation_client::{Annotation, AnnotationContents, AnnotationMutex};
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use mozannotation_client::{MozAnnotationNote, ANNOTATION_TYPE};
use std::cmp::min;
use std::iter::FromIterator;
use std::mem::{size_of, ManuallyDrop};
@@ -29,12 +35,7 @@ pub struct CAnnotation {
data: AnnotationData,
}
-#[cfg(target_os = "windows")]
-type ProcessHandle = winapi::shared::ntdef::HANDLE;
-#[cfg(any(target_os = "linux", target_os = "android"))]
-type ProcessHandle = libc::pid_t;
-#[cfg(any(target_os = "macos"))]
-type ProcessHandle = mach2::mach_types::task_t;
+pub type ProcessHandle = process_reader::ProcessHandle;
/// Return the annotations of a given process.
///
@@ -68,19 +69,23 @@ pub unsafe extern "C" fn mozannotation_free(ptr: *mut ThinVec<CAnnotation>) {
pub fn retrieve_annotations(
process: ProcessHandle,
max_annotations: usize,
-) -> Result<Box<ThinVec<CAnnotation>>, RetrievalError> {
+) -> Result<Box<ThinVec<CAnnotation>>, AnnotationsRetrievalError> {
let reader = ProcessReader::new(process)?;
- let address = reader.find_annotations()?;
+ let address = find_annotations(&reader)?;
- let mut mutex = reader.copy_object_shallow::<AnnotationMutex>(address)?;
+ let mut mutex = reader
+ .copy_object_shallow::<AnnotationMutex>(address)
+ .map_err(ProcessReaderError::from)?;
let mutex = unsafe { mutex.assume_init_mut() };
// TODO: we should clear the poison value here before getting the mutex
// contents. Right now we have to fail if the mutex was poisoned.
- let annotation_table = mutex.get_mut().map_err(|_e| RetrievalError::InvalidData)?;
+ let annotation_table = mutex
+ .get_mut()
+ .map_err(|_e| AnnotationsRetrievalError::InvalidData)?;
if !annotation_table.verify() {
- return Err(RetrievalError::InvalidAnnotationTable);
+ return Err(AnnotationsRetrievalError::InvalidAnnotationTable);
}
let vec_pointer = annotation_table.get_ptr();
@@ -97,8 +102,47 @@ pub fn retrieve_annotations(
Ok(Box::new(annotations))
}
+fn find_annotations(reader: &ProcessReader) -> Result<usize, AnnotationsRetrievalError> {
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ {
+ let libxul_address = reader.find_module("libxul.so")?;
+ let note_address = reader.find_program_note(
+ libxul_address,
+ ANNOTATION_TYPE,
+ size_of::<MozAnnotationNote>(),
+ )?;
+
+ let note = reader
+ .copy_object::<MozAnnotationNote>(note_address)
+ .map_err(ProcessReaderError::from)?;
+ let desc = note.desc;
+ let ehdr = (-note.ehdr) as usize;
+ let offset = desc + ehdr
+ - (offset_of!(MozAnnotationNote, ehdr) - offset_of!(MozAnnotationNote, desc));
+
+ usize::checked_add(libxul_address, offset).ok_or(AnnotationsRetrievalError::InvalidAddress)
+ }
+ #[cfg(any(target_os = "macos"))]
+ {
+ let libxul_address = reader.find_module("XUL")?;
+ reader
+ .find_section(libxul_address, ANNOTATION_SECTION)
+ .map_err(AnnotationsRetrievalError::from)
+ }
+ #[cfg(any(target_os = "windows"))]
+ {
+ let libxul_address = reader.find_module("xul.dll")?;
+ reader
+ .find_section(libxul_address, ANNOTATION_SECTION)
+ .map_err(AnnotationsRetrievalError::from)
+ }
+}
+
// Read an annotation from the given address
-fn read_annotation(reader: &ProcessReader, address: usize) -> Result<CAnnotation, ReadError> {
+fn read_annotation(
+ reader: &ProcessReader,
+ address: usize,
+) -> Result<CAnnotation, process_reader::error::ReadError> {
let raw_annotation = ManuallyDrop::new(reader.copy_object::<Annotation>(address)?);
let mut annotation = CAnnotation {
id: raw_annotation.id,
@@ -116,16 +160,16 @@ fn read_annotation(reader: &ProcessReader, address: usize) -> Result<CAnnotation
annotation.data = AnnotationData::ByteBuffer(string);
}
AnnotationContents::CStringPointer => {
- let buffer = copy_null_terminated_string_pointer(reader, raw_annotation.address)?;
- annotation.data = AnnotationData::ByteBuffer(buffer);
+ let string = copy_null_terminated_string_pointer(reader, raw_annotation.address)?;
+ annotation.data = AnnotationData::ByteBuffer(string);
}
AnnotationContents::CString => {
- let buffer = copy_null_terminated_string(reader, raw_annotation.address)?;
- annotation.data = AnnotationData::ByteBuffer(buffer);
+ let string = copy_null_terminated_string(reader, raw_annotation.address)?;
+ annotation.data = AnnotationData::ByteBuffer(string);
}
AnnotationContents::ByteBuffer(size) | AnnotationContents::OwnedByteBuffer(size) => {
- let buffer = copy_bytebuffer(reader, raw_annotation.address, size)?;
- annotation.data = AnnotationData::ByteBuffer(buffer);
+ let string = copy_bytebuffer(reader, raw_annotation.address, size)?;
+ annotation.data = AnnotationData::ByteBuffer(string);
}
};
@@ -135,7 +179,7 @@ fn read_annotation(reader: &ProcessReader, address: usize) -> Result<CAnnotation
fn copy_null_terminated_string_pointer(
reader: &ProcessReader,
address: usize,
-) -> Result<ThinVec<u8>, ReadError> {
+) -> Result<ThinVec<u8>, process_reader::error::ReadError> {
let buffer_address = reader.copy_object::<usize>(address)?;
copy_null_terminated_string(reader, buffer_address)
}
@@ -143,56 +187,15 @@ fn copy_null_terminated_string_pointer(
fn copy_null_terminated_string(
reader: &ProcessReader,
address: usize,
-) -> Result<ThinVec<u8>, ReadError> {
- // Try copying the string word-by-word first, this is considerably faster
- // than one byte at a time.
- if let Ok(string) = copy_null_terminated_string_word_by_word(reader, address) {
- return Ok(string);
- }
-
- // Reading the string one word at a time failed, let's try again one byte
- // at a time. It's slow but it might work in situations where the string
- // alignment causes word-by-word access to straddle page boundaries.
- let mut length = 0;
- let mut string = ThinVec::<u8>::new();
-
- loop {
- let char = reader.copy_object::<u8>(address + length)?;
- length += 1;
- string.push(char);
-
- if char == 0 {
- break;
- }
- }
-
- Ok(string)
+) -> Result<ThinVec<u8>, process_reader::error::ReadError> {
+ let string = reader.copy_null_terminated_string(address)?;
+ Ok(ThinVec::<u8>::from(string.as_bytes()))
}
-fn copy_null_terminated_string_word_by_word(
+fn copy_nscstring(
reader: &ProcessReader,
address: usize,
-) -> Result<ThinVec<u8>, ReadError> {
- const WORD_SIZE: usize = size_of::<usize>();
- let mut length = 0;
- let mut string = ThinVec::<u8>::new();
-
- loop {
- let array = reader.copy_array::<u8>(address + length, WORD_SIZE)?;
- let null_terminator = array.iter().position(|&e| e == 0);
- length += null_terminator.unwrap_or(WORD_SIZE);
- string.extend(array.into_iter());
-
- if null_terminator.is_some() {
- string.truncate(length);
- break;
- }
- }
-
- Ok(string)
-}
-
-fn copy_nscstring(reader: &ProcessReader, address: usize) -> Result<ThinVec<u8>, ReadError> {
+) -> Result<ThinVec<u8>, process_reader::error::ReadError> {
// HACK: This assumes the layout of the nsCString object
let length_address = address + size_of::<usize>();
let length = reader.copy_object::<u32>(length_address)?;
@@ -211,7 +214,7 @@ fn copy_bytebuffer(
reader: &ProcessReader,
address: usize,
size: u32,
-) -> Result<ThinVec<u8>, ReadError> {
+) -> Result<ThinVec<u8>, process_reader::error::ReadError> {
let value = reader.copy_array::<u8>(address, size as _)?;
Ok(ThinVec::<u8>::from_iter(value.into_iter()))
}
diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader.rs
deleted file mode 100644
index b405b4b725..0000000000
--- a/toolkit/crashreporter/mozannotation_server/src/process_reader.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use crate::ProcessHandle;
-
-pub struct ProcessReader {
- process: ProcessHandle,
-}
-
-#[cfg(target_os = "windows")]
-mod windows;
-
-#[cfg(any(target_os = "android", target_os = "linux"))]
-mod linux;
-
-#[cfg(target_os = "macos")]
-mod macos;
diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs
deleted file mode 100644
index 34f8ef90d5..0000000000
--- a/toolkit/crashreporter/mozannotation_server/src/process_reader/linux.rs
+++ /dev/null
@@ -1,314 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use mozannotation_client::MozAnnotationNote;
-use std::{
- cmp::min,
- fs::File,
- io::{BufRead, BufReader, Error},
- mem::{size_of, MaybeUninit},
- ptr::null_mut,
- slice,
-};
-
-use crate::{
- errors::{FindAnnotationsAddressError, PtraceError, ReadError, RetrievalError},
- ProcessHandle,
-};
-
-use super::ProcessReader;
-
-use goblin::elf::{
- self,
- program_header::{PF_R, PT_NOTE},
- Elf, ProgramHeader,
-};
-use libc::{
- c_int, c_long, c_void, pid_t, ptrace, waitpid, EINTR, PTRACE_ATTACH, PTRACE_DETACH,
- PTRACE_PEEKDATA, __WALL,
-};
-use memoffset::offset_of;
-use mozannotation_client::ANNOTATION_TYPE;
-
-impl ProcessReader {
- pub fn new(process: ProcessHandle) -> Result<ProcessReader, RetrievalError> {
- let pid: pid_t = process;
-
- ptrace_attach(pid)?;
-
- let mut status: i32 = 0;
-
- loop {
- let res = unsafe { waitpid(pid, &mut status as *mut _, __WALL) };
- if res < 0 {
- match get_errno() {
- EINTR => continue,
- _ => {
- ptrace_detach(pid)?;
- return Err(RetrievalError::WaitPidError);
- }
- }
- } else {
- break;
- }
- }
-
- Ok(ProcessReader { process: pid })
- }
-
- pub fn find_annotations(&self) -> Result<usize, FindAnnotationsAddressError> {
- let maps_file = File::open(format!("/proc/{}/maps", self.process))?;
-
- BufReader::new(maps_file)
- .lines()
- .flatten()
- .find_map(|line| self.find_annotations_in_module(&line).ok())
- .ok_or(FindAnnotationsAddressError::NotFound)
- }
-
- fn find_annotations_in_module(&self, line: &str) -> Result<usize, FindAnnotationsAddressError> {
- parse_proc_maps_line(line).and_then(|module_address| {
- let header_bytes = self.copy_array(module_address, size_of::<elf::Header>())?;
- let elf_header = Elf::parse_header(&header_bytes)?;
-
- let program_header_bytes = self.copy_array(
- module_address + (elf_header.e_phoff as usize),
- (elf_header.e_phnum as usize) * (elf_header.e_phentsize as usize),
- )?;
-
- let mut elf = Elf::lazy_parse(elf_header)?;
- let context = goblin::container::Ctx {
- container: elf.header.container()?,
- le: elf.header.endianness()?,
- };
-
- elf.program_headers = ProgramHeader::parse(
- &program_header_bytes,
- 0,
- elf_header.e_phnum as usize,
- context,
- )?;
-
- self.find_mozannotation_note(module_address, &elf)
- .ok_or(FindAnnotationsAddressError::ProgramHeaderNotFound)
- })
- }
-
- // Looks through the program headers for the note contained in the
- // mozannotation_client crate. If the note is found return the address of the
- // note's desc field as well as its contents.
- fn find_mozannotation_note(&self, module_address: usize, elf: &Elf) -> Option<usize> {
- for program_header in elf.program_headers.iter() {
- // We're looking for a note in the program headers, it needs to be
- // readable and it needs to be at least as large as the
- // MozAnnotationNote structure.
- if (program_header.p_type == PT_NOTE)
- && ((program_header.p_flags & PF_R) != 0
- && (program_header.p_memsz as usize >= size_of::<MozAnnotationNote>()))
- {
- // Iterate over the notes
- let notes_address = module_address + program_header.p_offset as usize;
- let mut notes_offset = 0;
- let notes_size = program_header.p_memsz as usize;
- while notes_offset < notes_size {
- let note_address = notes_address + notes_offset;
- if let Ok(note) = self.copy_object::<goblin::elf::note::Nhdr32>(note_address) {
- if note.n_type == ANNOTATION_TYPE {
- if let Ok(note) = self.copy_object::<MozAnnotationNote>(note_address) {
- let desc = note.desc;
- let ehdr = (-note.ehdr) as usize;
- let offset = desc + ehdr
- - (offset_of!(MozAnnotationNote, ehdr)
- - offset_of!(MozAnnotationNote, desc));
-
- return usize::checked_add(module_address, offset);
- }
- }
-
- notes_offset += size_of::<goblin::elf::note::Nhdr32>()
- + (note.n_descsz as usize)
- + (note.n_namesz as usize);
- } else {
- break;
- }
- }
- }
- }
-
- None
- }
-
- pub fn copy_object_shallow<T>(&self, src: usize) -> Result<MaybeUninit<T>, ReadError> {
- let data = self.copy_array(src, size_of::<T>())?;
- let mut object = MaybeUninit::<T>::uninit();
- let uninitialized_object = uninit_as_bytes_mut(&mut object);
-
- for (index, &value) in data.iter().enumerate() {
- uninitialized_object[index].write(value);
- }
-
- Ok(object)
- }
-
- pub fn copy_object<T>(&self, src: usize) -> Result<T, ReadError> {
- self.copy_object_shallow(src)
- .map(|object| unsafe { object.assume_init() })
- }
-
- pub fn copy_array<T>(&self, src: usize, num: usize) -> Result<Vec<T>, ReadError> {
- let mut array = Vec::<MaybeUninit<T>>::with_capacity(num);
- let num_bytes = num * size_of::<T>();
- let mut array_buffer = array.as_mut_ptr() as *mut u8;
- let mut index = 0;
-
- while index < num_bytes {
- let word = ptrace_read(self.process, src + index)?;
- let len = min(size_of::<c_long>(), num_bytes - index);
- let word_as_bytes = word.to_ne_bytes();
- for &byte in word_as_bytes.iter().take(len) {
- unsafe {
- array_buffer.write(byte);
- array_buffer = array_buffer.add(1);
- }
- }
-
- index += size_of::<c_long>();
- }
-
- unsafe {
- array.set_len(num);
- Ok(std::mem::transmute(array))
- }
- }
-}
-
-impl Drop for ProcessReader {
- fn drop(&mut self) {
- let _ignored = ptrace_detach(self.process);
- }
-}
-
-fn parse_proc_maps_line(line: &str) -> Result<usize, FindAnnotationsAddressError> {
- let mut splits = line.trim().splitn(6, ' ');
- let address_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- let _perms_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- let _offset_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- let _dev_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- let _inode_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- let _path_str = splits
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
-
- let address = get_proc_maps_address(address_str)?;
-
- Ok(address)
-}
-
-fn get_proc_maps_address(addresses: &str) -> Result<usize, FindAnnotationsAddressError> {
- let begin = addresses
- .split('-')
- .next()
- .ok_or(FindAnnotationsAddressError::ProcMapsParseError)?;
- usize::from_str_radix(begin, 16).map_err(FindAnnotationsAddressError::from)
-}
-
-fn uninit_as_bytes_mut<T>(elem: &mut MaybeUninit<T>) -> &mut [MaybeUninit<u8>] {
- // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
- unsafe { slice::from_raw_parts_mut(elem.as_mut_ptr() as *mut MaybeUninit<u8>, size_of::<T>()) }
-}
-
-/***********************************************************************
- ***** libc helpers *****
- ***********************************************************************/
-
-fn get_errno() -> c_int {
- #[cfg(target_os = "linux")]
- unsafe {
- *libc::__errno_location()
- }
- #[cfg(target_os = "android")]
- unsafe {
- *libc::__errno()
- }
-}
-
-fn clear_errno() {
- #[cfg(target_os = "linux")]
- unsafe {
- *libc::__errno_location() = 0;
- }
- #[cfg(target_os = "android")]
- unsafe {
- *libc::__errno() = 0;
- }
-}
-
-#[derive(Clone, Copy)]
-enum PTraceOperation {
- Attach,
- Detach,
- PeekData,
-}
-
-#[cfg(all(target_os = "linux", target_env = "gnu"))]
-type PTraceOperationNative = libc::c_uint;
-#[cfg(all(target_os = "linux", target_env = "musl"))]
-type PTraceOperationNative = libc::c_int;
-#[cfg(target_os = "android")]
-type PTraceOperationNative = c_int;
-
-impl From<PTraceOperation> for PTraceOperationNative {
- fn from(val: PTraceOperation) -> Self {
- match val {
- PTraceOperation::Attach => PTRACE_ATTACH,
- PTraceOperation::Detach => PTRACE_DETACH,
- PTraceOperation::PeekData => PTRACE_PEEKDATA,
- }
- }
-}
-
-fn ptrace_attach(pid: pid_t) -> Result<(), PtraceError> {
- ptrace_helper(pid, PTraceOperation::Attach, 0).map(|_r| ())
-}
-
-fn ptrace_detach(pid: pid_t) -> Result<(), PtraceError> {
- ptrace_helper(pid, PTraceOperation::Detach, 0).map(|_r| ())
-}
-
-fn ptrace_read(pid: libc::pid_t, addr: usize) -> Result<c_long, PtraceError> {
- ptrace_helper(pid, PTraceOperation::PeekData, addr)
-}
-
-fn ptrace_helper(pid: pid_t, op: PTraceOperation, addr: usize) -> Result<c_long, PtraceError> {
- clear_errno();
- let result = unsafe { ptrace(op.into(), pid, addr, null_mut::<c_void>()) };
-
- if result == -1 {
- let errno = get_errno();
- if errno != 0 {
- let error = match op {
- PTraceOperation::Attach => PtraceError::TraceError(Error::from_raw_os_error(errno)),
- PTraceOperation::Detach => PtraceError::TraceError(Error::from_raw_os_error(errno)),
- PTraceOperation::PeekData => {
- PtraceError::ReadError(Error::from_raw_os_error(errno))
- }
- };
- Err(error)
- } else {
- Ok(result)
- }
- } else {
- Ok(result)
- }
-}
diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs
deleted file mode 100644
index 52a3957ca9..0000000000
--- a/toolkit/crashreporter/mozannotation_server/src/process_reader/macos.rs
+++ /dev/null
@@ -1,214 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use goblin::mach::{
- header::{Header64, MH_DYLIB, MH_EXECUTE, MH_MAGIC_64},
- load_command::{LoadCommandHeader, Section64, SegmentCommand64, LC_SEGMENT_64},
-};
-use mach2::{
- kern_return::KERN_SUCCESS,
- task::task_info,
- task_info::{task_dyld_info, TASK_DYLD_ALL_IMAGE_INFO_64, TASK_DYLD_INFO},
- vm::mach_vm_read_overwrite,
-};
-use std::mem::{size_of, MaybeUninit};
-
-use crate::{
- errors::{FindAnnotationsAddressError, ReadError, RetrievalError},
- ProcessHandle,
-};
-
-use super::ProcessReader;
-
-#[repr(C)]
-#[derive(Copy, Clone, Debug)]
-struct AllImagesInfo {
- // VERSION 1
- pub version: u32,
- /// The number of [`ImageInfo`] structs at that following address
- info_array_count: u32,
- /// The address in the process where the array of [`ImageInfo`] structs is
- info_array_addr: u64,
- /// A function pointer, unused
- _notification: u64,
- /// Unused
- _process_detached_from_shared_region: bool,
- // VERSION 2
- lib_system_initialized: bool,
- // Note that crashpad adds a 32-bit int here to get proper alignment when
- // building on 32-bit targets...but we explicitly don't care about 32-bit
- // targets since Apple doesn't
- pub dyld_image_load_address: u64,
-}
-
-/// `dyld_image_info` from <usr/include/mach-o/dyld_images.h>
-#[repr(C)]
-#[derive(Debug, Clone, Copy)]
-struct ImageInfo {
- /// The address in the process where the image is loaded
- pub load_address: u64,
- /// The address in the process where the image's file path can be read
- pub file_path: u64,
- /// Timestamp for when the image's file was last modified
- pub file_mod_date: u64,
-}
-
-const DATA_SEGMENT: &[u8; 16] = b"__DATA\0\0\0\0\0\0\0\0\0\0";
-const MOZANNOTATION_SECTION: &[u8; 16] = b"mozannotation\0\0\0";
-
-impl ProcessReader {
- pub fn new(process: ProcessHandle) -> Result<ProcessReader, RetrievalError> {
- Ok(ProcessReader { process })
- }
-
- pub fn find_annotations(&self) -> Result<usize, FindAnnotationsAddressError> {
- let dyld_info = self.task_info()?;
- if (dyld_info.all_image_info_format as u32) != TASK_DYLD_ALL_IMAGE_INFO_64 {
- return Err(FindAnnotationsAddressError::ImageFormatError);
- }
-
- let all_image_info_size = dyld_info.all_image_info_size;
- let all_image_info_addr = dyld_info.all_image_info_addr;
- if (all_image_info_size as usize) < size_of::<AllImagesInfo>() {
- return Err(FindAnnotationsAddressError::ImageFormatError);
- }
-
- let all_images_info = self.copy_object::<AllImagesInfo>(all_image_info_addr as _)?;
-
- // Load the images
- let images = self.copy_array::<ImageInfo>(
- all_images_info.info_array_addr as _,
- all_images_info.info_array_count as _,
- )?;
-
- images
- .iter()
- .find_map(|image| self.find_annotations_in_image(image))
- .ok_or(FindAnnotationsAddressError::NotFound)
- }
-
- fn task_info(&self) -> Result<task_dyld_info, FindAnnotationsAddressError> {
- let mut info = std::mem::MaybeUninit::<task_dyld_info>::uninit();
- let mut count = (std::mem::size_of::<task_dyld_info>() / std::mem::size_of::<u32>()) as u32;
-
- let res = unsafe {
- task_info(
- self.process,
- TASK_DYLD_INFO,
- info.as_mut_ptr().cast(),
- &mut count,
- )
- };
-
- if res == KERN_SUCCESS {
- // SAFETY: this will be initialized if the call succeeded
- unsafe { Ok(info.assume_init()) }
- } else {
- Err(FindAnnotationsAddressError::TaskInfoError)
- }
- }
-
- fn find_annotations_in_image(&self, image: &ImageInfo) -> Option<usize> {
- self.copy_object::<Header64>(image.load_address as _)
- .map_err(FindAnnotationsAddressError::from)
- .and_then(|header| {
- let image_address = image.load_address as usize;
- let mut address = image_address + size_of::<Header64>();
-
- if header.magic == MH_MAGIC_64
- && (header.filetype == MH_EXECUTE || header.filetype == MH_DYLIB)
- {
- let end_of_commands = address + (header.sizeofcmds as usize);
-
- while address < end_of_commands {
- let command = self.copy_object::<LoadCommandHeader>(address)?;
-
- if command.cmd == LC_SEGMENT_64 {
- if let Ok(offset) = self.find_annotations_in_segment(address) {
- return image_address
- .checked_add(offset)
- .ok_or(FindAnnotationsAddressError::InvalidAddress);
- }
- }
-
- address += command.cmdsize as usize;
- }
- }
-
- Err(FindAnnotationsAddressError::NotFound)
- })
- .ok()
- }
-
- fn find_annotations_in_segment(
- &self,
- segment_address: usize,
- ) -> Result<usize, FindAnnotationsAddressError> {
- let segment = self.copy_object::<SegmentCommand64>(segment_address)?;
-
- if segment.segname.eq(DATA_SEGMENT) {
- let sections_addr = segment_address + size_of::<SegmentCommand64>();
- let sections = self.copy_array::<Section64>(sections_addr, segment.nsects as usize)?;
- for section in &sections {
- if section.sectname.eq(MOZANNOTATION_SECTION) {
- return Ok(section.offset as usize);
- }
- }
- }
-
- Err(FindAnnotationsAddressError::InvalidAddress)
- }
-
- pub fn copy_object_shallow<T>(&self, src: usize) -> Result<MaybeUninit<T>, ReadError> {
- let mut object = MaybeUninit::<T>::uninit();
- let mut size: u64 = 0;
- let res = unsafe {
- mach_vm_read_overwrite(
- self.process,
- src as u64,
- size_of::<T>() as u64,
- object.as_mut_ptr() as _,
- &mut size as _,
- )
- };
-
- if res == KERN_SUCCESS {
- Ok(object)
- } else {
- Err(ReadError::MachError)
- }
- }
-
- pub fn copy_object<T>(&self, src: usize) -> Result<T, ReadError> {
- let object = self.copy_object_shallow(src)?;
- Ok(unsafe { object.assume_init() })
- }
-
- pub fn copy_array<T>(&self, src: usize, num: usize) -> Result<Vec<T>, ReadError> {
- let mut array: Vec<MaybeUninit<T>> = Vec::with_capacity(num);
- let mut size: u64 = 0;
- let res = unsafe {
- mach_vm_read_overwrite(
- self.process,
- src as u64,
- (num * size_of::<T>()) as u64,
- array.as_mut_ptr() as _,
- &mut size as _,
- )
- };
-
- if res == KERN_SUCCESS {
- unsafe {
- array.set_len(num);
- Ok(std::mem::transmute(array))
- }
- } else {
- Err(ReadError::MachError)
- }
- }
-}
-
-impl Drop for ProcessReader {
- fn drop(&mut self) {}
-}
diff --git a/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs b/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs
deleted file mode 100644
index ffdcd95937..0000000000
--- a/toolkit/crashreporter/mozannotation_server/src/process_reader/windows.rs
+++ /dev/null
@@ -1,193 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use std::{
- convert::TryInto,
- mem::{size_of, MaybeUninit},
- ptr::null_mut,
-};
-
-use winapi::{
- shared::{
- basetsd::SIZE_T,
- minwindef::{DWORD, FALSE, HMODULE},
- },
- um::{
- memoryapi::ReadProcessMemory,
- psapi::{K32EnumProcessModules, K32GetModuleInformation, MODULEINFO},
- },
-};
-
-use crate::{
- errors::{FindAnnotationsAddressError, ReadError, RetrievalError},
- ProcessHandle,
-};
-
-use super::ProcessReader;
-
-impl ProcessReader {
- pub fn new(process: ProcessHandle) -> Result<ProcessReader, RetrievalError> {
- Ok(ProcessReader { process })
- }
-
- pub fn find_annotations(&self) -> Result<usize, FindAnnotationsAddressError> {
- let modules = self.get_module_list()?;
-
- modules
- .iter()
- .find_map(|&module| {
- self.get_module_info(module).and_then(|info| {
- self.find_annotations_in_module(
- info.lpBaseOfDll as usize,
- info.SizeOfImage as usize,
- )
- .ok()
- })
- })
- .ok_or(FindAnnotationsAddressError::InvalidAddress)
- }
-
- fn get_module_list(&self) -> Result<Vec<HMODULE>, FindAnnotationsAddressError> {
- let mut module_num: usize = 100;
- let mut required_buffer_size: DWORD = 0;
- let mut module_array = Vec::<MaybeUninit<HMODULE>>::with_capacity(module_num);
-
- loop {
- let buffer_size: DWORD = (module_num * size_of::<HMODULE>()).try_into()?;
- let res = unsafe {
- K32EnumProcessModules(
- self.process,
- module_array.as_mut_ptr() as *mut _,
- buffer_size,
- &mut required_buffer_size as *mut _,
- )
- };
-
- module_num = required_buffer_size as usize / size_of::<HMODULE>();
-
- if res == 0 {
- if required_buffer_size > buffer_size {
- module_array = Vec::<MaybeUninit<HMODULE>>::with_capacity(module_num);
- } else {
- return Err(FindAnnotationsAddressError::EnumProcessModulesError);
- }
- } else {
- break;
- }
- }
-
- // SAFETY: module_array has been filled by K32EnumProcessModules()
- let module_array: Vec<HMODULE> = unsafe {
- module_array.set_len(module_num);
- std::mem::transmute(module_array)
- };
-
- Ok(module_array)
- }
-
- fn get_module_info(&self, module: HMODULE) -> Option<MODULEINFO> {
- let mut info: MaybeUninit<MODULEINFO> = MaybeUninit::uninit();
- let res = unsafe {
- K32GetModuleInformation(
- self.process,
- module,
- info.as_mut_ptr(),
- size_of::<MODULEINFO>() as DWORD,
- )
- };
-
- if res == 0 {
- None
- } else {
- let info = unsafe { info.assume_init() };
- Some(info)
- }
- }
-
- fn find_annotations_in_module(
- &self,
- module_address: usize,
- size: usize,
- ) -> Result<usize, FindAnnotationsAddressError> {
- // We read only the first page from the module, this should be more than
- // enough to read the header and section list. In the future we might do
- // this incrementally but for now goblin requires an array to parse
- // so we can't do it just yet.
- let page_size = 4096;
- if size < page_size {
- // Don't try to read from the target module if it's too small
- return Err(FindAnnotationsAddressError::ReadError(
- ReadError::ReadProcessMemoryError,
- ));
- }
-
- let bytes = self.copy_array(module_address as _, 4096)?;
- let header = goblin::pe::header::Header::parse(&bytes)?;
-
- // Skip the PE header so we can parse the sections
- let optional_header_offset = header.dos_header.pe_pointer as usize
- + goblin::pe::header::SIZEOF_PE_MAGIC
- + goblin::pe::header::SIZEOF_COFF_HEADER;
- let offset =
- &mut (optional_header_offset + header.coff_header.size_of_optional_header as usize);
-
- let sections = header.coff_header.sections(&bytes, offset)?;
-
- for section in sections {
- if section.name.eq(mozannotation_client::ANNOTATION_SECTION) {
- let address = module_address.checked_add(section.virtual_address as usize);
- return address.ok_or(FindAnnotationsAddressError::InvalidAddress);
- }
- }
-
- Err(FindAnnotationsAddressError::SectionNotFound)
- }
-
- pub fn copy_object_shallow<T>(&self, src: usize) -> Result<MaybeUninit<T>, ReadError> {
- let mut object = MaybeUninit::<T>::uninit();
- let res = unsafe {
- ReadProcessMemory(
- self.process,
- src as _,
- object.as_mut_ptr() as _,
- size_of::<T>() as SIZE_T,
- null_mut(),
- )
- };
-
- if res != FALSE {
- Ok(object)
- } else {
- Err(ReadError::ReadProcessMemoryError)
- }
- }
-
- pub fn copy_object<T>(&self, src: usize) -> Result<T, ReadError> {
- let object = self.copy_object_shallow(src)?;
- Ok(unsafe { object.assume_init() })
- }
-
- pub fn copy_array<T>(&self, src: usize, num: usize) -> Result<Vec<T>, ReadError> {
- let num_of_bytes = num * size_of::<T>();
- let mut array: Vec<MaybeUninit<T>> = Vec::with_capacity(num);
- let res = unsafe {
- ReadProcessMemory(
- self.process,
- src as _,
- array.as_mut_ptr() as _,
- num_of_bytes as SIZE_T,
- null_mut(),
- )
- };
-
- if res != FALSE {
- unsafe {
- array.set_len(num);
- Ok(std::mem::transmute(array))
- }
- } else {
- Err(ReadError::ReadProcessMemoryError)
- }
- }
-}