libdd_crashtracker/lib.rs
1// Copyright 2023-Present Datadog, Inc. https://www.datadoghq.com/
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module implements a crashtracker based on catching UNIX signals and
5//! uploading the result to the backend.
6//!
7//! Architecturally, it consists of two parts:
8//! 1. A signal handler, which catches a UNIX signal (SIGSEGV, SIGBUS, SIGABRT)
9//! associated with a crash, and and collects information about the state of
10//! the program at crash time. The signal handler runs under a constrained
11//! environment where many standard operations are illegal.
12//! <https://man7.org/linux/man-pages/man7/signal-safety.7.html>
13//! In particular, memory allocation, and synchronization such as mutexes, are
14//! potentially UB. The signal handler therefore does as little as possible
15//! in process, and instead writes data across a socket to a separate receiver
16//! process.
17//! The signal handler then waits for the receiver process to exit in order to reap its exit
18//! status (otherwise, upon the termination of the crashing process the child will be
19//! re-parented to PID 1 in the current PID namespace, which can be problematic for some user
20//! applications) and restores the previous signal handler.
21//! Once the receiver has completed, the crash-handler returns, allowing the
22//! previous crash handler (if any) to execute, maintaining the customer
23//! experience as much as possible.
24//! 2. The receiver process, which is spawned by the signal handler. It is connected by an
25//! anynomous AF_UNIX `socketpair()` to the parent process. When a crash occurs, the receiver
26//! gathers the information from the pipe, adds additional data about the system state (e.g.
27//! /proc/cpuinfo and /proc/meminfo), formats it into a crash report, uploads it to the backend,
28//! and then exits. The signal handler must wait for the receiver in order to reap its exit
29//! status.
30//!
31//! Data collected:
32//! 1. The data collected by the crash-handler includes:
33//! 1. The signal type leading to the crash
34//! 2. The stacktrace at time of crash (for the crashing thread). Depending on a flag, this can
35//! either be resolved, or raw addresses. Resolving addresses provide more data, but sometimes
36//! crashes the crash handler (ironic).
37//! 3. System level info (e.g. /proc/self/maps).
38//! 4. The result of counters describing the current state of the profiler.
39//! 2. Data augmented by the receiver includes:
40//! 1. Metadata provided by the caller (e.g. library & profiler versions).
41//! 2. System info: OS version, /proc/cpuinfo /proc/meminfo, etc.
42//! 3. A timestamp and GUID for tracking the crash report.
43//!
44//! Handling of forks
45//! Safety issues
46
47#![cfg_attr(not(test), deny(clippy::panic))]
48#![cfg_attr(not(test), deny(clippy::unwrap_used))]
49#![cfg_attr(not(test), deny(clippy::expect_used))]
50#![cfg_attr(not(test), deny(clippy::todo))]
51#![cfg_attr(not(test), deny(clippy::unimplemented))]
52
53#[cfg(all(unix, feature = "collector"))]
54mod collector;
55#[cfg(all(windows, feature = "collector_windows"))]
56mod collector_windows;
57#[cfg(unix)]
58mod common;
59mod crash_info;
60#[cfg(all(unix, feature = "receiver"))]
61mod receiver;
62mod runtime_callback;
63
64// Keep this module private to avoid exposing blazesym to users of the crate
65#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
66#[cfg(not(feature = "benchmarking"))]
67mod shared;
68
69// Make this module public when benchmarking is enabled to allow access to constants
70#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
71#[cfg(feature = "benchmarking")]
72pub mod shared;
73
74#[cfg(all(unix, feature = "collector"))]
75pub use collector::{
76 begin_op, clear_additional_tags, clear_spans, clear_traces, consume_and_emit_additional_tags,
77 default_signals, disable, enable, end_op, init, insert_additional_tag, insert_span,
78 insert_trace, on_fork, reconfigure, remove_additional_tag, remove_span, remove_trace,
79 reset_counters, update_config, update_metadata, OpTypes, DEFAULT_SYMBOLS,
80};
81
82#[cfg(all(windows, feature = "collector_windows"))]
83pub use collector_windows::api::{exception_event_callback, init_crashtracking_windows};
84
85pub use crash_info::*;
86pub use runtime_callback::*;
87
88#[cfg(all(unix, feature = "receiver"))]
89pub use receiver::{
90 async_receiver_entry_point_unix_listener, async_receiver_entry_point_unix_socket,
91 get_receiver_unix_socket, receiver_entry_point_stdin, receiver_entry_point_unix_socket,
92};
93
94#[cfg(all(unix, any(feature = "collector", feature = "receiver")))]
95pub use shared::configuration::{
96 CrashtrackerConfiguration, CrashtrackerReceiverConfig, StacktraceCollection,
97};
98
99#[cfg(all(unix, feature = "benchmarking"))]
100pub use receiver::benchmark;
101
102#[cfg(unix)]
103pub use common::{get_tests_folder_path, SharedLibrary};