Bug 1776197 - mozannotation_client implementation r=afranchuk

This crate contains the required bits to store annotations in a process and
let the mozannotation_server crate find them and pull them out. Functionally
there's not much happening here as all the actual functionality is in
mozannotation_server.

Differential Revision: https://phabricator.services.mozilla.com/D173697
This commit is contained in:
Gabriele Svelto 2023-06-07 12:34:30 +00:00
Родитель 8dc38e490e
Коммит 73a3085a6b
9 изменённых файлов: 372 добавлений и 0 удалений

8
Cargo.lock сгенерированный
Просмотреть файл

@ -2107,6 +2107,7 @@ dependencies = [
"mime-guess-ffi",
"mio 0.8.0",
"moz_asserts",
"mozannotation_client",
"mozglue-static",
"mozurl",
"mp4parse_capi",
@ -3329,6 +3330,13 @@ dependencies = [
"moz_task",
]
[[package]]
name = "mozannotation_client"
version = "0.1.0"
dependencies = [
"nsstring",
]
[[package]]
name = "mozbuild"
version = "0.1.0"

Просмотреть файл

@ -63,6 +63,7 @@ if CONFIG["MOZ_CRASHREPORTER"]:
DIRS += [
"client",
"mozannotation_client",
]
if CONFIG["MOZ_CRASHREPORTER_INJECTOR"]:

Просмотреть файл

@ -0,0 +1,11 @@
[package]
name = "mozannotation_client"
version = "0.1.0"
authors = ["Gabriele Svelto"]
edition = "2018"
license = "MPL-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
nsstring = { path = "../../../xpcom/rust/nsstring/" }

Просмотреть файл

@ -0,0 +1,15 @@
header = """/* 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 http://mozilla.org/MPL/2.0/. */"""
autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. See RunCbindgen.py */
"""
include_version = true
braces = "SameLine"
line_length = 100
tab_width = 2
language = "C++"
include_guard = "mozannotation_client_ffi_generated_h"
includes = ["nsStringFwd.h"]
[export.rename]
"ThinVec" = "nsTArray"

Просмотреть файл

@ -0,0 +1,17 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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 http://mozilla.org/MPL/2.0/.
if CONFIG["COMPILE_ENVIRONMENT"]:
# This tells mach to run cbindgen and that this header-file should be created
CbindgenHeader(
"mozannotation_client_ffi_generated.h",
inputs=["/toolkit/crashreporter/mozannotation_client"],
)
# This tells mach to copy that generated file to obj/dist/include/mozilla/toolkit/crashreporter
EXPORTS.mozilla.toolkit.crashreporter += [
"!mozannotation_client_ffi_generated.h",
]

Просмотреть файл

@ -0,0 +1,317 @@
/* 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 http://mozilla.org/MPL/2.0/. */
use nsstring::nsCString;
use std::{ffi::c_void, sync::Mutex};
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::arch::global_asm;
#[repr(C)]
#[derive(Copy, Clone)]
pub enum AnnotationContents {
Empty,
NSCString,
CString,
CharBuffer,
USize,
ByteBuffer(u32),
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Annotation {
pub id: u32,
pub contents: AnnotationContents,
pub address: usize,
}
pub type AnnotationTable = Vec<Annotation>;
pub type AnnotationMutex = Mutex<AnnotationTable>;
#[cfg(target_os = "windows")]
#[link_section = "mozannot"]
static MOZANNOTATIONS: AnnotationMutex = Mutex::new(Vec::new());
#[cfg(any(target_os = "linux", target_os = "android"))]
static MOZANNOTATIONS: AnnotationMutex = Mutex::new(Vec::new());
#[cfg(target_os = "macos")]
#[link_section = "__DATA,mozannotation"]
static MOZANNOTATIONS: AnnotationMutex = Mutex::new(Vec::new());
#[no_mangle]
unsafe fn mozannotation_get() -> *const AnnotationMutex {
&MOZANNOTATIONS as _
}
extern "C" {
#[cfg(any(target_os = "linux", target_os = "android"))]
pub static MOZANNOTATION_NOTE_REFERENCE: &'static u32;
}
#[cfg(target_os = "windows")]
pub const ANNOTATION_SECTION: &'static [u8; 8] = b"mozannot";
// TODO: Use the following constants in the assembly below when constant
// expressions are stabilized: https://github.com/rust-lang/rust/issues/93332
#[cfg(any(target_os = "linux", target_os = "android"))]
const _ANNOTATION_NOTE_ALIGNMENT: u32 = 4;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const ANNOTATION_NOTE_NAME: &str = "mozannotation";
#[cfg(any(target_os = "linux", target_os = "android"))]
pub const ANNOTATION_TYPE: u32 = u32::from_le_bytes(*b"MOZA");
// We use the crashpad crash info trick here. We create a program note which
// we'll use to find the location of the MOZANNOTATIONS static. Since program
// headers are always available we'll always be able to find this note in the
// memory of the crashed program, even if it's stripped or the backing file on
// disk has been deleted.
//
// We'll set the note type and name so we can easily recognize it (see the
// constants above). In the note's desc field we'll have the linker store the
// offset between the address of the MOZANNOTATIONS static and the desc field
// itself.
//
// At runtime we'll localize the note in the target process' memory, find the
// address of the `desc` field, load its contents (that is the offset we stored
// at link time) and add them together. The resulting address is the location of
// the MOZANNOTATIONS static in memory.
#[cfg(all(
target_pointer_width = "64",
any(target_os = "linux", target_os = "android")
))]
global_asm!(
// The section holding the note will be called '.note.moz.annotation'. We
// create a program note that's allocated ('a' option) in the target binary
// so that it's loaded into memory.
" .section .note.moz.annotation,\"a\",%note",
// Note alignment must be 4 bytes because that's the default alignment for
// that section. If a different alignment is chosen the note will end up in
// its own section which we don't want.
" .balign 4", // TODO: _ANNOTATION_NOTE_ALIGNMENT
"MOZANNOTATION_NOTE:",
" .long name_end - name", // size in bytes of the note's name
" .long desc_end - desc", // size in bytes of the note's desc field
" .long 0x415a4f4d", // TODO: _ANNOTATION_TYPE, MOZA in reverse
"name:",
" .asciz \"mozannotation\"", // TODO: _ANNOTATION_NOTE_NAME
"name_end:",
" .balign 4", // TODO: _ANNOTATION_NOTE_ALIGNMENT
"desc:",
" .quad {mozannotation_symbol} - desc",
"desc_end:",
" .size MOZANNOTATION_NOTE, .-MOZANNOTATION_NOTE",
mozannotation_symbol = sym MOZANNOTATIONS
);
// The following global_asm!() expressions for other targets because Rust's
// support for putting statements within expressions is still experimental-only.
// Once https://github.com/rust-lang/rust/issues/15701 is fixed this can be
// folded in the `global_asm!()` statement above.
#[cfg(all(
target_pointer_width = "32",
any(target_os = "linux", target_os = "android")
))]
global_asm!(
" .section .note.moz.annotation,\"a\",%note",
" .balign 4",
"MOZANNOTATION_NOTE:",
" .long name_end - name",
" .long desc_end - desc",
" .long 0x415a4f4d",
"name:",
" .asciz \"mozannotation\"",
"name_end:",
" .balign 4",
"desc:",
" .long {mozannotation_symbol} - desc",
"desc_end:",
" .size MOZANNOTATION_NOTE, .-MOZANNOTATION_NOTE",
mozannotation_symbol = sym MOZANNOTATIONS
);
#[cfg(all(
any(target_os = "linux", target_os = "android"),
not(target_arch = "arm")
))]
global_asm!(
// MOZANNOTATION_NOTE can't be referenced directly because the relocation
// used to make the reference may require that the address be 8-byte aligned
// and notes must have 4-byte alignment.
" .section .rodata,\"a\",%progbits",
" .balign 8",
// .globl indicates that it's available to link against other .o files.
// .hidden indicates that it will not appear in the executable's symbol
// table.
" .globl",
" .hidden MOZANNOTATION_NOTE_REFERENCE",
" .type MOZANNOTATION_NOTE_REFERENCE, %object",
"MOZANNOTATION_NOTE_REFERENCE:",
// The value of this quad isn't important. It exists to reference
// MOZANNOTATION_NOTE, causing the linker to include the note into the
// binary linking the mozannotation_client crate. The subtraction from name
// is a convenience to allow the value to be computed statically.
" .quad name - MOZANNOTATION_NOTE",
);
// In theory we could have used the statement above for ARM targets but for some
// reason the current rust compiler rejects the .quad directive. As with the other
// duplicate code above we could replace this with a single conditional line once
// once https://github.com/rust-lang/rust/issues/15701 is fixed.
#[cfg(all(any(target_os = "linux", target_os = "android"), target_arch = "arm"))]
global_asm!(
" .section .rodata,\"a\",%progbits",
" .balign 8",
" .globl",
" .hidden MOZANNOTATION_NOTE_REFERENCE",
" .type MOZANNOTATION_NOTE_REFERENCE, %object",
"MOZANNOTATION_NOTE_REFERENCE:",
" .long name - MOZANNOTATION_NOTE",
);
/// This structure mirrors the contents of the note declared above in the
/// assembly blocks. It is used to copy the contents of the note out of the
/// target process.
#[cfg(any(target_os = "linux", target_os = "android"))]
#[allow(dead_code)]
#[repr(C, packed(4))]
pub struct MozAnnotationNote {
pub namesz: u32,
pub descsz: u32,
pub note_type: u32,
pub name: [u8; 16], // "mozannotation" plus padding to next 4-bytes boundary
pub desc: usize,
}
/// Register an annotation containing an nsCString.
/// Returns false if the annotation is already present (and doesn't change it).
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_nscstring(id: u32, address: *const nsCString) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
if annotations.iter().any(|e| e.id == id) {
return false;
}
annotations.push(Annotation {
id,
contents: AnnotationContents::NSCString,
address: address as usize,
});
true
}
/// Register an annotation containing a null-terminated string.
/// Returns false if the annotation is already present (and doesn't change it).
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_cstring(
id: u32,
address: *const *const std::ffi::c_char,
) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
if annotations.iter().any(|e| e.id == id) {
return false;
}
annotations.push(Annotation {
id,
contents: AnnotationContents::CString,
address: address as usize,
});
true
}
/// 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).
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_char_buffer(
id: u32,
address: *const std::ffi::c_char,
) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
if annotations.iter().any(|e| e.id == id) {
return false;
}
annotations.push(Annotation {
id,
contents: AnnotationContents::CharBuffer,
address: address as usize,
});
true
}
/// Register an annotation pointing to a variable of type usize.
/// Returns false if the annotation is already present (and doesn't change it).
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_usize(id: u32, address: *const usize) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
if annotations.iter().any(|e| e.id == id) {
return false;
}
annotations.push(Annotation {
id,
contents: AnnotationContents::USize,
address: address as usize,
});
true
}
/// Register an annotation pointing to a fixed size buffer.
/// Returns false if the annotation is already present (and doesn't change it).
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_bytebuffer(
id: u32,
address: *const c_void,
size: u32,
) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
if annotations.iter().any(|e| e.id == id) {
return false;
}
annotations.push(Annotation {
id,
contents: AnnotationContents::ByteBuffer(size),
address: address as usize,
});
true
}
/// Unregister a crash annotation. Returns false if the annotation is not present.
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_unregister(id: u32) -> bool {
let mut annotations = MOZANNOTATIONS.lock().unwrap();
let index = annotations.iter().position(|e| e.id == id);
if let Some(index) = index {
annotations.remove(index);
return true;
}
false
}

Просмотреть файл

@ -56,6 +56,7 @@ fluent-langneg = { version = "0.13", features = ["cldr"] }
fluent-langneg-ffi = { path = "../../../../intl/locale/rust/fluent-langneg-ffi" }
rure = "0.2.2"
rust_minidump_writer_linux = { path = "../../../crashreporter/rust_minidump_writer_linux", optional = true }
mozannotation_client = { path = "../../../crashreporter/mozannotation_client" }
gecko-profiler = { path = "../../../../tools/profiler/rust-api"}
midir_impl = { path = "../../../../dom/midi/midir_impl", optional = true }
dom = { path = "../../../../dom/base/rust" }

Просмотреть файл

@ -91,6 +91,7 @@ extern crate gecko_logger;
#[cfg(feature = "oxidized_breakpad")]
extern crate rust_minidump_writer_linux;
extern crate mozannotation_client;
#[cfg(feature = "webmidi_midir_impl")]
extern crate midir_impl;

Просмотреть файл

@ -33,6 +33,7 @@ clippy:
- testing/webdriver/
- third_party/rust/mp4parse/
- third_party/rust/mp4parse_capi/
- toolkit/crashreporter/mozannotation_client/
- toolkit/components/kvstore/
- toolkit/components/glean/
- toolkit/library/rust/