From 59797a24faf8be9344b2696961b29319f7fd447e Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 11 Aug 2026 08:01:31 +0000 Subject: [PATCH] docs: point the self-debugging research at the shipped ZDebug package The feasibility study still spoke of the debugger as a package that was expected to exist, and its roadmap listed work that has since landed there. - name ZDebug as the implementation, from the intro, the README's debugging section and the roadmap - mark the memoized per-op_array decision as shipped (ZDebug's OpArrayGate), leaving the compiler-option gating and the NOP strip-back as sketches - narrow the open debugger-side list to the async break command, the EXT_STMT-vs-ticks benchmark and the generator/fiber stepping experiment - add the zend_ast_process per-file EXT_STMT hook to the z-engine follow-ups Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0153cGVE6d7kFaNcyiyY4G9q --- README.md | 3 ++- docs/self-debugging.md | 31 +++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b246ea64..13a25d7f 100644 --- a/README.md +++ b/README.md @@ -244,7 +244,8 @@ Engine error and VM interrupt hooks (`Core::setErrorCallbackHandler()`, `Core::setInterruptHandler()` + `Core::$executor->requestInterrupt()`) round out the breakpoint/pause primitives. See **[docs/self-debugging.md](docs/self-debugging.md)** for the full feasibility research: what an Xdebug-equivalent can and cannot do from -pure PHP, and why. +pure PHP, and why — and **[ZDebug](https://github.com/lisachenko/zdebug)** for the +debugger built on it: a DBGp step debugger your IDE attaches to, with no C extension. ### Extensions written in PHP diff --git a/docs/self-debugging.md b/docs/self-debugging.md index 9bebbcf2..d3600724 100644 --- a/docs/self-debugging.md +++ b/docs/self-debugging.md @@ -8,9 +8,9 @@ first-chance exception breakpoints are partial. This document maps every Xdebug capability to the z-engine primitive that carries it, records what was verified on a live PHP 8.4 build (the statement hook, named frame locals, the error and interrupt hooks) and what is closed off by the engine itself (the observer API, the -exception-throw hook), and sketches the wire protocol story. The debugger itself is -expected to live in a separate package: z-engine's job, covered here, is the core -primitives. +exception-throw hook), and sketches the wire protocol story. The debugger itself lives +in a separate package — [ZDebug](https://github.com/lisachenko/zdebug), which implements +this study; z-engine's job, covered here, is the core primitives. Environment ground rules apply as everywhere in z-engine: exact supported PHP minor, `ffi.enable=1`, **JIT off** (the JIT rewrites the executor internals these hooks plug @@ -91,8 +91,9 @@ Three properties of user opcode handlers shape the whole design (toggle the compiler option from a `zend_ast_process` hook based on `Compiler::getFileName()`), memoize an include/exclude decision per op_array address instead of the backtrace filter, and strip `EXT_STMT` oplines back to - `NOP` while no breakpoint targets their file. All three are design sketches for - the debugger package, not shipped features. + `NOP` while no breakpoint targets their file. ZDebug ships the middle one (its + `OpArrayGate` decides each op_array once, keyed by entry address); the compiler-option + gating and the `NOP` strip-back remain design sketches. 3. **Reentrancy.** Opcodes executed inside `ZEngine\*` classes bypass user handlers by design, but that exclusion is class-prefix-based: top-level code, plain functions and closures of the debugger itself are *not* excluded. A debugger must @@ -289,10 +290,16 @@ Shipped with this research: `getVariableNames()` + `getLocalVariables()`/ `Core::setInterruptHandler()` + `Executor::requestInterrupt()`, the exported `zend_throw_exception_hook` symbol and its pinning test. -For the debugger package (separate repository): the breakpoint table + suspend loop + -DBGp transport over these primitives, per-file instrumentation gating, the -EXT_STMT-vs-ticks benchmark, and the generator/fiber stepping experiment. Candidate -z-engine follow-ups if that work needs them: exporting `zend_execute_ex` (call-depth -events without walking `getPrevious()`), `zend_vm_set_opcode_handler` (handler-level -retro-instrumentation), and a leaner statement-hook fast path that replaces the -per-hit backtrace filter with a memoized per-op_array decision. +The debugger package now exists: **[ZDebug](https://github.com/lisachenko/zdebug)** +implements this study — the breakpoint table, the suspend loop and the DBGp transport +over these primitives, the memoized per-op_array instrumentation decision, line / +conditional / call / return and first-chance exception breakpoints, stepping, stack and +variable inspection with write-back, `eval`, and return-value debugging. Still open +there: the async `break` command over `Core::setInterruptHandler()`, the +EXT_STMT-vs-ticks benchmark, and the generator/fiber stepping experiment. + +Candidate z-engine follow-ups if that work needs them: exporting `zend_execute_ex` +(call-depth events without walking `getPrevious()`), `zend_vm_set_opcode_handler` +(handler-level retro-instrumentation), a `zend_ast_process` hook for per-file +`EXT_STMT` emission, and a leaner statement-hook fast path that replaces the per-hit +backtrace filter with a memoized per-op_array decision.