feat(rsp): QTDP tracepoint vocabulary (#26 phase-2)#16
Merged
Conversation
Phase-2 of the v1.6 tracepoints chain wires the wire vocabulary for pushing tracepoints into the inferior via gdb-remote's tracepoint family (QTDP / QTStart / QTStop / QTFrame / qTStatus / qTBuffer / QTinit). Phase-1 (#26) shipped daemon-side tracepoint evaluation; this PR ships the packet builders + parser + carrier struct so a later phase-2.5 PR can route RspChannel-backed tracepoints through the in-target agent without daemon round-trips on every hit. Scoped to vocabulary only — dispatcher integration is intentionally phase-2.5. The vocabulary is reusable on its own (a custom-agent bpf/perf path could speak QTDP-like packets), and integration is large enough to fight TDD if landed here. docs/34 explains the phase-2.5 wiring + capability negotiation + failure fallbacks. Builders pin step=0 (no single-step collection; phase-3 territory) and treat pass_count==0 as unlimited (the orchestrator's rate-limit already covers that case daemon-side). QTDP_condition uses the spec's continuation `-T<id>` form so condition bytecode lands in a separate packet from the primary define. 7 new TEST_CASEs, 39 assertions. Builders get exact-wire-bytes goldens against the spec; parse_tstatus_reply covers T0/T1 + trailing kv pairs + malformed-shape rejection. ctest 70/70 green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The QTDP continuation packet (`build_QTDP_condition`) emitted
`QTDP:-T<id>:...` — a leading `-T`. Per the gdb-remote spec
(remote.c, `remote_add_target_side_condition` formats it as
`"QTDP:-%x:%s:%s"`) the continuation drops the `T`; only the PRIMARY
define packet (`QTDP:T<id>:...`) carries it. A real lldb-server or
gdbserver would silently NAK the malformed packet, so this would
have failed the first time we wired a real condition over RSP.
The existing test golden pinned the buggy value, so the unit test
passed against the wrong spec — a textbook silent-corruption failure
mode for a debugger. Updated the golden to the spec-compliant form
(`QTDP:-1:401000:X1,27`).
Three drive-by hardenings while touching the file:
* `build_QTDP_condition` now throws `backend::Error` on empty
bytecode. `X0,` is undefined by the agent-expression spec and
some servers NAK it; reject at the source so the caller gets a
typed error instead of a transport-level mystery.
* `parse_tstatus_reply` caps kv-pair allocation at 64. The parser
runs against untrusted remote-debug-server bytes; unbounded
allocation on a hostile/buggy server was a real attack surface.
* `append_hex_bytes` no longer warns under -Wsign-conversion. The
range-for over `std::string_view` was implicit-narrowing
`char → unsigned char`; switched to indexed iteration with an
explicit cast.
Tests:
* Updated QTDP continuation golden to the spec-correct bytes.
* Added `QTDP condition rejects empty bytecode` (throws).
* Added `parse_tstatus_reply caps kv-pair allocation` (64 OK, 65 nullopt).
* Net +2 TEST_CASE blocks in test_rsp_packets.cpp.
70/70 ctest green, warning-clean build.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b408a12 to
43734ca
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
QTinit,QTDPdefine + condition,QTStart/QTStop,qTStatus,qTBuffer,QTFrame) +parse_tstatus_reply+TracepointWirecarrier tosrc/transport/rsp/packets.{h,cpp}.docs/34-tracepoints-in-target.mddocuments wire shapes, the phase-2.5 dispatcher integration plan, capability negotiation (qSupported flags + empty-reply fallback), and the failure-mode matrix.Vocabulary-only PR — dispatcher integration is intentionally phase-2.5 (the integration adds capability detection, per-channel state, and a fallback path large enough to fight TDD if landed alongside the vocabulary).
Why phase-2
Phase-1 (#26) shipped daemon-side tracepoint evaluation: every hit fires the LLDB breakpoint callback, evaluates the predicate daemon-side, decides whether to log. That's the high-frequency path tracepoints exist to optimise, so phase-2 pushes the bytecode into the inferior's agent (lldb-server / gdbserver) via gdb-remote's QTDP family. The agent runs the predicate without round-tripping to the daemon.
What's deferred to phase-2.5
tracepoint.createemitsQTinit+QTDP:T...+QTDP:-T...+QTStartagainst RspChannel-backed targets, with daemon-side fallback onE NNor empty-reply.has_feature("tracepoints+")helper + per-channel capability cache onRspChannel.lldb-server gdbserver(outlined in §5 of the design note).Test plan
build/bin/ldb_unit_tests "[qtdp]"— 7 cases, 39 assertionsctest --test-dir build --output-on-failure— 70/70 greenappend_hex_bytesis on master; not introduced here)target.connect_remote_rsp→tracepoint.create→qTStatus→tracepoint.delete🤖 Generated with Claude Code