diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /toolkit/crashreporter/mozannotation_server/src/lib.rs | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/crashreporter/mozannotation_server/src/lib.rs')
-rw-r--r-- | toolkit/crashreporter/mozannotation_server/src/lib.rs | 137 |
1 files changed, 70 insertions, 67 deletions
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())) } |