textual-debugger 0.2.0__tar.gz → 0.2.4__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.4}/PKG-INFO +304 -23
- {textual_debugger-0.2.0/src/tdb → textual_debugger-0.2.4}/README.md +297 -18
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/pyproject.toml +7 -5
- {textual_debugger-0.2.0 → textual_debugger-0.2.4/src/tdb}/README.md +297 -18
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/__init__.py +1 -1
- textual_debugger-0.2.4/src/tdb/adapters/bash/__main__.py +23 -0
- textual_debugger-0.2.4/src/tdb/adapters/bash/declares.py +92 -0
- textual_debugger-0.2.4/src/tdb/adapters/bash/server.py +360 -0
- textual_debugger-0.2.4/src/tdb/adapters/bash/session.py +489 -0
- textual_debugger-0.2.4/src/tdb/adapters/bash/tdb_harness.sh +230 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/Devel/TdbCompile.pm +68 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/Devel/TdbRemote.pm +93 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/__main__.py +23 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/helpers.pl +425 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/protocol.py +110 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/refs.py +34 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/server.py +949 -0
- textual_debugger-0.2.4/src/tdb/adapters/perl/session.py +317 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/__init__.py +7 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/__main__.py +3 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/breakpoints.py +44 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/cli.py +163 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/guardian.py +718 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/inspect.py +187 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/instrumenter.py +354 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/models.py +61 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/protocol.py +68 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/runtime.py +304 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/scanner.py +225 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/server.py +553 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/session.py +1221 -0
- textual_debugger-0.2.4/src/tdb/adapters/tcsh/transport.py +914 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app.py +173 -33
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_handlers/dap_events.py +61 -64
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_handlers/ui_panels.py +2 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/cli.py +157 -57
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/dap/messages.py +20 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/dap/types.py +22 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/languages/base.py +51 -0
- textual_debugger-0.2.4/src/tdb/languages/bash.py +83 -0
- textual_debugger-0.2.4/src/tdb/languages/errors.py +235 -0
- textual_debugger-0.2.4/src/tdb/languages/perl.py +101 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/languages/python.py +2 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/languages/registry.py +32 -1
- textual_debugger-0.2.4/src/tdb/languages/tcsh.py +101 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/mcp/session.py +3 -6
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/persist.py +12 -10
- textual_debugger-0.2.4/src/tdb/replay.py +202 -0
- textual_debugger-0.2.4/src/tdb/server/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/server/event_handler.py +0 -3
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/server/handlers.py +14 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/server/runner.py +53 -18
- textual_debugger-0.2.4/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/controller.py +60 -9
- textual_debugger-0.2.4/src/tdb/session/recorder.py +106 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/state.py +22 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/textual_handler.py +0 -1
- textual_debugger-0.2.4/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/async_tasks_modal.py +1 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/code_view.py +88 -52
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/evaluate_console.py +2 -3
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/modals.py +11 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/PKG-INFO +304 -23
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/SOURCES.txt +36 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/requires.txt +1 -1
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/LICENSE +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/setup.cfg +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/_timeouts.py +0 -0
- {textual_debugger-0.2.0/src/tdb/dap → textual_debugger-0.2.4/src/tdb/adapters}/__init__.py +0 -0
- {textual_debugger-0.2.0/src/tdb/server → textual_debugger-0.2.4/src/tdb/adapters/bash}/__init__.py +0 -0
- {textual_debugger-0.2.0/src/tdb/session → textual_debugger-0.2.4/src/tdb/adapters/perl}/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_handlers/inspection.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_handlers/routing.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/breakpoint_hook.py +0 -0
- {textual_debugger-0.2.0/src/tdb/widgets → textual_debugger-0.2.4/src/tdb/dap}/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/dap/client.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/languages/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/languages/cpp.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/mcp/server.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/server/app.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/server/rpc_types.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/child_processes.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/inspect_service.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/statement_stepper.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/source_analysis.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/_inspection_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/stack_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/threads_modal.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.2.0 → textual_debugger-0.2.4}/src/textual_debugger.egg-info/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: textual-debugger
|
|
3
|
-
Version: 0.2.
|
|
4
|
-
Summary: A TUI Python
|
|
3
|
+
Version: 0.2.4
|
|
4
|
+
Summary: A TUI debugger for Python, Perl, and other languages. Based on textual.
|
|
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:
|
|
7
7
|
|
|
@@ -39,11 +39,13 @@ Classifier: Intended Audience :: Developers
|
|
|
39
39
|
Classifier: License :: OSI Approved :: MIT License
|
|
40
40
|
Classifier: Operating System :: POSIX :: Linux
|
|
41
41
|
Classifier: Programming Language :: Python :: 3
|
|
42
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
43
42
|
Classifier: Programming Language :: Python :: 3.11
|
|
44
43
|
Classifier: Programming Language :: Python :: 3.12
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
45
47
|
Classifier: Topic :: Software Development :: Debuggers
|
|
46
|
-
Requires-Python: >=3.
|
|
48
|
+
Requires-Python: >=3.11
|
|
47
49
|
Description-Content-Type: text/markdown
|
|
48
50
|
License-File: LICENSE
|
|
49
51
|
Requires-Dist: textual>=8.0.0
|
|
@@ -51,7 +53,7 @@ Requires-Dist: debugpy>=1.8.0
|
|
|
51
53
|
Requires-Dist: pygments>=2.17.0
|
|
52
54
|
Requires-Dist: fastapi>=0.115.0
|
|
53
55
|
Requires-Dist: uvicorn>=0.30.0
|
|
54
|
-
Requires-Dist: mcp
|
|
56
|
+
Requires-Dist: mcp<2.0.0,>=1.28.0
|
|
55
57
|
Provides-Extra: dev
|
|
56
58
|
Requires-Dist: pytest; extra == "dev"
|
|
57
59
|
Requires-Dist: pytest-cov; extra == "dev"
|
|
@@ -68,8 +70,12 @@ Dynamic: license-file
|
|
|
68
70
|
|
|
69
71
|
`textual-debugger` (the package) provides `tdb` (the command-line tool and module),
|
|
70
72
|
a full-featured terminal-based debugger for Python and other languages
|
|
71
|
-
with a Debug Adapter Protocol (DAP) implementation.
|
|
72
|
-
`
|
|
73
|
+
with a Debug Adapter Protocol (DAP) implementation. In addition to Python,
|
|
74
|
+
`tdb` comes with built-in support for
|
|
75
|
+
- C and C++ (via `gdb` or `lldb-dap`)
|
|
76
|
+
- Perl (via `perl -d`)
|
|
77
|
+
- Bash (via bash's own `DEBUG` trap; bash ≥ 4.4)
|
|
78
|
+
- Tcsh (via source instrumentation of a stock `tcsh`)
|
|
73
79
|
|
|
74
80
|
`tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
|
|
75
81
|
DAP to a pluggable debug adapter: [debugpy](https://github.com/microsoft/debugpy)
|
|
@@ -90,7 +96,9 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
90
96
|
`tdb`:
|
|
91
97
|
|
|
92
98
|
- debugs multiple languages through the Debug Adapter Protocol: Python (via `debugpy`,
|
|
93
|
-
the richest feature set)
|
|
99
|
+
the richest feature set), C/C++ (via `gdb -i dap` or `lldb-dap`), Perl (via `perl -d`),
|
|
100
|
+
Bash (via bash's own `DEBUG` trap), and Tcsh (via source instrumentation of a
|
|
101
|
+
stock `tcsh`), with the language
|
|
94
102
|
auto-detected from the target (ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
95
103
|
|
|
96
104
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
@@ -194,6 +202,10 @@ tdb --lang python ./mytool
|
|
|
194
202
|
# program runs to the first breakpoint)
|
|
195
203
|
tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
196
204
|
|
|
205
|
+
# run straight to line 20 without saving the breakpoint for future
|
|
206
|
+
# sessions (-t is -k minus the persistence)
|
|
207
|
+
tdb -t 20 my_program.py
|
|
208
|
+
|
|
197
209
|
# use a specific virtualenv
|
|
198
210
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
199
211
|
|
|
@@ -232,21 +244,26 @@ python -m tdb my_program.py
|
|
|
232
244
|
|
|
233
245
|
## Multi-Language Debugging
|
|
234
246
|
|
|
235
|
-
`tdb` debugs any language that has a Debug Adapter Protocol backend.
|
|
247
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Five
|
|
236
248
|
languages are supported out of the box:
|
|
237
249
|
|
|
238
|
-
| Language | Adapter(s) |
|
|
250
|
+
| Language | Adapter(s) | Dependencies | Feature level |
|
|
239
251
|
|----------|------------|------------------------|---------------|
|
|
240
|
-
| Python | `debugpy` (default) |
|
|
252
|
+
| Python | `debugpy` (default) | Python ≥ 3.11 | everything in this README |
|
|
241
253
|
| 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 |
|
|
254
|
+
| Perl | perl-tdb (bundled) | perl ≥ 5.18 on PATH | core debugging + remote attach |
|
|
255
|
+
| Bash | bash-tdb (bundled) | bash ≥ 4.4 on PATH | core debugging (no remote attach) |
|
|
256
|
+
| Tcsh | tcsh-tdb (bundled) | tcsh on PATH | core debugging (no remote attach, no conditional breakpoints, no pause) |
|
|
242
257
|
|
|
243
258
|
### Language detection and selection
|
|
244
259
|
|
|
245
260
|
The language is auto-detected from the debug target:
|
|
246
261
|
|
|
247
|
-
1. File extension: `.py` → Python
|
|
262
|
+
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl; `.sh` / `.bash`
|
|
263
|
+
→ Bash; `.csh` / `.tcsh` → Tcsh.
|
|
248
264
|
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++.
|
|
249
|
-
3. A `#!...python
|
|
265
|
+
3. A `#!...python`, `#!...perl`, `#!...bash`, or `#!...csh`/`#!...tcsh`
|
|
266
|
+
shebang → Python / Perl / Bash / Tcsh respectively.
|
|
250
267
|
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
251
268
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
252
269
|
5. Anything else produces an error naming the `--lang` override.
|
|
@@ -278,15 +295,62 @@ conditions and persistence), stepping, continue/pause, run-to-cursor, stack
|
|
|
278
295
|
navigation, variable inspection, the evaluate console, syntax highlighting,
|
|
279
296
|
and the JSON-RPC / MCP programmatic modes.
|
|
280
297
|
|
|
281
|
-
Python-specific features are hidden or return
|
|
298
|
+
Python-specific features are hidden or return "not supported for this
|
|
282
299
|
language" message when debugging other languages: statement-granularity
|
|
283
300
|
stepping (non-Python languages always step per line), the async task /
|
|
284
301
|
process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
302
|
+
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
303
|
+
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
304
|
+
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
305
|
+
[Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`), but not
|
|
306
|
+
for C/C++, Bash, or Tcsh. `--terminal` is
|
|
288
307
|
currently ignored for non-Python targets.
|
|
289
308
|
|
|
309
|
+
**Bash limitations (v1):** the bash adapter uses bash's own `DEBUG` trap and
|
|
310
|
+
has a smaller feature envelope than Python/Perl:
|
|
311
|
+
|
|
312
|
+
- Debuggee code that installs its own `DEBUG` trap clobbers the harness;
|
|
313
|
+
debugging silently degrades to free-running.
|
|
314
|
+
- No stopping inside subshells `(...)`, `$(...)`, or pipeline segments; they
|
|
315
|
+
execute normally.
|
|
316
|
+
- Child bash processes run uninstrumented.
|
|
317
|
+
- Outer-frame locals not inspectable (innermost frame only).
|
|
318
|
+
- Pause is deferred while blocked in an external command.
|
|
319
|
+
- `.sh` files that aren't bash are only diagnosed at launch, by bash itself
|
|
320
|
+
or the harness version check.
|
|
321
|
+
- The `DEBUG` trap never fires on a function-definition line, so a
|
|
322
|
+
breakpoint on a `func() {` line never hits; entry and step-in stops land
|
|
323
|
+
on the first executable line of the function body instead.
|
|
324
|
+
- The debug control channel occupies two inherited file descriptors
|
|
325
|
+
(typically high-numbered). A script that execs redirections onto those
|
|
326
|
+
exact fds (e.g. `exec 63>&-` or reusing them for its own I/O) will
|
|
327
|
+
silently break debugging.
|
|
328
|
+
|
|
329
|
+
See [Bash](#bash) below for launch details.
|
|
330
|
+
|
|
331
|
+
**Tcsh limitations (v1):** tcsh has no debug hooks at all, so the tcsh
|
|
332
|
+
adapter debugs an instrumented temporary *copy* of the script (original
|
|
333
|
+
paths and line numbers are preserved in everything tdb displays):
|
|
334
|
+
|
|
335
|
+
- Conditional breakpoints are not supported; a condition set in the
|
|
336
|
+
Breakpoint View is ignored for tcsh (the breakpoint always stops).
|
|
337
|
+
- No asynchronous pause: a free-running script stops only at the next
|
|
338
|
+
breakpoint (or when it exits).
|
|
339
|
+
- A breakpoint binds to the nearest safe statement at or after the
|
|
340
|
+
requested line; unplaceable breakpoints are reported unverified.
|
|
341
|
+
- Stack frames represent `source`d files, not native call frames, and only
|
|
342
|
+
literal `source` targets resolvable at launch are instrumented (computed
|
|
343
|
+
or `cd`-dependent sources run normally but are atomic to the debugger).
|
|
344
|
+
- All frames show the same live shell state (Shell Variables, Environment,
|
|
345
|
+
Aliases, Arguments). Stock tcsh keeps no per-frame history.
|
|
346
|
+
- Multiple commands on one physical line (`a ; b`), command substitutions,
|
|
347
|
+
and external commands are atomic stepping units.
|
|
348
|
+
- `$0` inside dynamically generated or evaluated text can expose the
|
|
349
|
+
generated copy's path (ordinary lexical `$0` is rewritten correctly).
|
|
350
|
+
- Requires Python ≥ 3.11.
|
|
351
|
+
|
|
352
|
+
See [Tcsh](#tcsh) below for launch details.
|
|
353
|
+
|
|
290
354
|
### C/C++ tips
|
|
291
355
|
|
|
292
356
|
- Compile with `-g` (ideally `-g -O0`). If no breakpoint in a file can be
|
|
@@ -297,12 +361,183 @@ currently ignored for non-Python targets.
|
|
|
297
361
|
variables, and evaluate console remain fully usable.
|
|
298
362
|
- GDB (the default adapter) has the most complete libstdc++
|
|
299
363
|
pretty-printing. `lldb-dap` (via `--adapter lldb-dap`) also debugs
|
|
300
|
-
GCC-built binaries fine
|
|
364
|
+
GCC-built binaries fine. DWARF is compiler-neutral.
|
|
301
365
|
- **GDB evaluate-console quirk:** GDB's DAP treats REPL input as CLI
|
|
302
366
|
commands, so evaluate expressions with an explicit `print`, e.g.
|
|
303
367
|
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
304
368
|
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
305
369
|
|
|
370
|
+
### Perl
|
|
371
|
+
|
|
372
|
+
`tdb` bundles its own Perl adapter (`perl-tdb`) so only need
|
|
373
|
+
`perl` ≥ 5.18 on `PATH`. It drives stock `perl5db` under the
|
|
374
|
+
hood, so it works with any Perl already on the system.
|
|
375
|
+
|
|
376
|
+
**Launching a script:**
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
tdb script.pl
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Compile-time code (`BEGIN` blocks):** Perl runs `BEGIN` blocks and the
|
|
383
|
+
`use` statements that are themselves `BEGIN` blocks while it is still
|
|
384
|
+
*compiling* your program, before stock `perl5db` ever stops. `tdb` arms the
|
|
385
|
+
debugger ahead of compilation so that code is debuggable too, which means the
|
|
386
|
+
first stop is the first **compile-time** statement of your file (typically
|
|
387
|
+
`use strict;` near the top) rather than the first runtime statement. Step from
|
|
388
|
+
there and you land inside your `BEGIN` blocks, with the stack and evaluate
|
|
389
|
+
views working normally (local variable listing is limited at a compile-time
|
|
390
|
+
stop); the `Stack` view shows the frame as `main::BEGIN`. Stepping through a
|
|
391
|
+
`use` line takes a few steps (the pragma's
|
|
392
|
+
own compile-time work happens in between) but you are never dragged into
|
|
393
|
+
another module's internals.
|
|
394
|
+
|
|
395
|
+
Two consequences worth knowing:
|
|
396
|
+
|
|
397
|
+
- **Breakpoints are deferred while your program compiles.** During the compile
|
|
398
|
+
phase Perl has only parsed part of your file, so its line table is
|
|
399
|
+
incomplete and a breakpoint can't be verified yet. `tdb` holds such requests
|
|
400
|
+
and, while it single-steps through the rest of compilation, checks each
|
|
401
|
+
compile-time statement it lands on against them. A breakpoint placed
|
|
402
|
+
*inside* a `BEGIN` block fires there directly, on the first run, without
|
|
403
|
+
needing to be stepped into by hand. Conditional breakpoints work the same
|
|
404
|
+
way at compile time; a condition that itself errors behaves exactly like a
|
|
405
|
+
bad condition at runtime in that it does not fire. Two residual caveats: a
|
|
406
|
+
breakpoint on a non-statement line (the `BEGIN {` line itself, or a blank
|
|
407
|
+
line) never fires during the compile phase, since it's never actually
|
|
408
|
+
trapped as a statement; and `hitCondition` (break on the Nth hit) isn't
|
|
409
|
+
honored for a compile-time stop, only a plain `condition`.
|
|
410
|
+
- **Startup is slower for large dependency graphs**, because the debugger is
|
|
411
|
+
active throughout compilation. A script with a big `use` tree takes
|
|
412
|
+
noticeably longer to reach its first stop under `tdb`.
|
|
413
|
+
|
|
414
|
+
**`END` blocks** are entered with **step-in** (`s`). `next` and `continue` run
|
|
415
|
+
straight past them to program termination, which is standard `perl5db`
|
|
416
|
+
behavior, not a `tdb` limitation.
|
|
417
|
+
|
|
418
|
+
**When your program dies:** an uncaught Perl error (`die`, or a fatal runtime
|
|
419
|
+
error such as division by zero) opens the same error modal Python tracebacks
|
|
420
|
+
get: the message, the call stack parsed from Perl's `at FILE line N.` /
|
|
421
|
+
`... called at FILE line N` output, and Code View navigated to the failing
|
|
422
|
+
line. This works for compile-time failures too, including a `die` inside a
|
|
423
|
+
`BEGIN` block that aborts compilation. Press `e` in Code View to re-summon the
|
|
424
|
+
last error. `tdb` also reports the debuggee's real exit status rather than
|
|
425
|
+
assuming success.
|
|
426
|
+
|
|
427
|
+
**Remote attach:** useful when the Perl process is already running (a long-
|
|
428
|
+
lived service, a process started by something other than `tdb`) or lives on
|
|
429
|
+
another host/container. Add three lines to the target program, with the
|
|
430
|
+
`use` line first so the debugger is armed before any of your code compiles:
|
|
431
|
+
|
|
432
|
+
```perl
|
|
433
|
+
use Devel::TdbRemote; # first line of your program
|
|
434
|
+
...
|
|
435
|
+
Devel::TdbRemote::listen(5678); # non-blocking
|
|
436
|
+
print "Waiting for tdb to attach on port 5678\n";
|
|
437
|
+
Devel::TdbRemote::wait_for_client(); # blocks until tdb connects
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Then attach from `tdb`, forcing the language since there's no local `program`
|
|
441
|
+
argument for `tdb` to detect it from:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
tdb --lang perl -r host:5678
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Arming caveat:** only code *compiled after* the debugger is armed can be
|
|
448
|
+
stepped into or breakpointed. That's why `use Devel::TdbRemote;` must be the
|
|
449
|
+
first line of the program. If you can't edit the first line (e.g. a wrapper
|
|
450
|
+
script controls startup), arm it before Perl even parses your file instead:
|
|
451
|
+
`perl -d:TdbRemote prog.pl`, or set `PERL5OPT=-d:TdbRemote` in the
|
|
452
|
+
environment that launches the debuggee.
|
|
453
|
+
|
|
454
|
+
**Copying the adapter to a remote host:** `Devel::TdbRemote` and its helper
|
|
455
|
+
script are plain files, not a CPAN install. Copy both onto the remote
|
|
456
|
+
machine and point `PERL5LIB` at the directory that contains them, for example:
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
# From a checkout or an installed wheel's site-packages/tdb/adapters/perl:
|
|
460
|
+
scp -r Devel/TdbRemote.pm helpers.pl remote-host:/opt/tdb-perl/
|
|
461
|
+
# On the remote host:
|
|
462
|
+
export PERL5LIB=/opt/tdb-perl:$PERL5LIB
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
(`Devel/TdbRemote.pm` locates `helpers.pl` next to itself at runtime, so keep
|
|
466
|
+
the two files in the same relative layout shown above; `helpers.pl` is a
|
|
467
|
+
sibling of the `Devel/` directory, not inside it.)
|
|
468
|
+
|
|
469
|
+
**PadWalker (optional but recommended):** inspecting lexical (`my`)
|
|
470
|
+
variables in the *current* frame always works. Lexicals in outer/caller
|
|
471
|
+
frames need the `PadWalker` module installed on the debuggee's Perl; without
|
|
472
|
+
it, tdb falls back to a read-only pad walk that can't reach fully into
|
|
473
|
+
enclosing scopes, and outer-frame variable listings degrade accordingly.
|
|
474
|
+
Install with `cpanm PadWalker` (or your distro's package) for full fidelity.
|
|
475
|
+
|
|
476
|
+
**Pause is unavailable in attach mode.** Launch-mode sessions (`tdb
|
|
477
|
+
script.pl`) support pausing a running program at any time. Remote-attach
|
|
478
|
+
sessions don't. Asynchronous pause (as Python gets via `debugpy`) needs a control channel
|
|
479
|
+
`Devel::TdbRemote` doesn't implement yet; `pause` in attach mode returns a
|
|
480
|
+
"not available" error instead of hanging.
|
|
481
|
+
|
|
482
|
+
### Bash
|
|
483
|
+
|
|
484
|
+
`tdb` bundles its own bash adapter (`bash-tdb`) so no separate adapter install
|
|
485
|
+
needed, just a `bash` ≥ 4.4 on `PATH`. It drives stock bash's own `DEBUG`
|
|
486
|
+
trap (with `extdebug` for return-value control) under the hood via a small
|
|
487
|
+
harness script sourced through `BASH_ENV`, so it works with any bash already
|
|
488
|
+
on the system.
|
|
489
|
+
|
|
490
|
+
**Launching a script:**
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
tdb script.sh
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
Core debugging works as described above (breakpoints, stepping,
|
|
497
|
+
continue/pause, stack, variables, evaluate console), with the v1 caveats
|
|
498
|
+
listed in [What works for non-Python languages](#what-works-for-non-python-languages).
|
|
499
|
+
Most notably, a breakpoint can't be set on a `func() {` line itself (the
|
|
500
|
+
`DEBUG` trap never fires there), stops never land inside subshells or
|
|
501
|
+
pipeline segments, child bash processes run uninstrumented, and only the
|
|
502
|
+
innermost frame's locals are inspectable. There is no remote-attach mode for
|
|
503
|
+
Bash.
|
|
504
|
+
|
|
505
|
+
The Variables view shows three scopes for bash: Locals (innermost frame
|
|
506
|
+
only), Globals (unexported shell variables), and Environment (exported
|
|
507
|
+
variables, both inherited and script-`export`ed).
|
|
508
|
+
|
|
509
|
+
### Tcsh
|
|
510
|
+
|
|
511
|
+
`tdb` bundles its own tcsh adapter (`tcsh-tdb`) so no separate adapter
|
|
512
|
+
is needed, just a stock `tcsh` on `PATH` (or
|
|
513
|
+
`{"adapters": {"tcsh": "/path/to/tcsh"}}` in `config.json`). Stock tcsh has
|
|
514
|
+
no debugger hooks, so the adapter instruments a temporary copy of the script
|
|
515
|
+
(and of any literal `source`d files), runs it with `tcsh -f`, and
|
|
516
|
+
coordinates stops through private FIFOs. tdb always shows the original
|
|
517
|
+
source paths and line numbers; the generated copies are private adapter
|
|
518
|
+
details and are cleaned up when the session ends.
|
|
519
|
+
|
|
520
|
+
**Launching a script:**
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
tdb script.csh
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
Core debugging works as described above: line breakpoints, stepping
|
|
527
|
+
(`next` steps over `source`d files, `stepIn` steps into instrumented ones),
|
|
528
|
+
stack navigation across `source` nesting, variable inspection, and the
|
|
529
|
+
evaluate console with the v1 caveats listed in
|
|
530
|
+
[What works for non-Python languages](#what-works-for-non-python-languages),
|
|
531
|
+
most notably: no conditional breakpoints, no pause of a free-running
|
|
532
|
+
script, and stepping is per logical source line.
|
|
533
|
+
|
|
534
|
+
The Variables view shows four scopes for tcsh: Shell Variables (`set`),
|
|
535
|
+
Environment (`setenv`), Aliases, and Arguments (`argv`). All of them show
|
|
536
|
+
the live state of the single tcsh process. The evaluate console executes
|
|
537
|
+
text directly in the paused shell. It can inspect *and mutate* state
|
|
538
|
+
(`set name = value` takes effect immediately), and a syntax error in
|
|
539
|
+
evaluated text can terminate the debuggee; there is no isolation.
|
|
540
|
+
|
|
306
541
|
## Layout
|
|
307
542
|
|
|
308
543
|
```
|
|
@@ -446,8 +681,10 @@ Breakpoints persist across session restarts.
|
|
|
446
681
|
|
|
447
682
|
### Variable Inspection
|
|
448
683
|
|
|
449
|
-
The Variable View shows a tree of scopes
|
|
450
|
-
|
|
684
|
+
The Variable View shows a tree of scopes with all variables in the current frame. The scopes
|
|
685
|
+
themselves are language-dependent: Locals, Globals, plus Environment for bash; Lexicals,
|
|
686
|
+
Globals, Specials for Perl (see the [Bash](#bash) and [Perl](#perl) sections above for
|
|
687
|
+
details). Expand nodes to drill into complex objects. Children are loaded lazily on demand.
|
|
451
688
|
Variable values can be changed in the Evaluate Console.
|
|
452
689
|
|
|
453
690
|
Double-click a variable, or highlight the variable with the text cursor in
|
|
@@ -893,6 +1130,40 @@ curl -N http://127.0.0.1:8150/events
|
|
|
893
1130
|
Events: `initialized`, `stopped`, `continued`, `terminated`, `exited`, `output`.
|
|
894
1131
|
Each is JSON with `event`, `data`, and `timestamp` fields.
|
|
895
1132
|
|
|
1133
|
+
## Recording and replaying sessions
|
|
1134
|
+
|
|
1135
|
+
`tdb --record session.jsonl prog.py` runs a normal TUI session and captures
|
|
1136
|
+
your debugging actions including breakpoints (including `-k`/`-t` and persisted
|
|
1137
|
+
ones), stepping, continue/pause, Evaluate-console entries, stack-frame
|
|
1138
|
+
navigation, variable expansion, restart, quit. The session is
|
|
1139
|
+
written to `session.jsonl` as
|
|
1140
|
+
JSON-RPC commands. Works with launch mode (any language) and `-r`
|
|
1141
|
+
remote attach.
|
|
1142
|
+
|
|
1143
|
+
Replay it two ways:
|
|
1144
|
+
|
|
1145
|
+
- `tdb --replay session.jsonl` launches the recorded
|
|
1146
|
+
program headless, feeds every recorded command through the same RPC
|
|
1147
|
+
dispatch `tdb --server` uses, and prints a transcript (recorded time,
|
|
1148
|
+
command, verbatim result, interleaved program output). Exit code 0 iff
|
|
1149
|
+
every command succeeded. Add `--timing` to reproduce the original
|
|
1150
|
+
pacing, `--replay-timeout S` to bound each stop-wait (default 30 s).
|
|
1151
|
+
- Against a live server: start `tdb --server prog.py`, then feed line 2
|
|
1152
|
+
onward of the file to `POST /rpc` . Each line is a valid request body:
|
|
1153
|
+
|
|
1154
|
+
tail -n +2 session.jsonl | while read line; do
|
|
1155
|
+
curl -s -X POST -H 'Content-Type: application/json' \
|
|
1156
|
+
-d "$line" http://127.0.0.1:8150/rpc
|
|
1157
|
+
done
|
|
1158
|
+
|
|
1159
|
+
(On Windows, an equivalent loop in Python: read the file, skip the
|
|
1160
|
+
first line, `requests.post` each remaining line.)
|
|
1161
|
+
|
|
1162
|
+
Not captured: pure viewing (scrolling, search, modals, thread/task
|
|
1163
|
+
lists), breakpoint enable/disable toggles, variable expansions when the
|
|
1164
|
+
adapter reports no `evaluateName` (currently the Perl adapter), and
|
|
1165
|
+
File > Open program switches.
|
|
1166
|
+
|
|
896
1167
|
## MCP Integration
|
|
897
1168
|
|
|
898
1169
|
tdb ships a Model Context Protocol (MCP) server (`tdb-mcp`) that exposes
|
|
@@ -932,7 +1203,7 @@ client expects to launch servers.
|
|
|
932
1203
|
| Cluster | Tools |
|
|
933
1204
|
|---------|-------|
|
|
934
1205
|
| Lifecycle | `debug_launch`, `debug_attach`, `quit` |
|
|
935
|
-
| Control | `control(action, timeout_s=30)`
|
|
1206
|
+
| Control | `control(action, timeout_s=30)` where `action ∈ {continue, next, step_in, step_out, pause, wait_for_stop}` |
|
|
936
1207
|
| Inspection | `inspect(expressions)`, `read_source(file_path)`, `stack_trace()`, `status()`, `get_output()` |
|
|
937
1208
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
938
1209
|
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
@@ -1002,11 +1273,12 @@ usage: tdb [-h] [-v] [-r [HOST:]PORT] [--cwd CWD] [--no-stop-on-entry]
|
|
|
1002
1273
|
| `--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
1274
|
| `--remote-root PATH` | Remote directory matched to `--local-root` (same CLI position via `zip()`). |
|
|
1004
1275
|
| `-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. |
|
|
1276
|
+
| `-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
1277
|
| `--no-stop-on-entry` | Do not pause at the first line (default: stop on entry; automatic when `-k` is given) |
|
|
1006
1278
|
| `--cwd DIR` | Working directory for the debuggee |
|
|
1007
1279
|
| `--python PATH` | Python interpreter for the debuggee (Python targets only) |
|
|
1008
1280
|
| `--pv` | Shorthand for --python .venv/bin/python |
|
|
1009
|
-
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`); default: auto-detect from the target |
|
|
1281
|
+
| `--lang LANGUAGE` | Debuggee language (`python`, `cpp`, `perl`); default: auto-detect from the target |
|
|
1010
1282
|
| `--adapter ADAPTER` | Debug adapter within the language (e.g. `--lang cpp --adapter lldb-dap`); default: the language's standard adapter |
|
|
1011
1283
|
| `--no-just-my-code` | Step into stdlib/site-packages code instead of skipping it
|
|
1012
1284
|
(default: skipped). On uncaught exceptions, the crash modal always shows the full traceback
|
|
@@ -1035,8 +1307,17 @@ executable path (`{"adapters": {"lldb-dap": "/opt/llvm/bin/lldb-dap"}}`), and
|
|
|
1035
1307
|
`default_adapters` picks a language's default adapter
|
|
1036
1308
|
(`{"default_adapters": {"cpp": "lldb-dap"}}`).
|
|
1037
1309
|
|
|
1310
|
+
**Perl is a special case:** `perl-tdb` is tdb's own bundled adapter (always
|
|
1311
|
+
found; it's Python code, not an external executable), so
|
|
1312
|
+
`adapters.perl` doesn't select an adapter binary. Instead it names the
|
|
1313
|
+
*Perl interpreter* tdb should spawn to run the debuggee:
|
|
1314
|
+
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1315
|
+
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1316
|
+
|
|
1038
1317
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
1039
|
-
directory. Each project's breakpoints are independent.
|
|
1318
|
+
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1319
|
+
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
1320
|
+
the session but are never saved.
|
|
1040
1321
|
|
|
1041
1322
|
**Step mode** (`step_mode` in `config.json`) controls how `n` (step over) and `s` (step
|
|
1042
1323
|
into) handle multi-line source statements:
|