diff options
Diffstat (limited to 'toolkit/crashreporter/mozannotation_client/src/lib.rs')
-rw-r--r-- | toolkit/crashreporter/mozannotation_client/src/lib.rs | 257 |
1 files changed, 162 insertions, 95 deletions
diff --git a/toolkit/crashreporter/mozannotation_client/src/lib.rs b/toolkit/crashreporter/mozannotation_client/src/lib.rs index 17fe017095..df2bd5bf94 100644 --- a/toolkit/crashreporter/mozannotation_client/src/lib.rs +++ b/toolkit/crashreporter/mozannotation_client/src/lib.rs @@ -3,30 +3,53 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ use nsstring::nsCString; -use std::{ffi::c_void, sync::Mutex}; +use std::{ + alloc::{self, Layout}, + cmp::min, + ffi::{c_char, c_void, CStr}, + ptr::{copy_nonoverlapping, null_mut}, + sync::Mutex, +}; #[cfg(any(target_os = "linux", target_os = "android"))] use std::arch::global_asm; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum AnnotationContents { Empty, - NSCString, + NSCStringPointer, + CStringPointer, CString, - CharBuffer, - USize, ByteBuffer(u32), + OwnedByteBuffer(u32), } - #[repr(C)] -#[derive(Clone, Copy)] pub struct Annotation { pub id: u32, pub contents: AnnotationContents, pub address: usize, } +impl Drop for Annotation { + fn drop(&mut self) { + match self.contents { + AnnotationContents::OwnedByteBuffer(len) => { + if (self.address != 0) && (len > 0) { + let align = min(usize::next_power_of_two(len as usize), 32); + unsafe { + let layout = Layout::from_size_align_unchecked(len as usize, align); + alloc::dealloc(self.address as *mut u8, layout); + } + } + } + _ => { + // Nothing to do + } + }; + } +} + pub struct AnnotationTable { data: Vec<Annotation>, magic_number: u32, @@ -222,98 +245,126 @@ pub struct MozAnnotationNote { pub ehdr: isize, } -/// Register an annotation containing an nsCString. -/// Returns false if the annotation is already present (and doesn't change it). +fn store_annotation<T>(id: u32, contents: AnnotationContents, address: *const T) -> *const T { + let address = match contents { + AnnotationContents::OwnedByteBuffer(len) => { + if !address.is_null() && (len > 0) { + // Copy the contents of this annotation, we'll own the copy + let len = len as usize; + let align = min(usize::next_power_of_two(len), 32); + unsafe { + let layout = Layout::from_size_align_unchecked(len as usize, align); + let src = address as *mut u8; + let dst = alloc::alloc(layout); + copy_nonoverlapping(src, dst, len); + dst + } + } else { + null_mut() + } + } + _ => address as *mut u8, + }; + + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + let old = if let Some(existing) = annotations.iter_mut().find(|e| e.id == id) { + let old = match existing.contents { + AnnotationContents::OwnedByteBuffer(len) => { + // If we owned the previous value of this annotation we must free it. + if (existing.address != 0) && (len > 0) { + let len = len as usize; + let align = min(usize::next_power_of_two(len), 32); + unsafe { + let layout = Layout::from_size_align_unchecked(len, align); + alloc::dealloc(existing.address as *mut u8, layout); + } + } + null_mut::<T>() + } + _ => existing.address as *mut T, + }; + + existing.contents = contents; + existing.address = address as usize; + old + } else { + annotations.push(Annotation { + id, + contents, + address: address as usize, + }); + null_mut::<T>() + }; + + old +} + +/// Register a pointer to an nsCString string. +/// +/// Returns the value of the previously registered annotation or null. /// /// This function will be exposed to C++ #[no_mangle] -pub extern "C" fn mozannotation_register_nscstring(id: u32, address: *const nsCString) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - - if annotations.iter().any(|e| e.id == id) { - return false; - } - - annotations.push(Annotation { - id, - contents: AnnotationContents::NSCString, - address: address as usize, - }); - - true +pub extern "C" fn mozannotation_register_nscstring( + id: u32, + address: *const nsCString, +) -> *const nsCString { + store_annotation(id, AnnotationContents::NSCStringPointer, address) } -/// Register an annotation containing a null-terminated string. -/// Returns false if the annotation is already present (and doesn't change it). +/// Create a copy of the provided string with a specified size that will be +/// owned by the crate, and register a pointer to it. /// /// This function will be exposed to C++ #[no_mangle] -pub extern "C" fn mozannotation_register_cstring( +pub extern "C" fn mozannotation_record_nscstring_from_raw_parts( id: u32, - address: *const *const std::ffi::c_char, -) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - - if annotations.iter().any(|e| e.id == id) { - return false; - } - - annotations.push(Annotation { + address: *const u8, + size: usize, +) { + store_annotation( id, - contents: AnnotationContents::CString, - address: address as usize, - }); - - true + AnnotationContents::OwnedByteBuffer(size as u32), + address, + ); } -/// Register an annotation pointing to a buffer holding a null-terminated string. -/// Returns false if the annotation is already present (and doesn't change it). +/// Register a pointer to a pointer to a nul-terminated string. +/// +/// Returns the value of the previously registered annotation or null. /// /// This function will be exposed to C++ #[no_mangle] -pub extern "C" fn mozannotation_register_char_buffer( +pub extern "C" fn mozannotation_register_cstring_ptr( id: u32, - address: *const std::ffi::c_char, -) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - - if annotations.iter().any(|e| e.id == id) { - return false; - } - - annotations.push(Annotation { - id, - contents: AnnotationContents::CharBuffer, - address: address as usize, - }); - - true + address: *const *const c_char, +) -> *const *const c_char { + store_annotation(id, AnnotationContents::CStringPointer, address) } -/// Register an annotation pointing to a variable of type usize. -/// Returns false if the annotation is already present (and doesn't change it). +/// Register a pointer to a nul-terminated string. +/// +/// Returns the value of the previously registered annotation or null. /// /// This function will be exposed to C++ #[no_mangle] -pub extern "C" fn mozannotation_register_usize(id: u32, address: *const usize) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - - if annotations.iter().any(|e| e.id == id) { - return false; - } - - annotations.push(Annotation { - id, - contents: AnnotationContents::USize, - address: address as usize, - }); +pub extern "C" fn mozannotation_register_cstring(id: u32, address: *const c_char) -> *const c_char { + store_annotation(id, AnnotationContents::CString, address) +} - true +/// Create a copy of the provided nul-terminated string which will be owned by +/// the crate, and register a pointer to it. +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_record_cstring(id: u32, address: *const c_char) { + let len = unsafe { CStr::from_ptr(address).to_bytes().len() }; + store_annotation(id, AnnotationContents::OwnedByteBuffer(len as u32), address); } -/// Register an annotation pointing to a fixed size buffer. -/// Returns false if the annotation is already present (and doesn't change it). +/// Register a pointer to a fixed size buffer. +/// +/// Returns the value of the previously registered annotation or null. /// /// This function will be exposed to C++ #[no_mangle] @@ -321,34 +372,50 @@ pub extern "C" fn mozannotation_register_bytebuffer( id: u32, address: *const c_void, size: u32, -) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - - if annotations.iter().any(|e| e.id == id) { - return false; - } +) -> *const c_void { + store_annotation(id, AnnotationContents::ByteBuffer(size), address) +} - annotations.push(Annotation { - id, - contents: AnnotationContents::ByteBuffer(size), - address: address as usize, - }); +/// Create a copy of the provided buffer which will be owned by the crate, and +/// register a pointer to it. +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_record_bytebuffer(id: u32, address: *const c_void, size: u32) { + store_annotation(id, AnnotationContents::OwnedByteBuffer(size), address); +} - true +/// Unregister a crash annotation. Returns the previously registered pointer or +/// null if none was present. Return null also if the crate owned the +/// annotations' buffer. +/// +/// This function will be exposed to C++ +#[no_mangle] +pub extern "C" fn mozannotation_unregister(id: u32) -> *const c_void { + store_annotation(id, AnnotationContents::Empty, null_mut()) } -/// Unregister a crash annotation. Returns false if the annotation is not present. +/// Returns the raw address of an annotation if it has been registered or NULL +/// if it hasn't. /// /// This function will be exposed to C++ #[no_mangle] -pub extern "C" fn mozannotation_unregister(id: u32) -> bool { - let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; - let index = annotations.iter().position(|e| e.id == id); +pub extern "C" fn mozannotation_get_contents(id: u32, contents: *mut AnnotationContents) -> usize { + let annotations = &MOZANNOTATIONS.lock().unwrap().data; + if let Some(annotation) = annotations.iter().find(|e| e.id == id) { + if annotation.contents == AnnotationContents::Empty { + return 0; + } - if let Some(index) = index { - annotations.remove(index); - return true; + unsafe { *contents = annotation.contents }; + return annotation.address; } - false + return 0; +} + +#[no_mangle] +pub extern "C" fn mozannotation_clear_all() { + let annotations = &mut MOZANNOTATIONS.lock().unwrap().data; + annotations.clear(); } |