Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/ci/appsec-gradle-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ If you need to inspect sidecar/helper or PHP issues:
(`pref -f dd-ipc-helper`) or to PHP (usually an apache or an FPM worker -- if
you're investigating code run during processes it will not be the master
process). sidecar requires as a first command `file /proc/<pid>/exe`).
* See [gdb.md](../gdb.md) for more information on how to run gdb. Always read
* See [gdb.md](../debugging/gdb.md) for more information on how to run gdb. Always read
this file before attempting to use gdb.

## Gotchas
Expand Down
2 changes: 1 addition & 1 deletion .claude/ci/system-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ cd /path/to/system-tests
architecture in the filename. CI always sets this variable.
Alternatively, build an arm64 `.so` with `make` (not `make static`)
and use the `.so` override path — see
[../debugging-system-tests.md](../debugging-system-tests.md).
[../debugging/system-tests.md](../debugging/system-tests.md).

- Artifacts are collected from `system-tests/logs_parametric/` and
`system-tests/logs/` -- these directories are always uploaded
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The appsec Gradle integration tests run inside Docker containers. Use
attach gdb to processes inside the container (PHP-FPM workers, sidecar).

See [gdb.md](gdb.md) for gdb-specific instructions.
See [ci/appsec-gradle-integration.md](ci/appsec-gradle-integration.md) for
See [ci/appsec-gradle-integration.md](../ci/appsec-gradle-integration.md) for
Gradle test details.

## Workflow
Expand Down
File renamed without changes.
13 changes: 13 additions & 0 deletions .claude/debugging/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Debugging guides

How to debug this project's components locally. Each file covers one scenario.

| Guide | Covers |
|---|---|
| [gdb.md](gdb.md) | gdb-via-tmux fundamentals: attaching, scripting, watchpoints, reading optimized-out vars, C-vs-Rust language mode, attaching to the sidecar. Start here for any native (C/Rust) debugging. |
| [appsec-integration.md](appsec-integration.md) | Debugging the appsec Gradle integration tests: driving containers with `jdb` (`--debug-jvm`) + gdb, breakpoint strategy, keeping the container alive, the sidecar watchdog. |
| [system-tests.md](system-tests.md) | Debugging system tests locally (arm64): pytest `--pdb` + gdb inside the weblog container. |

Related: for *building* the binaries you debug, see
[../ci/building-locally.md](../ci/building-locally.md); for reproducing a
specific CI job, see [../ci/index.md](../ci/index.md).
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Combines Python debugging (pytest `--pdb`) with gdb inside the weblog
container. For build/run instructions see
[ci/system-tests.md](ci/system-tests.md). For gdb fundamentals see
[ci/system-tests.md](../ci/system-tests.md). For gdb fundamentals see
[gdb.md](gdb.md).

## arm64-specific build notes
Expand All @@ -20,7 +20,7 @@ emulation is too slow.

## Building ddtrace.so with Rust linked

