Skip to content

Commit 610ad43

Browse files
Collect runtime crash frames (#3479)
* Collect runtime crash frames Signed-off-by: Bob Weinand <[email protected]> * Adapt to newest libdatadog Signed-off-by: Bob Weinand <[email protected]> # Conflicts: # Cargo.lock * Fix Signed-off-by: Bob Weinand <[email protected]> * fix jit tags * Skip crash pings * Test FLF function in crashtrace Signed-off-by: Bob Weinand <[email protected]> --------- Signed-off-by: Bob Weinand <[email protected]> Co-authored-by: Florian Engelhardt <[email protected]>
1 parent 09e56b2 commit 610ad43

22 files changed

+790
-379
lines changed

Cargo.lock

Lines changed: 326 additions & 248 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ RUN_TESTS_CMD := DD_SERVICE= DD_ENV= REPORT_EXIT_STATUS=1 TEST_PHP_SRCDIR=$(PROJ
4848

4949
C_FILES = $(shell find components components-rs ext src/dogstatsd zend_abstract_interface -name '*.c' -o -name '*.h' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' )
5050
TEST_FILES = $(shell find tests/ext -name '*.php*' -o -name '*.inc' -o -name '*.json' -o -name '*.yaml' -o -name 'CONFLICTS' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' )
51-
RUST_FILES = $(BUILD_DIR)/Cargo.toml $(BUILD_DIR)/Cargo.lock $(shell find components-rs -name '*.c' -o -name '*.rs' -o -name 'Cargo.toml' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) $(shell find libdatadog/{build-common,datadog-crashtracker,datadog-crashtracker-ffi,data-pipeline,ddcommon,ddcommon-ffi,ddtelemetry,ddtelemetry-ffi,datadog-ipc,datadog-ipc-macros,datadog-live-debugger,datadog-live-debugger-ffi,datadog-remote-config,datadog-sidecar,datadog-sidecar-ffi,datadog-sidecar-macros,libdd-alloc,libdd-ddsketch,libdd-dogstatsd-client,libdd-library-config,libdd-library-config-ffi,libdd-log,libdd-tinybytes,spawn_worker,tools/{cc_utils,sidecar_mockgen},datadog-trace-*,Cargo.toml} \( -type l -o -type f \) \( -path "*/src*" -o -path "*/examples*" -o -path "*Cargo.toml" -o -path "*/build.rs" -o -path "*/tests/dataservice.rs" -o -path "*/tests/service_functional.rs" \) -not -path "*/datadog-ipc/build.rs" -not -path "*/datadog-sidecar-ffi/build.rs")
51+
RUST_FILES = $(BUILD_DIR)/Cargo.toml $(BUILD_DIR)/Cargo.lock $(shell find components-rs -name '*.c' -o -name '*.rs' -o -name 'Cargo.toml' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' ) $(shell find libdatadog/{build-common,datadog-crashtracker,datadog-crashtracker-ffi,datadog-ipc,datadog-ipc-macros,datadog-live-debugger,datadog-live-debugger-ffi,datadog-remote-config,datadog-sidecar,datadog-sidecar-ffi,datadog-sidecar-macros,libdd-alloc,libdd-common,libdd-common-ffi,libdd-data-pipeline,libdd-ddsketch,libdd-dogstatsd-client,libdd-library-config,libdd-library-config-ffi,libdd-log,libdd-telemetry,libdd-telemetry-ffi,libdd-tinybytes,libdd-trace-*,spawn_worker,tools/{cc_utils,sidecar_mockgen},datadog-trace-*,Cargo.toml} \( -type l -o -type f \) \( -path "*/src*" -o -path "*/examples*" -o -path "*Cargo.toml" -o -path "*/build.rs" -o -path "*/tests/dataservice.rs" -o -path "*/tests/service_functional.rs" \) -not -path "*/datadog-ipc/build.rs" -not -path "*/datadog-sidecar-ffi/build.rs")
5252
ALL_OBJECT_FILES = $(C_FILES) $(RUST_FILES) $(BUILD_DIR)/Makefile
5353
TEST_OPCACHE_FILES = $(shell find tests/opcache -name '*.php*' -o -name '.gitkeep' | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' )
5454
TEST_STUB_FILES = $(shell find tests/ext -type d -name 'stubs' -exec find '{}' -type f \; | awk '{ printf "$(BUILD_DIR)/%s\n", $$1 }' )
@@ -424,14 +424,14 @@ generate_cbindgen: cbindgen_binary # Regenerate components-rs/ddtrace.h componen
424424
--config cbindgen.toml \
425425
--output $(PROJECT_ROOT)/components-rs/ddtrace.h; \
426426
cd libdatadog; \
427-
$(command rustup && echo run nightly --) cbindgen --crate ddcommon-ffi \
428-
--config ddcommon-ffi/cbindgen.toml \
427+
$(command rustup && echo run nightly --) cbindgen --crate libdd-common-ffi \
428+
--config libdd-common-ffi/cbindgen.toml \
429429
--output $(PROJECT_ROOT)/components-rs/common.h; \
430430
$(command rustup && echo run nightly --) cbindgen --crate datadog-live-debugger-ffi \
431431
--config datadog-live-debugger-ffi/cbindgen.toml \
432432
--output $(PROJECT_ROOT)/components-rs/live-debugger.h; \
433-
$(command rustup && echo run nightly --) cbindgen --crate ddtelemetry-ffi \
434-
--config ddtelemetry-ffi/cbindgen.toml \
433+
$(command rustup && echo run nightly --) cbindgen --crate libdd-telemetry-ffi \
434+
--config libdd-telemetry-ffi/cbindgen.toml \
435435
--output $(PROJECT_ROOT)/components-rs/telemetry.h; \
436436
$(command rustup && echo run nightly --) cbindgen --crate datadog-sidecar-ffi \
437437
--config datadog-sidecar-ffi/cbindgen.toml \

cbindgen.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ rename_variants = "ScreamingSnakeCase"
3030
[parse]
3131
parse_deps = true
3232
include = [
33-
"ddcommon",
34-
"ddtelemetry",
35-
"ddtelemetry-ffi",
36-
"ddcommon-ffi",
33+
"libdd-common",
34+
"libdd-telemetry",
35+
"libdd-telemetry-ffi",
36+
"libdd-common-ffi",
3737
"datadog-crashtracker-ffi",
3838
"datadog-sidecar",
3939
"datadog-ipc",

components-rs/Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ crate-type = ["staticlib", "cdylib"]
88
path = "lib.rs"
99

1010
[dependencies]
11-
ddcommon = { path = "../libdatadog/ddcommon", features = ["cgroup_testing"] }
12-
ddcommon-ffi = { path = "../libdatadog/ddcommon-ffi", default-features = false }
13-
ddtelemetry = { path = "../libdatadog/ddtelemetry" }
14-
ddtelemetry-ffi = { path = "../libdatadog/ddtelemetry-ffi", default-features = false }
11+
libdd-common = { path = "../libdatadog/libdd-common", features = ["cgroup_testing"] }
12+
libdd-common-ffi = { path = "../libdatadog/libdd-common-ffi", default-features = false }
13+
libdd-telemetry = { path = "../libdatadog/libdd-telemetry" }
14+
libdd-telemetry-ffi = { path = "../libdatadog/libdd-telemetry-ffi", default-features = false }
1515
datadog-live-debugger = { path = "../libdatadog/datadog-live-debugger" }
1616
datadog-live-debugger-ffi = { path = "../libdatadog/datadog-live-debugger-ffi", default-features = false }
1717
datadog-ipc = { path = "../libdatadog/datadog-ipc" }
1818
datadog-remote-config = { path = "../libdatadog/datadog-remote-config" }
1919
datadog-sidecar = { path = "../libdatadog/datadog-sidecar" }
2020
datadog-sidecar-ffi = { path = "../libdatadog/datadog-sidecar-ffi" }
2121
libdd-tinybytes = { path = "../libdatadog/libdd-tinybytes" }
22-
datadog-trace-utils = { path = "../libdatadog/datadog-trace-utils" }
22+
libdd-trace-utils = { path = "../libdatadog/libdd-trace-utils" }
2323
datadog-crashtracker-ffi = { path = "../libdatadog/datadog-crashtracker-ffi", default-features = false, features = ["collector"] }
2424
libdd-library-config-ffi = { path = "../libdatadog/libdd-library-config-ffi", default-features = false }
2525
spawn_worker = { path = "../libdatadog/spawn_worker" }

components-rs/bytes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use datadog_trace_utils::span::SpanBytes;
2-
use ddcommon_ffi::slice::{AsBytes, CharSlice};
1+
use libdd_trace_utils::span::SpanBytes;
2+
use libdd_common_ffi::slice::{AsBytes, CharSlice};
33
use std::borrow::Cow;
44
use std::ffi::CStr;
55
use std::os::raw::c_char;

components-rs/common.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,14 @@ typedef enum ddog_crasht_BuildIdType {
10521052
DDOG_CRASHT_BUILD_ID_TYPE_SHA1,
10531053
} ddog_crasht_BuildIdType;
10541054

1055+
/**
1056+
* Result type for runtime callback registration
1057+
*/
1058+
typedef enum ddog_crasht_CallbackResult {
1059+
DDOG_CRASHT_CALLBACK_RESULT_OK,
1060+
DDOG_CRASHT_CALLBACK_RESULT_ERROR,
1061+
} ddog_crasht_CallbackResult;
1062+
10551063
typedef enum ddog_crasht_DemangleOptions {
10561064
DDOG_CRASHT_DEMANGLE_OPTIONS_COMPLETE,
10571065
DDOG_CRASHT_DEMANGLE_OPTIONS_NAME_ONLY,
@@ -1506,6 +1514,46 @@ typedef struct ddog_StringWrapperResult {
15061514
};
15071515
} ddog_StringWrapperResult;
15081516

1517+
typedef struct ddog_crasht_RuntimeStackFrame {
1518+
/**
1519+
* Line number in source file (0 if unknown)
1520+
*/
1521+
uint32_t line;
1522+
/**
1523+
* Column number in source file (0 if unknown)
1524+
*/
1525+
uint32_t column;
1526+
/**
1527+
* Function name (fully qualified if possible)
1528+
*/
1529+
ddog_CharSlice function;
1530+
/**
1531+
* Source file name
1532+
*/
1533+
ddog_CharSlice file;
1534+
/**
1535+
* Type name (class/module/namespace/etc.)
1536+
*/
1537+
ddog_CharSlice type_name;
1538+
} ddog_crasht_RuntimeStackFrame;
1539+
1540+
typedef void (*ddog_crasht_RuntimeStackFrameCallback)(void (*emit_frame)(const struct ddog_crasht_RuntimeStackFrame*));
1541+
1542+
/**
1543+
* Function signature for runtime stacktrace string collection callbacks
1544+
*
1545+
* This callback is invoked during crash handling in a signal context, so it must be signal-safe:
1546+
*
1547+
* # Parameters
1548+
* - `emit_stacktrace_string`: Function to call for complete stacktrace string (takes C string)
1549+
*
1550+
* # Safety
1551+
* The callback function is marked unsafe because:
1552+
* - It receives function pointers that take raw pointers as parameters
1553+
* - All C strings passed must be null-terminated and remain valid for the call duration
1554+
*/
1555+
typedef void (*ddog_crasht_RuntimeStacktraceStringCallback)(void (*emit_stacktrace_string)(const char*));
1556+
15091557
typedef enum ddog_LibraryConfigSource {
15101558
DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG = 0,
15111559
DDOG_LIBRARY_CONFIG_SOURCE_FLEET_STABLE_CONFIG = 1,

components-rs/crashtracker.h

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -643,27 +643,19 @@ struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_trace_id(struct ddog_cr
643643
* The CharSlice must be valid.
644644
*/
645645
DDOG_CHECK_RETURN
646-
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_uuid(struct ddog_crasht_Handle_CrashInfoBuilder *builder,
647-
ddog_CharSlice uuid);
646+
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_message(struct ddog_crasht_Handle_CrashInfoBuilder *builder,
647+
ddog_CharSlice message);
648648

649649
/**
650650
* # Safety
651651
* The `builder` can be null, but if non-null it must point to a Builder made by this module,
652652
* which has not previously been dropped.
653-
* The CharSlice must be valid.
654-
*/
655-
DDOG_CHECK_RETURN
656-
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_uuid_random(struct ddog_crasht_Handle_CrashInfoBuilder *builder);
657-
658-
/**
659-
* # Safety
660-
* The `crash_info` can be null, but if non-null it must point to a Builder made by this module,
661-
* which has not previously been dropped.
662-
* The CharSlice must be valid.
653+
* All arguments must be valid.
654+
* This method requires that the builder has a UUID, siginfo, and metadata set
663655
*/
664656
DDOG_CHECK_RETURN
665-
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_with_message(struct ddog_crasht_Handle_CrashInfoBuilder *builder,
666-
ddog_CharSlice message);
657+
struct ddog_VoidResult ddog_crasht_CrashInfoBuilder_upload_ping_to_endpoint(struct ddog_crasht_Handle_CrashInfoBuilder *builder,
658+
const struct ddog_Endpoint *endpoint);
667659

668660
/**
669661
* Create a new StackFrame, and returns an opaque reference to it.
@@ -884,6 +876,76 @@ DDOG_CHECK_RETURN struct ddog_VoidResult ddog_crasht_receiver_entry_point_stdin(
884876
DDOG_CHECK_RETURN
885877
struct ddog_VoidResult ddog_crasht_receiver_entry_point_unix_socket(ddog_CharSlice socket_path);
886878

879+
/**
880+
* Register a runtime stack collection callback
881+
*
882+
* # Arguments
883+
* - `callback`: The callback function to invoke during crashes
884+
*
885+
* # Returns
886+
* - `CallbackResult::Ok` if registration succeeds
887+
* - `CallbackResult::Error` if registration fails
888+
*
889+
* # Safety
890+
* - The callback must be signal-safe
891+
* - Only one callback can be registered at a time
892+
* - The callback must be registered once on CrashTracker initialization, before any crash occurs
893+
*
894+
* # Example Usage from C
895+
* ```c
896+
* static void my_runtime_callback(
897+
* void (*emit_frame)(const ddog_RuntimeStackFrameFFI*),
898+
* ) {
899+
* // Collect runtime frames and call emit_frame for each one
900+
* const char* function_name = "my_function";
901+
* const char* file_name = "script.rb";
902+
* ddog_CharSlice type_name = DDOG_CHARSLICE_FROM_CSTR("MyModule.MyClass");
903+
* ddog_crasht_RuntimeStackFrameFFI frame = {
904+
* .type_name = type_name,
905+
* .function = DDOG_CHARSLICE_FROM_CSTR(function_name),
906+
* .file = DDOG_CHARSLICE_FROM_CSTR(file_name),
907+
* .line = 42,
908+
* .column = 10
909+
* };
910+
* emit_frame(&frame);
911+
* }
912+
*/
913+
enum ddog_crasht_CallbackResult ddog_crasht_register_runtime_frame_callback(ddog_crasht_RuntimeStackFrameCallback callback);
914+
915+
/**
916+
* Register a runtime stacktrace string collection callback
917+
*
918+
* # Arguments
919+
* - `callback`: The callback function to invoke during crashes
920+
*
921+
* # Returns
922+
* - `CallbackResult::Ok` if registration succeeds (replaces any existing callback)
923+
* - `CallbackResult::Error` if registration fails
924+
*
925+
* # Safety
926+
* - The callback must be signal-safe
927+
* - Only one callback can be registered at a time (this replaces any existing one)
928+
*/
929+
enum ddog_crasht_CallbackResult ddog_crasht_register_runtime_stacktrace_string_callback(ddog_crasht_RuntimeStacktraceStringCallback callback);
930+
931+
/**
932+
* Returns true if a callback is registered, false otherwise
933+
*
934+
* # Safety
935+
* This function is safe to call at any time
936+
*/
937+
bool ddog_crasht_is_runtime_callback_registered(void);
938+
939+
/**
940+
* Get the callback type from the currently registered callback context
941+
*
942+
* # Safety
943+
* - The returned pointer is valid only while the callback remains registered
944+
* - The caller should not free the returned pointer
945+
* - The returned string should be copied if it needs to persist beyond callback lifetime
946+
*/
947+
const char *ddog_crasht_get_registered_callback_type(void);
948+
887949
#ifdef __cplusplus
888950
} // extern "C"
889951
#endif // __cplusplus

components-rs/lib.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub mod sidecar;
88
pub mod telemetry;
99
pub mod bytes;
1010

11-
use ddcommon::entity_id::{get_container_id, set_cgroup_file};
11+
use libdd_common::entity_id::{get_container_id, set_cgroup_file};
1212
use http::uri::{PathAndQuery, Scheme};
1313
use http::Uri;
1414
use std::borrow::Cow;
@@ -19,10 +19,10 @@ use uuid::Uuid;
1919
pub use datadog_crashtracker_ffi::*;
2020
pub use libdd_library_config_ffi::*;
2121
pub use datadog_sidecar_ffi::*;
22-
use ddcommon::{parse_uri, Endpoint};
23-
use ddcommon_ffi::slice::AsBytes;
24-
pub use ddcommon_ffi::*;
25-
pub use ddtelemetry_ffi::*;
22+
use libdd_common::{parse_uri, Endpoint};
23+
use libdd_common_ffi::slice::AsBytes;
24+
pub use libdd_common_ffi::*;
25+
pub use libdd_telemetry_ffi::*;
2626

2727
#[no_mangle]
2828
#[allow(non_upper_case_globals)]

components-rs/log.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use tracing_subscriber::fmt::{FmtContext, FormatEvent, FormatFields};
1010
use tracing_subscriber::fmt::format::Writer;
1111
use tracing_subscriber::registry::LookupSpan;
1212
use tracing_subscriber::util::SubscriberInitExt;
13-
use ddcommon_ffi::CharSlice;
14-
use ddcommon_ffi::slice::AsBytes;
13+
use libdd_common_ffi::CharSlice;
14+
use libdd_common_ffi::slice::AsBytes;
1515

1616
pub const LOG_ONCE: isize = 1 << 3;
1717

components-rs/remote_config.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ use datadog_sidecar::service::blocking::SidecarTransport;
1515
use datadog_sidecar::service::{InstanceId, QueueId};
1616
use datadog_sidecar::shm_remote_config::{RemoteConfigManager, RemoteConfigUpdate};
1717
use datadog_sidecar_ffi::ddog_sidecar_send_debugger_diagnostics;
18-
use ddcommon::tag::Tag;
19-
use ddcommon::Endpoint;
20-
use ddcommon_ffi::slice::AsBytes;
21-
use ddcommon_ffi::{CharSlice, MaybeError};
18+
use libdd_common::tag::Tag;
19+
use libdd_common::Endpoint;
20+
use libdd_common_ffi::slice::AsBytes;
21+
use libdd_common_ffi::{CharSlice, MaybeError};
2222
use itertools::Itertools;
2323
use regex_automata::dfa::regex::Regex;
2424
use serde::Serialize;
@@ -39,14 +39,14 @@ type DynamicConfigUpdate = for<'a> extern "C" fn(
3939
static mut LIVE_DEBUGGER_CALLBACKS: Option<LiveDebuggerCallbacks> = None;
4040
static mut DYNAMIC_CONFIG_UPDATE: Option<DynamicConfigUpdate> = None;
4141

42-
type VecRemoteConfigProduct = ddcommon_ffi::Vec<RemoteConfigProduct>;
42+
type VecRemoteConfigProduct = libdd_common_ffi::Vec<RemoteConfigProduct>;
4343
#[no_mangle]
44-
pub static mut DDTRACE_REMOTE_CONFIG_PRODUCTS: VecRemoteConfigProduct = ddcommon_ffi::Vec::new();
44+
pub static mut DDTRACE_REMOTE_CONFIG_PRODUCTS: VecRemoteConfigProduct = libdd_common_ffi::Vec::new();
4545

46-
type VecRemoteConfigCapabilities = ddcommon_ffi::Vec<RemoteConfigCapabilities>;
46+
type VecRemoteConfigCapabilities = libdd_common_ffi::Vec<RemoteConfigCapabilities>;
4747
#[no_mangle]
4848
pub static mut DDTRACE_REMOTE_CONFIG_CAPABILITIES: VecRemoteConfigCapabilities =
49-
ddcommon_ffi::Vec::new();
49+
libdd_common_ffi::Vec::new();
5050

5151
#[derive(Default)]
5252
struct DynamicConfig {
@@ -433,7 +433,7 @@ pub extern "C" fn ddog_remote_configs_service_env_change(
433433
service: CharSlice,
434434
env: CharSlice,
435435
version: CharSlice,
436-
tags: &ddcommon_ffi::Vec<Tag>,
436+
tags: &libdd_common_ffi::Vec<Tag>,
437437
) -> bool {
438438
let new_target = Target {
439439
service: service.to_utf8_lossy().to_string(),

0 commit comments

Comments
 (0)