textual-debugger 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/PKG-INFO +126 -9
- {textual_debugger-0.2.0/src/tdb → textual_debugger-0.2.2}/README.md +124 -7
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/pyproject.toml +2 -2
- {textual_debugger-0.2.0 → textual_debugger-0.2.2/src/tdb}/README.md +124 -7
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/__init__.py +1 -1
- textual_debugger-0.2.2/src/tdb/adapters/perl/Devel/TdbRemote.pm +93 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/__main__.py +23 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/helpers.pl +384 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/protocol.py +110 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/refs.py +34 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/server.py +593 -0
- textual_debugger-0.2.2/src/tdb/adapters/perl/session.py +247 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app.py +168 -14
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/cli.py +157 -57
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/dap/messages.py +20 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/dap/types.py +3 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/languages/base.py +5 -0
- textual_debugger-0.2.2/src/tdb/languages/perl.py +98 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/languages/registry.py +14 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/mcp/session.py +3 -6
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/persist.py +12 -10
- textual_debugger-0.2.2/src/tdb/replay.py +202 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/server/handlers.py +14 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/server/runner.py +53 -18
- textual_debugger-0.2.2/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/controller.py +4 -1
- textual_debugger-0.2.2/src/tdb/session/recorder.py +106 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/state.py +15 -0
- textual_debugger-0.2.2/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/code_view.py +88 -51
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/PKG-INFO +126 -9
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/SOURCES.txt +12 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/requires.txt +1 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/LICENSE +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/setup.cfg +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/_timeouts.py +0 -0
- {textual_debugger-0.2.0/src/tdb/dap → textual_debugger-0.2.2/src/tdb/adapters}/__init__.py +0 -0
- {textual_debugger-0.2.0/src/tdb/server → textual_debugger-0.2.2/src/tdb/adapters/perl}/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_handlers/dap_events.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_handlers/inspection.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_handlers/routing.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_handlers/ui_panels.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/breakpoint_hook.py +0 -0
- {textual_debugger-0.2.0/src/tdb/session → textual_debugger-0.2.2/src/tdb/dap}/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/dap/client.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/languages/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/languages/cpp.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/languages/python.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/mcp/server.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.2.0/src/tdb/widgets → textual_debugger-0.2.2/src/tdb/server}/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/server/app.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/server/event_handler.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/server/rpc_types.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/child_processes.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/inspect_service.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/statement_stepper.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/session/textual_handler.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/source_analysis.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/_inspection_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/async_tasks_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/evaluate_console.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/modals.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/stack_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/threads_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.2}/src/textual_debugger.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: textual-debugger
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A TUI Python debugger based on textual and debugpy
|
|
5
5
|
Author-email: Al Danial <al.danial@gmail.com>
|
|
6
6
|
License: textual-debugger is licensed to you under the MIT/X Consortium license:
|
|
@@ -51,7 +51,7 @@ Requires-Dist: debugpy>=1.8.0
|
|
|
51
51
|
Requires-Dist: pygments>=2.17.0
|
|
52
52
|
Requires-Dist: fastapi>=0.115.0
|
|
53
53
|
Requires-Dist: uvicorn>=0.30.0
|
|
54
|
-
Requires-Dist: mcp
|
|
54
|
+
Requires-Dist: mcp<2.0.0,>=1.28.0
|
|
55
55
|
Provides-Extra: dev
|
|
56
56
|
Requires-Dist: pytest; extra == "dev"
|
|
57
57
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -194,6 +194,10 @@ tdb --lang python ./mytool
|
|
|
194
194
|
# program runs to the first breakpoint)
|
|
195
195
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
196
196
|
|
|
197
|
+
# run straight to line 20 without saving the breakpoint for future
|
|
198
|
+
# sessions (-t is -k minus the persistence)
|
|
199
|
+
tdb -t 20 my_program.py
|
|
200
|
+
|
|
197
201
|
# use a specific virtualenv
|
|
198
202
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
199
203
|
|
|
@@ -239,14 +243,15 @@ languages are supported out of the box:
|
|
|
239
243
|
|----------|------------|------------------------|---------------|
|
|
240
244
|
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
241
245
|
| C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
|
|
246
|
+
| Perl | perl-tdb (bundled) | needs perl ≥ 5.18 on PATH (or `{"adapters": {"perl": ...}}`) | core debugging + remote attach |
|
|
242
247
|
|
|
243
248
|
### Language detection and selection
|
|
244
249
|
|
|
245
250
|
The language is auto-detected from the debug target:
|
|
246
251
|
|
|
247
|
-
1. File extension: `.py` → Python.
|
|
252
|
+
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl.
|
|
248
253
|
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
249
|
-
3. A `#!...python` shebang → Python.
|
|
254
|
+
3. A `#!...python` or `#!...perl` shebang → Python / Perl respectively.
|
|
250
255
|
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
251
256
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
252
257
|
5. Anything else produces an error naming the `--lang` override.
|
|
@@ -282,9 +287,11 @@ Python-specific features are hidden or return a clear "not supported for this
|
|
|
282
287
|
language" message when debugging other languages: statement-granularity
|
|
283
288
|
stepping (non-Python languages always step per line), the async task /
|
|
284
289
|
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
290
|
+
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
291
|
+
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
292
|
+
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
293
|
+
[Perl](#perl) — `Devel::TdbRemote` in place of `debugpy.listen()`), but not
|
|
294
|
+
for C/C++. `--terminal` is
|
|
288
295
|
currently ignored for non-Python targets.
|
|
289
296
|
|
|
290
297
|
### C/C++ tips
|
|
@@ -303,6 +310,72 @@ currently ignored for non-Python targets.
|
|
|
303
310
|
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
304
311
|
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
305
312
|
|
|
313
|
+
### Perl
|
|
314
|
+
|
|
315
|
+
`tdb` bundles its own Perl adapter (`perl-tdb`) — no separate adapter install
|
|
316
|
+
needed, just a `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
|
|
317
|
+
hood, so it works with any Perl already on the system.
|
|
318
|
+
|
|
319
|
+
**Launching a script:**
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
tdb script.pl
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Remote attach:** useful when the Perl process is already running (a long-
|
|
326
|
+
lived service, a process started by something other than `tdb`) or lives on
|
|
327
|
+
another host/container. Add three lines to the target program, with the
|
|
328
|
+
`use` line first so the debugger is armed before any of your code compiles:
|
|
329
|
+
|
|
330
|
+
```perl
|
|
331
|
+
use Devel::TdbRemote; # FIRST line of your program
|
|
332
|
+
...
|
|
333
|
+
Devel::TdbRemote::listen(5678); # non-blocking
|
|
334
|
+
Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Then attach from `tdb`, forcing the language since there's no local `program`
|
|
338
|
+
argument for `tdb` to detect it from:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
tdb --lang perl -r host:5678
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
**Arming caveat:** only code *compiled after* the debugger is armed can be
|
|
345
|
+
stepped into or breakpointed. That's why `use Devel::TdbRemote;` must be the
|
|
346
|
+
first line of the program. If you can't edit the first line (e.g. a wrapper
|
|
347
|
+
script controls startup), arm it before Perl even parses your file instead:
|
|
348
|
+
`perl -d:TdbRemote prog.pl`, or set `PERL5OPT=-d:TdbRemote` in the
|
|
349
|
+
environment that launches the debuggee.
|
|
350
|
+
|
|
351
|
+
**Copying the adapter to a remote host:** `Devel::TdbRemote` and its helper
|
|
352
|
+
script are plain files, not a CPAN install — copy both onto the remote
|
|
353
|
+
machine and point `PERL5LIB` at the directory that contains them:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
|
|
357
|
+
scp -r Devel/TdbRemote.pm helpers.pl remote-host:/opt/tdb-perl/
|
|
358
|
+
# On the remote host:
|
|
359
|
+
export PERL5LIB=/opt/tdb-perl:$PERL5LIB
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
(`Devel/TdbRemote.pm` locates `helpers.pl` next to itself at runtime, so keep
|
|
363
|
+
the two files in the same relative layout shown above — `helpers.pl` is a
|
|
364
|
+
sibling of the `Devel/` directory, not inside it.)
|
|
365
|
+
|
|
366
|
+
**PadWalker (optional but recommended):** inspecting lexical (`my`)
|
|
367
|
+
variables in the *current* frame always works. Lexicals in outer/caller
|
|
368
|
+
frames need the `PadWalker` module installed on the debuggee's Perl; without
|
|
369
|
+
it, tdb falls back to a read-only pad walk that can't reach fully into
|
|
370
|
+
enclosing scopes, and outer-frame variable listings degrade accordingly.
|
|
371
|
+
Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
|
|
372
|
+
|
|
373
|
+
**Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
|
|
374
|
+
script.pl`) support pausing a running program at any time. Remote-attach
|
|
375
|
+
sessions don't — debugpy-style asynchronous pause needs a control channel
|
|
376
|
+
`Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
|
|
377
|
+
clear "not available" error instead of hanging.
|
|
378
|
+
|
|
306
379
|
## Layout
|
|
307
380
|
|
|
308
381
|
```
|
|
@@ -893,6 +966,40 @@ curl -N http://127.0.0.1:8150/events
|
|
|
893
966
|
Events: `initialized`, `stopped`, `continued`, `terminated`, `exited`, `output`.
|
|
894
967
|
Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
895
968
|
|
|
969
|
+
## Recording and replaying sessions
|
|
970
|
+
|
|
971
|
+
`tdb --record session.jsonl prog.py` runs a normal TUI session and captures
|
|
972
|
+
your debugging actions — breakpoints (including `-k`/`-t` and persisted
|
|
973
|
+
ones), stepping, continue/pause, Evaluate-console entries, stack-frame
|
|
974
|
+
navigation, variable expansion, restart, quit — to `session.jsonl` as
|
|
975
|
+
JSON-RPC commands. Works with launch mode (any language) and `-r`
|
|
976
|
+
remote attach.
|
|
977
|
+
|
|
978
|
+
Replay it two ways:
|
|
979
|
+
|
|
980
|
+
- `tdb --replay session.jsonl` — one command: launches the recorded
|
|
981
|
+
program headless, feeds every recorded command through the same RPC
|
|
982
|
+
dispatch `tdb --server` uses, and prints a transcript (recorded time,
|
|
983
|
+
command, verbatim result, interleaved program output). Exit code 0 iff
|
|
984
|
+
every command succeeded. Add `--timing` to reproduce the original
|
|
985
|
+
pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
|
|
986
|
+
- Against a live server: start `tdb --server prog.py`, then feed line 2
|
|
987
|
+
onward of the file to `POST /rpc` — each line is already a valid
|
|
988
|
+
request body:
|
|
989
|
+
|
|
990
|
+
tail -n +2 session.jsonl | while read line; do
|
|
991
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
992
|
+
-d "$line" http://127.0.0.1:8150/rpc
|
|
993
|
+
done
|
|
994
|
+
|
|
995
|
+
(On Windows, an equivalent loop in Python: read the file, skip the
|
|
996
|
+
first line, `requests.post` each remaining line.)
|
|
997
|
+
|
|
998
|
+
Not captured: pure viewing (scrolling, search, modals, thread/task
|
|
999
|
+
lists), breakpoint enable/disable toggles, variable expansions when the
|
|
1000
|
+
adapter reports no `evaluateName` (currently the Perl adapter), and
|
|
1001
|
+
File > Open program switches.
|
|
1002
|
+
|
|
896
1003
|
## MCP Integration
|
|
897
1004
|
|
|
898
1005
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
@@ -1002,11 +1109,12 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
1002
1109
|
| `--local-root PATH` | Local directory containing a copy of remote code (repeat to mirror multiple trees). Pair with `--remote-root`; counts must match. Required when `-k` sets a breakpoint against a remote debuggee whose code lives at a different path. |
|
|
1003
1110
|
| `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
|
|
1004
1111
|
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
1112
|
+
| `-t`, `--to-line FILE:LINE|LINE` | Like `-k`, but the breakpoint is not saved to the breakpoints file — it just takes you to that spot in the code for this session (may be repeated). |
|
|
1005
1113
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
1006
1114
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
1007
1115
|
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
1008
1116
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
1009
|
-
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
1117
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`, `perl`); default: auto-detect from the target |
|
|
1010
1118
|
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
1011
1119
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
1012
1120
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
@@ -1035,8 +1143,17 @@ executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
|
1035
1143
|
`default_adapters` picks a language's default adapter
|
|
1036
1144
|
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
1037
1145
|
|
|
1146
|
+
**Perl is a special case:** `perl-tdb` is tdb's own bundled adapter (always
|
|
1147
|
+
found — it's Python code, not an external executable), so
|
|
1148
|
+
`adapters.perl` doesn't select an adapter binary. Instead it names the
|
|
1149
|
+
*Perl interpreter* tdb should spawn to run the debuggee:
|
|
1150
|
+
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1151
|
+
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1152
|
+
|
|
1038
1153
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
1039
|
-
directory. Each project's breakpoints are independent.
|
|
1154
|
+
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1155
|
+
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
1156
|
+
the session but are never saved.
|
|
1040
1157
|
|
|
1041
1158
|
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
1042
1159
|
into) handle multi-line source statements:
|
|
@@ -128,6 +128,10 @@ tdb --lang python ./mytool
|
|
|
128
128
|
# program runs to the first breakpoint)
|
|
129
129
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
130
130
|
|
|
131
|
+
# run straight to line 20 without saving the breakpoint for future
|
|
132
|
+
# sessions (-t is -k minus the persistence)
|
|
133
|
+
tdb -t 20 my_program.py
|
|
134
|
+
|
|
131
135
|
# use a specific virtualenv
|
|
132
136
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
133
137
|
|
|
@@ -173,14 +177,15 @@ languages are supported out of the box:
|
|
|
173
177
|
|----------|------------|------------------------|---------------|
|
|
174
178
|
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
175
179
|
| C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
|
|
180
|
+
| Perl | perl-tdb (bundled) | needs perl ≥ 5.18 on PATH (or `{"adapters": {"perl": ...}}`) | core debugging + remote attach |
|
|
176
181
|
|
|
177
182
|
### Language detection and selection
|
|
178
183
|
|
|
179
184
|
The language is auto-detected from the debug target:
|
|
180
185
|
|
|
181
|
-
1. File extension: `.py` → Python.
|
|
186
|
+
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl.
|
|
182
187
|
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
183
|
-
3. A `#!...python` shebang → Python.
|
|
188
|
+
3. A `#!...python` or `#!...perl` shebang → Python / Perl respectively.
|
|
184
189
|
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
185
190
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
186
191
|
5. Anything else produces an error naming the `--lang` override.
|
|
@@ -216,9 +221,11 @@ Python-specific features are hidden or return a clear "not supported for this
|
|
|
216
221
|
language" message when debugging other languages: statement-granularity
|
|
217
222
|
stepping (non-Python languages always step per line), the async task /
|
|
218
223
|
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
225
|
+
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
226
|
+
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
227
|
+
[Perl](#perl) — `Devel::TdbRemote` in place of `debugpy.listen()`), but not
|
|
228
|
+
for C/C++. `--terminal` is
|
|
222
229
|
currently ignored for non-Python targets.
|
|
223
230
|
|
|
224
231
|
### C/C++ tips
|
|
@@ -237,6 +244,72 @@ currently ignored for non-Python targets.
|
|
|
237
244
|
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
238
245
|
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
239
246
|
|
|
247
|
+
### Perl
|
|
248
|
+
|
|
249
|
+
`tdb` bundles its own Perl adapter (`perl-tdb`) — no separate adapter install
|
|
250
|
+
needed, just a `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
|
|
251
|
+
hood, so it works with any Perl already on the system.
|
|
252
|
+
|
|
253
|
+
**Launching a script:**
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
tdb script.pl
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Remote attach:** useful when the Perl process is already running (a long-
|
|
260
|
+
lived service, a process started by something other than `tdb`) or lives on
|
|
261
|
+
another host/container. Add three lines to the target program, with the
|
|
262
|
+
`use` line first so the debugger is armed before any of your code compiles:
|
|
263
|
+
|
|
264
|
+
```perl
|
|
265
|
+
use Devel::TdbRemote; # FIRST line of your program
|
|
266
|
+
...
|
|
267
|
+
Devel::TdbRemote::listen(5678); # non-blocking
|
|
268
|
+
Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Then attach from `tdb`, forcing the language since there's no local `program`
|
|
272
|
+
argument for `tdb` to detect it from:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
tdb --lang perl -r host:5678
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Arming caveat:** only code *compiled after* the debugger is armed can be
|
|
279
|
+
stepped into or breakpointed. That's why `use Devel::TdbRemote;` must be the
|
|
280
|
+
first line of the program. If you can't edit the first line (e.g. a wrapper
|
|
281
|
+
script controls startup), arm it before Perl even parses your file instead:
|
|
282
|
+
`perl -d:TdbRemote prog.pl`, or set `PERL5OPT=-d:TdbRemote` in the
|
|
283
|
+
environment that launches the debuggee.
|
|
284
|
+
|
|
285
|
+
**Copying the adapter to a remote host:** `Devel::TdbRemote` and its helper
|
|
286
|
+
script are plain files, not a CPAN install — copy both onto the remote
|
|
287
|
+
machine and point `PERL5LIB` at the directory that contains them:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
|
|
291
|
+
scp -r Devel/TdbRemote.pm helpers.pl remote-host:/opt/tdb-perl/
|
|
292
|
+
# On the remote host:
|
|
293
|
+
export PERL5LIB=/opt/tdb-perl:$PERL5LIB
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
(`Devel/TdbRemote.pm` locates `helpers.pl` next to itself at runtime, so keep
|
|
297
|
+
the two files in the same relative layout shown above — `helpers.pl` is a
|
|
298
|
+
sibling of the `Devel/` directory, not inside it.)
|
|
299
|
+
|
|
300
|
+
**PadWalker (optional but recommended):** inspecting lexical (`my`)
|
|
301
|
+
variables in the *current* frame always works. Lexicals in outer/caller
|
|
302
|
+
frames need the `PadWalker` module installed on the debuggee's Perl; without
|
|
303
|
+
it, tdb falls back to a read-only pad walk that can't reach fully into
|
|
304
|
+
enclosing scopes, and outer-frame variable listings degrade accordingly.
|
|
305
|
+
Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
|
|
306
|
+
|
|
307
|
+
**Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
|
|
308
|
+
script.pl`) support pausing a running program at any time. Remote-attach
|
|
309
|
+
sessions don't — debugpy-style asynchronous pause needs a control channel
|
|
310
|
+
`Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
|
|
311
|
+
clear "not available" error instead of hanging.
|
|
312
|
+
|
|
240
313
|
## Layout
|
|
241
314
|
|
|
242
315
|
```
|
|
@@ -827,6 +900,40 @@ curl -N http://127.0.0.1:8150/events
|
|
|
827
900
|
Events: `initialized`, `stopped`, `continued`, `terminated`, `exited`, `output`.
|
|
828
901
|
Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
829
902
|
|
|
903
|
+
## Recording and replaying sessions
|
|
904
|
+
|
|
905
|
+
`tdb --record session.jsonl prog.py` runs a normal TUI session and captures
|
|
906
|
+
your debugging actions — breakpoints (including `-k`/`-t` and persisted
|
|
907
|
+
ones), stepping, continue/pause, Evaluate-console entries, stack-frame
|
|
908
|
+
navigation, variable expansion, restart, quit — to `session.jsonl` as
|
|
909
|
+
JSON-RPC commands. Works with launch mode (any language) and `-r`
|
|
910
|
+
remote attach.
|
|
911
|
+
|
|
912
|
+
Replay it two ways:
|
|
913
|
+
|
|
914
|
+
- `tdb --replay session.jsonl` — one command: launches the recorded
|
|
915
|
+
program headless, feeds every recorded command through the same RPC
|
|
916
|
+
dispatch `tdb --server` uses, and prints a transcript (recorded time,
|
|
917
|
+
command, verbatim result, interleaved program output). Exit code 0 iff
|
|
918
|
+
every command succeeded. Add `--timing` to reproduce the original
|
|
919
|
+
pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
|
|
920
|
+
- Against a live server: start `tdb --server prog.py`, then feed line 2
|
|
921
|
+
onward of the file to `POST /rpc` — each line is already a valid
|
|
922
|
+
request body:
|
|
923
|
+
|
|
924
|
+
tail -n +2 session.jsonl | while read line; do
|
|
925
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
926
|
+
-d "$line" http://127.0.0.1:8150/rpc
|
|
927
|
+
done
|
|
928
|
+
|
|
929
|
+
(On Windows, an equivalent loop in Python: read the file, skip the
|
|
930
|
+
first line, `requests.post` each remaining line.)
|
|
931
|
+
|
|
932
|
+
Not captured: pure viewing (scrolling, search, modals, thread/task
|
|
933
|
+
lists), breakpoint enable/disable toggles, variable expansions when the
|
|
934
|
+
adapter reports no `evaluateName` (currently the Perl adapter), and
|
|
935
|
+
File > Open program switches.
|
|
936
|
+
|
|
830
937
|
## MCP Integration
|
|
831
938
|
|
|
832
939
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
@@ -936,11 +1043,12 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
936
1043
|
| `--local-root PATH` | Local directory containing a copy of remote code (repeat to mirror multiple trees). Pair with `--remote-root`; counts must match. Required when `-k` sets a breakpoint against a remote debuggee whose code lives at a different path. |
|
|
937
1044
|
| `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
|
|
938
1045
|
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
1046
|
+
| `-t`, `--to-line FILE:LINE|LINE` | Like `-k`, but the breakpoint is not saved to the breakpoints file — it just takes you to that spot in the code for this session (may be repeated). |
|
|
939
1047
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
940
1048
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
941
1049
|
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
942
1050
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
943
|
-
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
1051
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`, `perl`); default: auto-detect from the target |
|
|
944
1052
|
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
945
1053
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
946
1054
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
@@ -969,8 +1077,17 @@ executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
|
969
1077
|
`default_adapters` picks a language's default adapter
|
|
970
1078
|
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
971
1079
|
|
|
1080
|
+
**Perl is a special case:** `perl-tdb` is tdb's own bundled adapter (always
|
|
1081
|
+
found — it's Python code, not an external executable), so
|
|
1082
|
+
`adapters.perl` doesn't select an adapter binary. Instead it names the
|
|
1083
|
+
*Perl interpreter* tdb should spawn to run the debuggee:
|
|
1084
|
+
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1085
|
+
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1086
|
+
|
|
972
1087
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
973
|
-
directory. Each project's breakpoints are independent.
|
|
1088
|
+
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1089
|
+
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
1090
|
+
the session but are never saved.
|
|
974
1091
|
|
|
975
1092
|
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
976
1093
|
into) handle multi-line source statements:
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"pygments>=2.17.0",
|
|
26
26
|
"fastapi>=0.115.0",
|
|
27
27
|
"uvicorn>=0.30.0",
|
|
28
|
-
"mcp>=1.28.0",
|
|
28
|
+
"mcp>=1.28.0,<2.0.0",
|
|
29
29
|
]
|
|
30
30
|
|
|
31
31
|
# extras needed to run the examples and tests
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
where = ["src"]
|
|
58
58
|
|
|
59
59
|
[tool.setuptools.package-data]
|
|
60
|
-
tdb = ["README.md"]
|
|
60
|
+
tdb = ["README.md", "adapters/perl/helpers.pl", "adapters/perl/Devel/TdbRemote.pm"]
|
|
61
61
|
|
|
62
62
|
[tool.pytest.ini_options]
|
|
63
63
|
testpaths = ["tests"]
|
|
@@ -128,6 +128,10 @@ tdb --lang python ./mytool
|
|
|
128
128
|
# program runs to the first breakpoint)
|
|
129
129
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
130
130
|
|
|
131
|
+
# run straight to line 20 without saving the breakpoint for future
|
|
132
|
+
# sessions (-t is -k minus the persistence)
|
|
133
|
+
tdb -t 20 my_program.py
|
|
134
|
+
|
|
131
135
|
# use a specific virtualenv
|
|
132
136
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
133
137
|
|
|
@@ -173,14 +177,15 @@ languages are supported out of the box:
|
|
|
173
177
|
|----------|------------|------------------------|---------------|
|
|
174
178
|
| Python | `debugpy` (default) | installed with `textual-debugger` | everything in this README |
|
|
175
179
|
| C / C++ (any native binary) | `gdb` (default), `lldb-dap` (alternate) | `gdb -i dap` requires GDB ≥ 14; `lldb-dap` ships with LLVM ≥ 17 (e.g. `apt install lldb`) | core debugging: breakpoints, stepping, stack, variables, evaluate console |
|
|
180
|
+
| Perl | perl-tdb (bundled) | needs perl ≥ 5.18 on PATH (or `{"adapters": {"perl": ...}}`) | core debugging + remote attach |
|
|
176
181
|
|
|
177
182
|
### Language detection and selection
|
|
178
183
|
|
|
179
184
|
The language is auto-detected from the debug target:
|
|
180
185
|
|
|
181
|
-
1. File extension: `.py` → Python.
|
|
186
|
+
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl.
|
|
182
187
|
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
183
|
-
3. A `#!...python` shebang → Python.
|
|
188
|
+
3. A `#!...python` or `#!...perl` shebang → Python / Perl respectively.
|
|
184
189
|
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
185
190
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
186
191
|
5. Anything else produces an error naming the `--lang` override.
|
|
@@ -216,9 +221,11 @@ Python-specific features are hidden or return a clear "not supported for this
|
|
|
216
221
|
language" message when debugging other languages: statement-granularity
|
|
217
222
|
stepping (non-Python languages always step per line), the async task /
|
|
218
223
|
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
224
|
+
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
225
|
+
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
226
|
+
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
227
|
+
[Perl](#perl) — `Devel::TdbRemote` in place of `debugpy.listen()`), but not
|
|
228
|
+
for C/C++. `--terminal` is
|
|
222
229
|
currently ignored for non-Python targets.
|
|
223
230
|
|
|
224
231
|
### C/C++ tips
|
|
@@ -237,6 +244,72 @@ currently ignored for non-Python targets.
|
|
|
237
244
|
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
238
245
|
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
239
246
|
|
|
247
|
+
### Perl
|
|
248
|
+
|
|
249
|
+
`tdb` bundles its own Perl adapter (`perl-tdb`) — no separate adapter install
|
|
250
|
+
needed, just a `perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
|
|
251
|
+
hood, so it works with any Perl already on the system.
|
|
252
|
+
|
|
253
|
+
**Launching a script:**
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
tdb script.pl
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Remote attach:** useful when the Perl process is already running (a long-
|
|
260
|
+
lived service, a process started by something other than `tdb`) or lives on
|
|
261
|
+
another host/container. Add three lines to the target program, with the
|
|
262
|
+
`use` line first so the debugger is armed before any of your code compiles:
|
|
263
|
+
|
|
264
|
+
```perl
|
|
265
|
+
use Devel::TdbRemote; # FIRST line of your program
|
|
266
|
+
...
|
|
267
|
+
Devel::TdbRemote::listen(5678); # non-blocking
|
|
268
|
+
Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Then attach from `tdb`, forcing the language since there's no local `program`
|
|
272
|
+
argument for `tdb` to detect it from:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
tdb --lang perl -r host:5678
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Arming caveat:** only code *compiled after* the debugger is armed can be
|
|
279
|
+
stepped into or breakpointed. That's why `use Devel::TdbRemote;` must be the
|
|
280
|
+
first line of the program. If you can't edit the first line (e.g. a wrapper
|
|
281
|
+
script controls startup), arm it before Perl even parses your file instead:
|
|
282
|
+
`perl -d:TdbRemote prog.pl`, or set `PERL5OPT=-d:TdbRemote` in the
|
|
283
|
+
environment that launches the debuggee.
|
|
284
|
+
|
|
285
|
+
**Copying the adapter to a remote host:** `Devel::TdbRemote` and its helper
|
|
286
|
+
script are plain files, not a CPAN install — copy both onto the remote
|
|
287
|
+
machine and point `PERL5LIB` at the directory that contains them:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
|
|
291
|
+
scp -r Devel/TdbRemote.pm helpers.pl remote-host:/opt/tdb-perl/
|
|
292
|
+
# On the remote host:
|
|
293
|
+
export PERL5LIB=/opt/tdb-perl:$PERL5LIB
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
(`Devel/TdbRemote.pm` locates `helpers.pl` next to itself at runtime, so keep
|
|
297
|
+
the two files in the same relative layout shown above — `helpers.pl` is a
|
|
298
|
+
sibling of the `Devel/` directory, not inside it.)
|
|
299
|
+
|
|
300
|
+
**PadWalker (optional but recommended):** inspecting lexical (`my`)
|
|
301
|
+
variables in the *current* frame always works. Lexicals in outer/caller
|
|
302
|
+
frames need the `PadWalker` module installed on the debuggee's Perl; without
|
|
303
|
+
it, tdb falls back to a read-only pad walk that can't reach fully into
|
|
304
|
+
enclosing scopes, and outer-frame variable listings degrade accordingly.
|
|
305
|
+
Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
|
|
306
|
+
|
|
307
|
+
**Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
|
|
308
|
+
script.pl`) support pausing a running program at any time. Remote-attach
|
|
309
|
+
sessions don't — debugpy-style asynchronous pause needs a control channel
|
|
310
|
+
`Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
|
|
311
|
+
clear "not available" error instead of hanging.
|
|
312
|
+
|
|
240
313
|
## Layout
|
|
241
314
|
|
|
242
315
|
```
|
|
@@ -827,6 +900,40 @@ curl -N http://127.0.0.1:8150/events
|
|
|
827
900
|
Events: `initialized`, `stopped`, `continued`, `terminated`, `exited`, `output`.
|
|
828
901
|
Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
829
902
|
|
|
903
|
+
## Recording and replaying sessions
|
|
904
|
+
|
|
905
|
+
`tdb --record session.jsonl prog.py` runs a normal TUI session and captures
|
|
906
|
+
your debugging actions — breakpoints (including `-k`/`-t` and persisted
|
|
907
|
+
ones), stepping, continue/pause, Evaluate-console entries, stack-frame
|
|
908
|
+
navigation, variable expansion, restart, quit — to `session.jsonl` as
|
|
909
|
+
JSON-RPC commands. Works with launch mode (any language) and `-r`
|
|
910
|
+
remote attach.
|
|
911
|
+
|
|
912
|
+
Replay it two ways:
|
|
913
|
+
|
|
914
|
+
- `tdb --replay session.jsonl` — one command: launches the recorded
|
|
915
|
+
program headless, feeds every recorded command through the same RPC
|
|
916
|
+
dispatch `tdb --server` uses, and prints a transcript (recorded time,
|
|
917
|
+
command, verbatim result, interleaved program output). Exit code 0 iff
|
|
918
|
+
every command succeeded. Add `--timing` to reproduce the original
|
|
919
|
+
pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
|
|
920
|
+
- Against a live server: start `tdb --server prog.py`, then feed line 2
|
|
921
|
+
onward of the file to `POST /rpc` — each line is already a valid
|
|
922
|
+
request body:
|
|
923
|
+
|
|
924
|
+
tail -n +2 session.jsonl | while read line; do
|
|
925
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
926
|
+
-d "$line" http://127.0.0.1:8150/rpc
|
|
927
|
+
done
|
|
928
|
+
|
|
929
|
+
(On Windows, an equivalent loop in Python: read the file, skip the
|
|
930
|
+
first line, `requests.post` each remaining line.)
|
|
931
|
+
|
|
932
|
+
Not captured: pure viewing (scrolling, search, modals, thread/task
|
|
933
|
+
lists), breakpoint enable/disable toggles, variable expansions when the
|
|
934
|
+
adapter reports no `evaluateName` (currently the Perl adapter), and
|
|
935
|
+
File > Open program switches.
|
|
936
|
+
|
|
830
937
|
## MCP Integration
|
|
831
938
|
|
|
832
939
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
@@ -936,11 +1043,12 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
936
1043
|
| `--local-root PATH` | Local directory containing a copy of remote code (repeat to mirror multiple trees). Pair with `--remote-root`; counts must match. Required when `-k` sets a breakpoint against a remote debuggee whose code lives at a different path. |
|
|
937
1044
|
| `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
|
|
938
1045
|
| `-k`, `--breakpoint FILE:LINE|LINE` | Set a breakpoint (may be repeated). Passing `-k` implies `--no-stop-on-entry` so the program runs straight to the first breakpoint. |
|
|
1046
|
+
| `-t`, `--to-line FILE:LINE|LINE` | Like `-k`, but the breakpoint is not saved to the breakpoints file — it just takes you to that spot in the code for this session (may be repeated). |
|
|
939
1047
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
940
1048
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
941
1049
|
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
942
1050
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
943
|
-
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
1051
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`, `perl`); default: auto-detect from the target |
|
|
944
1052
|
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
945
1053
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
946
1054
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
@@ -969,8 +1077,17 @@ executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
|
969
1077
|
`default_adapters` picks a language's default adapter
|
|
970
1078
|
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
971
1079
|
|
|
1080
|
+
**Perl is a special case:** `perl-tdb` is tdb's own bundled adapter (always
|
|
1081
|
+
found — it's Python code, not an external executable), so
|
|
1082
|
+
`adapters.perl` doesn't select an adapter binary. Instead it names the
|
|
1083
|
+
*Perl interpreter* tdb should spawn to run the debuggee:
|
|
1084
|
+
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1085
|
+
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1086
|
+
|
|
972
1087
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
973
|
-
directory. Each project's breakpoints are independent.
|
|
1088
|
+
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1089
|
+
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
1090
|
+
the session but are never saved.
|
|
974
1091
|
|
|
975
1092
|
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
976
1093
|
into) handle multi-line source statements:
|