See [ci/building-locally.md](ci/building-locally.md#for-system-tests-centos-7-release-like-build)
See [ci/building-locally.md](../ci/building-locally.md#for-system-tests-centos-7-release-like-build)
for the build command, CARGO_HOME workaround, and `make` vs
`make static` explanation.

Expand Down
52 changes: 52 additions & 0 deletions .claude/project/appsec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# appsec/ — application security

## What it is

A separate PHP extension (`ddappsec.so`) plus a standalone WAF helper
process (`libddappsec-helper.so`, C++ original or Rust rewrite). The helper
runs libddwaf on request data, handles remote config and security actions;
matches tag spans via `asm_event`.

## Key files & dirs

- `appsec/src/extension/` — `ddappsec.c`,
`commands/{client_init,request_init,request_exec,request_shutdown}.c`,
`helper_process.c`, `configuration.c`, `msgpack_helpers.c`,
`ip_extraction.c`.
- `appsec/src/helper/` — C++ helper: `main.cpp`, `client`/`runner`/`engine`/
`service` (`.cpp`/`.hpp`), and dirs `network/`, `remote_config/`,
`subscriber/`.
- `appsec/helper-rust/` — Rust helper:
`src/{lib,server,client,service,config,rc,telemetry}.rs`, `build.rs`,
`CLAUDE.md`.
- `appsec/third_party/{libddwaf,libddwaf-rust,msgpack-c,cpp-base64}/`.

## How it fits

AppSec is enabled through the sidecar: during sidecar setup `ext/sidecar.c`
calls the appsec module's `dd_appsec_maybe_enable_helper` →
`ddog_sidecar_enable_appsec` with the resolved helper path (Rust helper if
present, else C++), before ddappsec's first RINIT. Per request the extension
sends headers/body/query to the helper via msgpack; the helper runs the WAF
and returns block/redirect decisions + matched rules. Matches emit
`asm_event`, which [tracer/](tracer.md) attaches to the root span on serialize.

Two decoupled `.so` files (can be disabled independently); talks to the
helper over msgpack; integrates with the tracer via `asm_event` and reads
remote config (ASM rules) via the [sidecar](sidecar.md).

## Gotchas

- Two helper implementations: C++ (reference) vs Rust (modern, the CMake
default). `-PuseHelperCpp` is an appsec integration-test Gradle property that
runs the tests against the C++ helper — not a build-time selector.
- Submodules required: `libddwaf`, `libddwaf-rust`, `msgpack-c`,
`cpp-base64`, `libdatadog` — see
[building-locally.md](../ci/building-locally.md#submodule-initialisation).
- The C++ helper needs C++17 / devtoolset on CentOS.
- `appsec/helper-rust/CLAUDE.md` has the deep guide for the Rust helper.
- Helper build differs by implementation: Gradle/Docker for Rust, CMake for
C++.
- For build/test detail see
[../ci/building-locally.md](../ci/building-locally.md) and
[../debugging/index.md](../debugging/index.md).
45 changes: 45 additions & 0 deletions .claude/project/components.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# components/ + components-rs/ + zend_abstract_interface/ (ZAI)

## What it is

- `components/` — PHP-agnostic C utilities (no Zend API), each with its own
`.h`/`.c` + CMake tests.
- `components-rs/` — Rust FFI bridge to libdatadog (cbindgen-generated
headers).
- `zend_abstract_interface/` (ZAI) — Zend engine abstraction gating
PHP-version differences.

## Key files & dirs

- `components/{string_view,log,sapi,stack-sample}/` (+ polyfill headers).
- `components-rs/lib.rs` — modules: `agent_info`, `log`, `remote_config`,
`sidecar`, `stats`, `telemetry`, `trace_filter`, `bytes`.
- `components-rs/{common,datadog,sidecar,telemetry,crashtracker,
library-config,live-debugger}.h` — cbindgen-generated.
- `components-rs/Cargo.toml`.
- `zend_abstract_interface/{hook,config,env,zai_string,
sandbox/{php7,php8},interceptor/{php7,php8},jit_utils,exceptions,headers,
json,uri_normalization}/`.

## How it fits

[ext/](ext.md) and [tracer/](tracer.md) `#include` component headers
(symbols prefixed `datadog_php_`); components compile via `config.m4`.
`components-rs` compiles into `libdatadog_php.a` and links in; C calls
`#[no_mangle] extern "C"` functions. `make generate_cbindgen` regenerates
headers (CI checks they're up to date).

ZAI: `tracer/` calls `zai_hook_install()`; ZAI absorbs PHP7 vs PHP8
(`zend_observer`) differences so callers avoid scattered `PHP_VERSION_ID`
checks.

## Gotchas

- No Zend API allowed in `components/`.
- `components/container_id/` is a stale build-artifact dir (no source);
container ID access is in the Rust bridge (`ddtrace_get_container_id`).
- Version gating is concentrated in ZAI (`hook.c`, `sandbox/php{7,8}`,
`interceptor/php{7,8}`) — put new version-dependent logic there, not in
scattered `PHP_VERSION_ID` checks elsewhere.
- Keep the FFI surface small: don't leak libdatadog structs into C.
- Regenerate cbindgen headers whenever `lib.rs` changes.
54 changes: 54 additions & 0 deletions .claude/project/ext.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# ext/ — extension infra shared across products

## What it is

Runtime bedrock shared by tracer, profiler, and appsec: config, sidecar IPC,
telemetry, remote config, signal handlers, logging, agent connectivity.
Tracer-specific C was split out into [tracer/](tracer.md) (#3912); stray
`ext/hook/`, `ext/integrations/` etc. are build artifacts, not sources.

## Key files & dirs

- `ext/datadog.c` — module entry (MINIT/RINIT/RSHUTDOWN/MSHUTDOWN).
- `ext/configuration.{c,h}` — shared/infra x-macro INI/env table (tracer-
specific config is in `tracer/configuration.h`).
- `ext/sidecar.{c,h}` — IPC to the sidecar (see [sidecar.md](sidecar.md)).
- `ext/telemetry.{c,h}`, `ext/remote_config.{c,h}` — sidecar-backed features.
- `ext/logging.{c,h}` — signal-safe logging for the background sender.
- `ext/signals.{c,h}` — SIGTERM/INT/CHLD, `pcntl_fork` interception.
- `ext/endpoints.c` — agent/dogstatsd URL resolution.
- `ext/startup_logging.{c,h}` — first-RINIT diagnostics.
- `ext/process_tags.{c,h}`, `ext/agent_info.c`, `ext/git.c`.
- `ext/otel_config.{c,h}` — `OTEL_*` → `DD_*` bridging.
- `ext/crashtracking_windows.c` — Windows only; Unix crashtracking lives in
libdatadog Rust.

## How it fits

MINIT: logging init first, then config, `zend_extension` registration,
sidecar, remote_config, signals (tracer pre/early/late phases interleave).

RINIT: remote_config → one-time `dd_rinit_once` (process tags, signals,
startup diagnostics, tracer first-rinit) → agent_info → sidecar → tracer.

RSHUTDOWN: remote_config → tracer → sidecar (finalize) → telemetry →
sidecar (rshutdown) → git.

MSHUTDOWN is **not** a reverse of MINIT — notably the sidecar shuts down
late (after config is freed). Order: tracer → remote_config → signals → log
→ config → sidecar → process_tags.

`ext/configuration.h` holds the shared/infra x-macro config table (tracer-
specific config lives in `tracer/configuration.h`). ext/ exposes the
sidecar/telemetry/remote_config public API consumed by [tracer/](tracer.md),
[appsec/](appsec.md), and [profiling/](profiling.md).

## Gotchas

- Config is x-macro-driven: add a macro + parser, not ad hoc code.
- `DD_TRACE_SIDECAR_CONNECTION_MODE`: `subprocess` is fork-safe, `thread` is
not — see [sidecar.md](sidecar.md).
- `PHP_VERSION_ID` gating throughout; prefer ZAI (see
[components.md](components.md)) for anything non-trivial.
- Signal handlers use a best-effort sidecar pointer (may be null/stale).
- Telemetry redacts repo paths before upload.
119 changes: 119 additions & 0 deletions .claude/project/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Project knowledge

The Datadog PHP tracer (`ddtrace`): a PHP extension bringing APM, distributed
tracing, profiling, and application security to PHP. Multi-language:

- **C** extension (`ext/`, `tracer/`) — low-level hooks and runtime glue.
- **Rust** (`components-rs/`, `libdatadog/` submodule, `profiling/`, appsec
helper) — shared cross-tracer functionality, sidecar, crashtracker.
- **PHP** userland (`src/`) — high-level instrumentation.

User docs: <https://docs.datadoghq.com/tracing/languages/php/>.
For build/test/CI, see the pointers below — do not duplicate them here.

## Layout

```
ext/ Extension infra shared across products: sidecar,
telemetry, remote_config, otel_config, process_tags,
agent_info, crashtracking, configuration, logging,
signal/pcntl handlers, startup.
tracer/ Tracer-specific C: ddtrace.c, hook/ (userland hooks),
integrations/, limiter/, priority_sampling/,
tracer_tag_propagation/, distributed tracing,
code_origins, asm_event, collect_backtrace,
live_debugger, inferred_proxy_headers,
endpoint_guessing, coms/auto_flush (trace sender).
src/ PHP userland: DDTrace/, api/, bridge/, dogstatsd/.
components/ PHP-agnostic C, one .h/.c + tests/ each (CMake).
components-rs/ PHP-specific Rust wrapping libdatadog.
libdatadog/ Datadog shared Rust library (git submodule).
zend_abstract_interface/ Zend engine abstraction across PHP versions (ZAI).
appsec/ Application security (extension + C++/Rust helpers).
profiling/ Rust profiler extension.
loader/ SSI loader.
tea/ Test harness for ZAI/components.
tests/ .phpt tests + PHPUnit (tests/Integration/).
tooling/ Packaging, installers, artifact helpers.
dockerfiles/ Dev/CI images and package verification.
```

> The tracer C was split out of `ext/` into `tracer/` (#3912). Stray
> `ext/hook/`, `ext/integrations/` etc. are build artifacts, not sources —
> the tracked sources live under `tracer/`.

## Subsystem map

| Area | What | Guide |
|---|---|---|
| `ext/` | Shared runtime infra: config, sidecar IPC, telemetry, remote config, signals | [ext.md](ext.md) |
| `tracer/` | Instrumentation engine: spans, sampling, serialization, hooks, trace sender | [tracer.md](tracer.md) |
| `src/` | PHP userland: Tracer/Span API, propagators, ~40 integrations | [userland.md](userland.md) |
| `components/`, `components-rs/`, ZAI | PHP-agnostic C, Rust FFI bridge, Zend version abstraction | [components.md](components.md) |
| sidecar | Rust background service for async I/O (trace/telemetry/RC upload) | [sidecar.md](sidecar.md) |
| `appsec/` | Application security extension + WAF helper process | [appsec.md](appsec.md) |
| `profiling/` | Rust profiler extension (CPU/wall/alloc/exception) | [profiling.md](profiling.md) |

## Architecture

**PHP version support.** PHP 7.0 → 8.5+. Version-specific behavior gates on
`PHP_VERSION_ID` macros; `zend_abstract_interface/` (ZAI) absorbs Zend API
differences (see [components.md](components.md)). Common C is gradually
extracted into PHP-agnostic `components/`.

**Trace sender.** Traces are encoded with msgpack and uploaded asynchronously
so PHP request threads never block. The default sender is version-gated: the
sidecar (below) on PHP 8.3+/Windows, the in-process `tracer/coms.c` sender on
PHP 7.0–8.2 (`DD_SIDECAR_TRACE_SENDER_DEFAULT`); either is overridable. See
[tracer.md](tracer.md) and [../../architecture.md](../../architecture.md) for
the background-sender design.

**Sidecar.** A Rust background service (`libdatadog/datadog-sidecar*`, driven
from `ext/sidecar.{c,h}`) that offloads I/O off request threads: telemetry,
trace upload, crashtracking, DogStatsD, remote config, live debugger, and
appsec data. PHP ↔ sidecar over IPC (`ddog_SidecarTransport`). It survives
request crashes and is shared across language tracers. See
[sidecar.md](sidecar.md).

- `DD_TRACE_SIDECAR_CONNECTION_MODE` = `auto` (default) | `subprocess` |
`thread`. `auto` tries subprocess, falls back to thread.
- **Thread mode is not `pcntl_fork()`-safe** — apps that fork must use
subprocess mode. There is no `docs/SIDECAR_CONNECTION_MODES.md`; the modes
are documented in comments in `ext/sidecar.c`.

**Rust integration.** `libdatadog/` compiles into the extension;
`compile_rust.sh` (invoked from the Makefile) drives it. Minimize FFI surface;
headers are generated with cbindgen (see [components.md](components.md)).
Toolchain is pinned — see `Cargo.toml` (`rust-version`) and
`profiling/rust-toolchain.toml`, not a hardcoded version.

## Configuration & INI

- Runtime config: `DD_*` env vars and `datadog.*` INI keys, in two x-macro
tables — `ext/configuration.h` (shared/infra) and `tracer/configuration.h`
(tracer-specific, the majority of keys).
- System INI is installed as `.../conf.d/98-ddtrace.ini`.
- Inspect: `php --ri ddtrace`, or `php -i | grep -E 'datadog\.|ddtrace\.'`.

## Coding conventions

- **C/C++:** follow existing patterns; gate version differences on
`PHP_VERSION_ID`; keep `components/` free of the Zend API; treat the trace
sender / sidecar paths as thread-safe.
- **PHP:** PSR-2. `composer lint`, `composer fix-lint`. Userland in `src/`.
- **Rust:** standard conventions; keep the FFI boundary small.

## Pointers (don't duplicate these here)

- Operating rules: [../general.md](../general.md)
- Building any artifact locally:
[../ci/building-locally.md](../ci/building-locally.md)
- Reproducing CI jobs locally: [../ci/index.md](../ci/index.md)
- Debugging (gdb, appsec integration, system tests):
[../debugging/index.md](../debugging/index.md)
- Component design + background sender + PHP-version code:
[../../architecture.md](../../architecture.md)
- Contributor setup / linting / local testing:
[../../CONTRIBUTING.md](../../CONTRIBUTING.md)
- Version is in `VERSION`; supported framework versions in
`integration_versions.md`; libdatadog updates in `LIBDATADOG.md`.
48 changes: 48 additions & 0 deletions .claude/project/profiling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# profiling/ — Rust profiler extension

## What it is

A separate Rust `cdylib` extension for continuous CPU/wall-time profiling,
heap allocation, exception, and I/O profiling. Uploads pprof directly to the
agent.

## Key files & dirs

- `profiling/Cargo.toml` — `cdylib`; depends on `libdd-profiling`/`alloc`/
`common` from libdatadog.
- `profiling/rust-toolchain.toml` — pins Rust (distinct from the workspace
toolchain).
- `profiling/src/lib.rs` — module entry: `minit`/`rinit`/`prshutdown`, Zend
interrupt registration.
- `profiling/src/profiling/` — `mod.rs` (`Profiler` + `SampleValues`),
`interrupts.rs`, `backtrace.rs`, `stack_walking.rs`, `uploader.rs`,
`thread_utils.rs`.
- `profiling/src/allocation/` — `allocation_ge84.rs` (PHP 8.4+),
`allocation_le83.rs` (≤8.3).
- `profiling/src/config.rs`, `profiling/src/capi.rs`.
- `profiling/build.rs` — bindgen + `php-config` feature detection.
- `profiling/src/php_ffi.{c,h}`.

## How it fits

`minit` registers a hybrid module + zend_extension; `rinit` starts a
per-request `Profiler` sampling on VM interrupt (~10ms) and hooks
`zend_execute_internal`. Samples wall/CPU/alloc/heap/exception; uploads
pprof via a background thread; `prshutdown` flushes.

Builds independently from the tracer; depends on libdatadog for pprof. The
main tracer looks up `ddog_php_prof_interrupt_function` by symbol to call on
interrupt (see [tracer.md](tracer.md)). Not sidecar-dependent — it uploads
directly (contrast with [sidecar.md](sidecar.md)). `build.rs` reads
`../VERSION`.

## Gotchas

- Pinned `rust-toolchain.toml`, not the workspace default.
- `CARGO_TARGET_DIR` must be set (the Makefile uses `tmp/build_profiler`).
- `cdylib` is release-only — phpt tests fail on debug builds.
- Allocation hook differs: PHP 8.4+ vs ≤8.3 use different modules.
- `io_profiling` is Linux/macOS only.
- `trigger_time_sample` is a debug-only build feature.
- For build/test detail see
[../ci/building-locally.md](../ci/building-locally.md).
Loading
Loading