textual-debugger 0.2.6__tar.gz → 0.2.10__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.6 → textual_debugger-0.2.10}/PKG-INFO +553 -51
- {textual_debugger-0.2.6/src/tdb → textual_debugger-0.2.10}/README.md +551 -49
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/pyproject.toml +3 -2
- {textual_debugger-0.2.6 → textual_debugger-0.2.10/src/tdb}/README.md +551 -49
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/__init__.py +1 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/_timeouts.py +4 -0
- textual_debugger-0.2.10/src/tdb/adapters/ocaml/lldb_formatters.py +153 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/server.py +21 -10
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/session.py +9 -1
- textual_debugger-0.2.10/src/tdb/adapters/powershell/__init__.py +3 -0
- textual_debugger-0.2.10/src/tdb/adapters/powershell/__main__.py +23 -0
- textual_debugger-0.2.10/src/tdb/adapters/powershell/locate.py +121 -0
- textual_debugger-0.2.10/src/tdb/adapters/powershell/output.py +80 -0
- textual_debugger-0.2.10/src/tdb/adapters/powershell/server.py +913 -0
- textual_debugger-0.2.10/src/tdb/adapters/powershell/tdb_launch.ps1 +14 -0
- textual_debugger-0.2.10/src/tdb/adapters/ruby/__init__.py +1 -0
- textual_debugger-0.2.10/src/tdb/adapters/ruby/__main__.py +23 -0
- textual_debugger-0.2.10/src/tdb/adapters/ruby/server.py +1120 -0
- textual_debugger-0.2.10/src/tdb/adapters/seqs.py +62 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app.py +31 -17
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app_handlers/dap_events.py +3 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app_handlers/inspection.py +171 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app_handlers/routing.py +72 -0
- textual_debugger-0.2.10/src/tdb/app_handlers/ui_panels.py +143 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/breakpoint_hook.py +16 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/cli.py +249 -18
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/dap/client.py +80 -1
- textual_debugger-0.2.10/src/tdb/eval_mode.py +314 -0
- textual_debugger-0.2.10/src/tdb/go_concurrency/analyzer.py +112 -0
- textual_debugger-0.2.10/src/tdb/go_concurrency/classifier.py +59 -0
- textual_debugger-0.2.10/src/tdb/go_concurrency/collector.py +122 -0
- textual_debugger-0.2.10/src/tdb/go_concurrency/models.py +123 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/base.py +88 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/bash.py +3 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/cpp.py +49 -6
- textual_debugger-0.2.10/src/tdb/languages/errors.py +661 -0
- textual_debugger-0.2.10/src/tdb/languages/go.py +217 -0
- textual_debugger-0.2.10/src/tdb/languages/ocaml.py +399 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/perl.py +3 -1
- textual_debugger-0.2.10/src/tdb/languages/powershell.py +124 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/python.py +6 -4
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/registry.py +96 -11
- textual_debugger-0.2.10/src/tdb/languages/ruby.py +117 -0
- textual_debugger-0.2.10/src/tdb/languages/rust.py +158 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/tcsh.py +3 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/mcp/server.py +53 -9
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/mcp/session.py +29 -5
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/replay.py +12 -2
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/run_mode.py +64 -30
- textual_debugger-0.2.10/src/tdb/rust_concurrency/__init__.py +41 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/analyzer.py +505 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/classifier.py +255 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/collector.py +337 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/models.py +269 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/__init__.py +18 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/base.py +166 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/gdb.py +27 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/gdb_script.py +238 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/lldb.py +35 -0
- textual_debugger-0.2.10/src/tdb/rust_concurrency/probes/lldb_script.py +276 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/server/app.py +1 -1
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/server/handlers.py +42 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/server/rpc_types.py +17 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/server/runner.py +19 -3
- textual_debugger-0.2.10/src/tdb/session/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/controller.py +195 -17
- textual_debugger-0.2.10/src/tdb/session/errors.py +23 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/inspect_service.py +33 -15
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/recorder.py +3 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/state.py +9 -0
- textual_debugger-0.2.10/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/_inspection_modal.py +11 -2
- textual_debugger-0.2.10/src/tdb/widgets/goroutines_modal.py +354 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/modals.py +21 -10
- textual_debugger-0.2.10/src/tdb/widgets/rust_concurrency_modal.py +397 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/stack_view.py +6 -2
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/threads_modal.py +55 -8
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/textual_debugger.egg-info/PKG-INFO +553 -51
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/textual_debugger.egg-info/SOURCES.txt +37 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/textual_debugger.egg-info/requires.txt +1 -1
- textual_debugger-0.2.6/src/tdb/app_handlers/ui_panels.py +0 -65
- textual_debugger-0.2.6/src/tdb/languages/errors.py +0 -235
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/LICENSE +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/setup.cfg +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/__main__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/declares.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/server.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/session.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/bash/tdb_harness.sh +0 -0
- {textual_debugger-0.2.6/src/tdb/adapters/perl → textual_debugger-0.2.10/src/tdb/adapters/ocaml}/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/Devel/TdbCompile.pm +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/Devel/TdbRemote.pm +0 -0
- {textual_debugger-0.2.6/src/tdb/dap → textual_debugger-0.2.10/src/tdb/adapters/perl}/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/__main__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/helpers.pl +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/protocol.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/perl/refs.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/__main__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/breakpoints.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/cli.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/guardian.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/inspect.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/instrumenter.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/models.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/protocol.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/runtime.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/scanner.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/server.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/session.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/adapters/tcsh/transport.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.2.6/src/tdb/server → textual_debugger-0.2.10/src/tdb/dap}/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/dap/messages.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/dap/reverse.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/dap/types.py +0 -0
- {textual_debugger-0.2.6/src/tdb/session → textual_debugger-0.2.10/src/tdb/go_concurrency}/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/languages/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/persist.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.2.6/src/tdb/widgets → textual_debugger-0.2.10/src/tdb/server}/__init__.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/server/event_handler.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/child_processes.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/event_bus.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/statement_stepper.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/session/textual_handler.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/source_analysis.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/async_tasks_modal.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/code_view.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/evaluate_console.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.2.6 → textual_debugger-0.2.10}/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.10
|
|
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:
|
|
@@ -49,7 +49,7 @@ Requires-Python: >=3.11
|
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
50
50
|
License-File: LICENSE
|
|
51
51
|
Requires-Dist: textual>=8.0.0
|
|
52
|
-
Requires-Dist: debugpy>=1.8.
|
|
52
|
+
Requires-Dist: debugpy>=1.8.12
|
|
53
53
|
Requires-Dist: pygments>=2.17.0
|
|
54
54
|
Requires-Dist: fastapi>=0.115.0
|
|
55
55
|
Requires-Dist: uvicorn>=0.30.0
|
|
@@ -73,16 +73,18 @@ a full-featured terminal-based debugger for Python and other languages
|
|
|
73
73
|
with a Debug Adapter Protocol (DAP) implementation. In addition to Python,
|
|
74
74
|
`tdb` comes with built-in support for
|
|
75
75
|
- C and C++ (via `gdb` or `lldb-dap`)
|
|
76
|
+
- Rust (via `gdb` or `lldb-dap`, selected explicitly)
|
|
76
77
|
- Perl (via `perl -d`)
|
|
77
78
|
- Bash (via bash's own `DEBUG` trap; bash ≥ 4.4)
|
|
78
79
|
- Tcsh (via source instrumentation of a stock `tcsh`)
|
|
80
|
+
- Ruby (via the [debug gem](https://github.com/ruby/debug)'s `rdbg`; debug ≥ 1.9)
|
|
81
|
+
- OCaml (native via `lldb-dap`/`gdb`, bytecode via [ocamlearlybird](https://github.com/hackwaly/ocamlearlybird))
|
|
82
|
+
- Go (via [Delve](https://github.com/go-delve/delve)'s `dlv dap`)
|
|
83
|
+
- PowerShell 7 (via [PowerShell Editor Services](https://github.com/PowerShell/PowerShellEditorServices); Linux/macOS, Windows experimental)
|
|
79
84
|
|
|
80
85
|
`tdb` is built with [textual](https://github.com/Textualize/textual) and speaks
|
|
81
|
-
DAP to a pluggable debug adapter
|
|
82
|
-
|
|
83
|
-
[GDB's DAP mode](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Debugger-Adapter-Protocol.html) or
|
|
84
|
-
[lldb-dap](https://lldb.llvm.org/resources/lldbdap.html)
|
|
85
|
-
for compiled code. It provides a rich interactive interface for stepping through
|
|
86
|
+
DAP to a pluggable debug adapter.
|
|
87
|
+
It provides a rich interactive interface for stepping through
|
|
86
88
|
code, inspecting variables, managing breakpoints, and evaluating expressions in
|
|
87
89
|
complex programs.
|
|
88
90
|
|
|
@@ -96,10 +98,14 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
96
98
|
`tdb`:
|
|
97
99
|
|
|
98
100
|
- debugs multiple languages through the Debug Adapter Protocol: Python (via `debugpy`,
|
|
99
|
-
the richest feature set), C/C++ (via `gdb -i dap` or `lldb-dap`),
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
the richest feature set), C/C++ (via `gdb -i dap` or `lldb-dap`), Rust (via `gdb` or
|
|
102
|
+
`lldb-dap`), Perl (via `perl -d`),
|
|
103
|
+
Bash (via bash's own `DEBUG` trap), Tcsh (via source instrumentation of a
|
|
104
|
+
stock `tcsh`), Ruby (via the debug gem's `rdbg`), OCaml (native via
|
|
105
|
+
`lldb-dap`/`gdb`, bytecode via ocamlearlybird), Go (via Delve's `dlv
|
|
106
|
+
dap`), and PowerShell 7 (via PowerShell Editor Services). Most languages are
|
|
107
|
+
auto-detected from the target; Rust intentionally requires `--lang rust`
|
|
108
|
+
(ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
103
109
|
|
|
104
110
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
105
111
|
It specifically supports modules
|
|
@@ -107,7 +113,7 @@ It specifically supports modules
|
|
|
107
113
|
- `threading` (with a thread inspector)
|
|
108
114
|
- `multiprocessing` / `concurrent.futures` (with automatic child process attachment and a process inspector)
|
|
109
115
|
|
|
110
|
-
- supports remote attachment to
|
|
116
|
+
- supports remote attachment to Python, Perl, Ruby, Rust, C/C++, and Go programs
|
|
111
117
|
|
|
112
118
|
- includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
|
|
113
119
|
programmatic debug control, making it suitable for
|
|
@@ -142,7 +148,8 @@ as open source.
|
|
|
142
148
|
- OpenAI, for providing access to Codex through the
|
|
143
149
|
[Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
|
|
144
150
|
|
|
145
|
-
This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
|
|
151
|
+
This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
|
|
152
|
+
Python debugger.
|
|
146
153
|
|
|
147
154
|
## Gallery
|
|
148
155
|
<p align="center">
|
|
@@ -208,6 +215,10 @@ tdb -k 20 -k 35 -k module.py:14 my_program.py arg1 arg2
|
|
|
208
215
|
# sessions (-t is -k minus the persistence)
|
|
209
216
|
tdb -t 20 my_program.py
|
|
210
217
|
|
|
218
|
+
# no TUI: run at (almost) full speed, printing nr each time line 25 is
|
|
219
|
+
# reached, then continuing (-e may be repeated; see "Eval Mode" below)
|
|
220
|
+
tdb --eval my_program.py:25 "print(f'{nr=}')" my_program.py
|
|
221
|
+
|
|
211
222
|
# use a specific virtualenv
|
|
212
223
|
tdb --python /path/to/venv/bin/python my_program.py
|
|
213
224
|
|
|
@@ -234,6 +245,11 @@ tdb -r remotehost:5678 -k my_program.py:42
|
|
|
234
245
|
# than code on the remote host
|
|
235
246
|
tdb -r remotehost:5678 --local-root /my/code/dir --remote-root /app -k my_program.py:42
|
|
236
247
|
|
|
248
|
+
# attach to a program that pauses itself (debugpy.breakpoint() right after
|
|
249
|
+
# debugpy.wait_for_client()); without this flag tdb pauses the program on
|
|
250
|
+
# attach, which can leave it suspended after tdb quits
|
|
251
|
+
tdb -r remotehost:5678 --no-pause-on-attach
|
|
252
|
+
|
|
237
253
|
# separate tdb arguments from debuggee arguments with `--`
|
|
238
254
|
tdb --python /path/to/venv/bin/python -- my_program.py -k 17 --max 23.3
|
|
239
255
|
```
|
|
@@ -246,32 +262,58 @@ python -m tdb my_program.py
|
|
|
246
262
|
|
|
247
263
|
## Multi-Language Debugging
|
|
248
264
|
|
|
249
|
-
`tdb` debugs any language that has a Debug Adapter Protocol backend.
|
|
265
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Ten
|
|
250
266
|
languages are supported out of the box:
|
|
251
267
|
|
|
252
268
|
| Language | Adapter(s) | Dependencies | Feature level |
|
|
253
269
|
|----------|------------|------------------------|---------------|
|
|
254
270
|
| Python | `debugpy` (default) | Python ≥ 3.11 | everything in this README |
|
|
255
|
-
| 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 |
|
|
271
|
+
| 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 + remote attach (gdbserver/lldb-server, local symbol-bearing executable required) |
|
|
272
|
+
| Rust (explicit `--lang rust`) | `gdb` (Linux default), `lldb-dap` (macOS default) | any rustc building with debug info; GDB ≥ 14 or LLVM `lldb-dap` ≥ 17 (concurrency ownership evidence additionally requires stable Rust 1.98) | core debugging + best-effort Rust concurrency inspection + remote attach |
|
|
256
273
|
| Perl | perl-tdb (bundled) | perl ≥ 5.18 on PATH | core debugging + remote attach |
|
|
257
274
|
| Bash | bash-tdb (bundled) | bash ≥ 4.4 on PATH | core debugging (no remote attach) |
|
|
258
275
|
| Tcsh | tcsh-tdb (bundled) | tcsh on PATH | core debugging (no remote attach, no conditional breakpoints, no pause) |
|
|
276
|
+
| Ruby | `rdbg` (the [debug gem](https://github.com/ruby/debug)) | `rdbg` ≥ 1.9 on PATH | core debugging + remote attach |
|
|
277
|
+
| OCaml (native executable) | `lldb-dap` (default), `gdb` (alternate) | `lldb-dap` ships with LLVM ≥ 17; `gdb -i dap` requires GDB ≥ 14 | core debugging + domains-as-threads; Variables view shows no OCaml locals (upstream DWARF limitation); evaluate console is lldb/C-level, not OCaml |
|
|
278
|
+
| OCaml (bytecode executable) | `ocamlearlybird` (default) | `opam install earlybird` | core debugging + rich OCaml locals; no pause/`--run`, no evaluate responses, no fatal-error modal (ocamlearlybird 1.3.6 limitations); single-domain only |
|
|
279
|
+
| Go | `dlv` (the [Delve](https://github.com/go-delve/delve) DAP server) | Delve ≥ 1.21 on PATH (`go install github.com/go-delve/delve/cmd/dlv@latest`) | core debugging + goroutine inspection (wait graph, findings) + remote attach (no `--terminal`) |
|
|
280
|
+
| PowerShell 7 | `pses` (PowerShell Editor Services, driven by tdb's bundled proxy) | `pwsh` ≥ 7.2 on PATH + the PSES module (see [PowerShell](#powershell)) | core debugging (breakpoints incl. conditional/hit-count/log, stepping, stack, variables, evaluate console) + `--run`; no `--terminal`, no remote attach; Windows untested |
|
|
259
281
|
|
|
260
282
|
### Language detection and selection
|
|
261
283
|
|
|
262
284
|
The language is auto-detected from the debug target:
|
|
263
285
|
|
|
264
|
-
1.
|
|
265
|
-
|
|
266
|
-
2.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
286
|
+
1. A directory → Go, if it contains any `*.go` file (a Go package
|
|
287
|
+
directory, e.g. `tdb ./pkg`); otherwise an error naming `--lang`.
|
|
288
|
+
2. File extension: `.py` → Python; `.go` → Go; `.pl` / `.pm` / `.t` → Perl;
|
|
289
|
+
`.sh` / `.bash` → Bash; `.csh` / `.tcsh` → Tcsh; `.rb` → Ruby; `.ps1` /
|
|
290
|
+
`.psm1` → PowerShell. (`.ml` / `.mli` do *not* auto-select OCaml, see
|
|
291
|
+
point 6.)
|
|
292
|
+
3. Native executables (ELF, Mach-O, PE magic bytes) → C/C++, unless
|
|
293
|
+
byte-checking finds an OCaml marker (a native binary's
|
|
294
|
+
`caml_program`/`caml_startup` runtime symbols, a bytecode file's
|
|
295
|
+
trailing `Caml1999` marker, or a `#!...ocamlrun` shebang) → OCaml
|
|
296
|
+
(native or bytecode respectively), or a Go buildinfo blob (the marker
|
|
297
|
+
`go version` itself locates, scanned in the first 16MB of the file) →
|
|
298
|
+
Go. A stripped native OCaml binary, or a Go binary whose buildinfo
|
|
299
|
+
blob sits beyond the 16MB scan window, that byte-checking can't
|
|
300
|
+
identify falls back to C/C++; force it with `--lang ocaml` or `--lang
|
|
301
|
+
go` respectively. Rust is never inferred from an executable; select it
|
|
302
|
+
explicitly with `--lang rust`.
|
|
303
|
+
4. A `#!...python`, `#!...perl`, `#!...bash`, `#!...csh`/`#!...tcsh`,
|
|
304
|
+
`#!...ruby`, or `#!...pwsh` shebang → Python / Perl / Bash / Tcsh / Ruby /
|
|
305
|
+
PowerShell respectively.
|
|
306
|
+
5. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
270
307
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
271
|
-
|
|
308
|
+
6. `.ml` / `.mli` (OCaml source) produce an error too: build the project
|
|
309
|
+
first (dune's dev profile keeps debug info) and pass the **built
|
|
310
|
+
executable** to `tdb` (`tdb ./_build/default/bin/main.exe`), never the
|
|
311
|
+
`.ml` file.
|
|
312
|
+
7. Anything else produces an error naming the `--lang` override.
|
|
272
313
|
|
|
273
314
|
`--lang` forces the language; `--adapter` picks a non-default adapter within
|
|
274
|
-
it (`tdb --lang cpp --adapter lldb-dap ./myprog`).
|
|
315
|
+
it (`tdb --lang cpp --adapter lldb-dap ./myprog`). Rust always requires the
|
|
316
|
+
explicit language selection (`tdb --lang rust target/debug/app`).
|
|
275
317
|
|
|
276
318
|
> **Migration note:** extensionless Python scripts without a `python` shebang
|
|
277
319
|
> were previously assumed to be Python; they now require `--lang python`.
|
|
@@ -299,18 +341,28 @@ and the JSON-RPC / MCP programmatic modes.
|
|
|
299
341
|
|
|
300
342
|
Python-specific features are hidden or return "not supported for this
|
|
301
343
|
language" message when debugging other languages: statement-granularity
|
|
302
|
-
stepping (non-Python languages
|
|
303
|
-
|
|
344
|
+
stepping (non-Python languages step at their debugger's native granularity
|
|
345
|
+
— per line, except PowerShell, whose debugger stops per statement, see
|
|
346
|
+
[PowerShell](#powershell)), the async task / process inspectors and wait
|
|
347
|
+
graph, the evaluate console's trailing-`?` help,
|
|
304
348
|
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
305
349
|
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
306
350
|
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
307
|
-
[Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`),
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
351
|
+
[Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`), Ruby
|
|
352
|
+
(see [Ruby](#ruby), `rdbg --open` in place of `debugpy.listen()`), Go (see
|
|
353
|
+
[Go](#go), `dlv dap --listen` in place of `debugpy.listen()`), and for
|
|
354
|
+
Rust and C/C++ native binaries (against a gdbserver/lldb-server stub, with
|
|
355
|
+
a local symbol-bearing executable; see [Rust](#rust) — the same flags work
|
|
356
|
+
for a C/C++ target without `--lang`), but not for Bash, Tcsh, OCaml, or
|
|
357
|
+
PowerShell. `--terminal` works for every launch-mode
|
|
358
|
+
language — Python, Perl, Bash, Tcsh, Ruby, and C/C++, OCaml native, or Rust
|
|
359
|
+
sessions via `--adapter lldb-dap` — see
|
|
360
|
+
[External Terminal Support](#external-terminal-support). Go and PowerShell do
|
|
361
|
+
not support `--terminal` yet (`dlv dap` and PSES have no terminal-routing
|
|
362
|
+
mode).
|
|
311
363
|
|
|
312
364
|
**Bash limitations (v1):** the bash adapter uses bash's own `DEBUG` trap and
|
|
313
|
-
has a smaller feature
|
|
365
|
+
has a smaller feature set than Python:
|
|
314
366
|
|
|
315
367
|
- Debuggee code that installs its own `DEBUG` trap clobbers the harness;
|
|
316
368
|
debugging silently degrades to free-running.
|
|
@@ -354,9 +406,53 @@ paths and line numbers are preserved in everything tdb displays):
|
|
|
354
406
|
|
|
355
407
|
See [Tcsh](#tcsh) below for launch details.
|
|
356
408
|
|
|
409
|
+
**OCaml limitations (v1):** OCaml has two independent adapters with
|
|
410
|
+
different, non-overlapping gaps; see [OCaml](#ocaml) below for the full
|
|
411
|
+
picture:
|
|
412
|
+
|
|
413
|
+
- **Native (`lldb-dap`/`gdb`):** the Variables view shows no named OCaml
|
|
414
|
+
locals in an OCaml frame (only a `Registers` scope). This is an
|
|
415
|
+
upstream OCaml/DWARF limitation on stock OCaml 5.4, not a `tdb` bug; use
|
|
416
|
+
the bytecode adapter when you need to inspect locals. The evaluate
|
|
417
|
+
console evaluates lldb/C-level expressions (runtime spelunking), not
|
|
418
|
+
OCaml expressions.
|
|
419
|
+
- **Bytecode (`ocamlearlybird`):** single-domain only (no multicore); no
|
|
420
|
+
`pause` while running (so `--run` is unavailable); the evaluate console
|
|
421
|
+
never gets a response for any expression (an `ocamlearlybird` 1.3.6
|
|
422
|
+
limitation); and the fatal-error modal doesn't appear for an uncaught
|
|
423
|
+
exception (`ocamlearlybird` swallows the real exception text before it
|
|
424
|
+
reaches `tdb`). Run the program outside the debugger to see the
|
|
425
|
+
backtrace instead.
|
|
426
|
+
- No Windows support, no remote attach, and a stripped native binary that
|
|
427
|
+
byte-checking can't identify needs `--lang ocaml`.
|
|
428
|
+
|
|
429
|
+
**Go limitations (v1):**
|
|
430
|
+
|
|
431
|
+
- `--terminal` is not supported (`dlv dap` has no terminal-routing mode).
|
|
432
|
+
- The Goroutines workspace's wait graph shows channel-send/-receive,
|
|
433
|
+
mutex, and `WaitGroup` edges; a goroutine parked in a `select` is
|
|
434
|
+
classified but contributes no wait edge (Delve can't tell which of the
|
|
435
|
+
`select`'s cases it's waiting on).
|
|
436
|
+
- No mutex-holder identification: Go's `sync.Mutex` doesn't record an
|
|
437
|
+
owner at the runtime level, so unlike Python's Lock/Semaphore inspector
|
|
438
|
+
the wait graph can name what a goroutine is blocked on but never who
|
|
439
|
+
holds it.
|
|
440
|
+
- Goroutines spawned by `exec.Command` (child OS processes) are not
|
|
441
|
+
automatically attached or debugged, unlike Python's automatic
|
|
442
|
+
multiprocessing child attach.
|
|
443
|
+
- Detection of a Go binary via buildinfo check scans only the first
|
|
444
|
+
16MB of the file; a huge binary whose buildinfo blob sits beyond that
|
|
445
|
+
falls back to C/C++ — force it with `--lang go`.
|
|
446
|
+
- `-a`/`--attach`'s language auto-detection (reading the target pid's
|
|
447
|
+
buildinfo from `/proc/PID/exe`) is Linux-only; on macOS/Windows pass
|
|
448
|
+
`--lang go` alongside `-a`.
|
|
449
|
+
|
|
450
|
+
See [Go](#go) below for launch details.
|
|
451
|
+
|
|
357
452
|
### C/C++ tips
|
|
358
453
|
|
|
359
|
-
- Compile with `-g` (ideally `-g -O0`
|
|
454
|
+
- Compile with `-g` (ideally `-g -O0` or `-g3 -O0`).
|
|
455
|
+
If no breakpoint in a file can be
|
|
360
456
|
bound, `tdb` prints a console warning suggesting the program may lack
|
|
361
457
|
debug info.
|
|
362
458
|
- Stack frames pointing into system libraries often have no source on disk;
|
|
@@ -373,6 +469,72 @@ See [Tcsh](#tcsh) below for launch details.
|
|
|
373
469
|
requires `--adapter lldb-dap`; GDB's DAP mode has no terminal integration
|
|
374
470
|
and `tdb` refuses `--terminal` with the default `gdb` adapter.
|
|
375
471
|
|
|
472
|
+
### Rust
|
|
473
|
+
|
|
474
|
+
Rust debugging is intentionally explicit: build a normal debug executable,
|
|
475
|
+
leave it unmodified, and pass that executable with `--lang rust`. Linux and
|
|
476
|
+
macOS are supported; Windows is not yet (MSVC-toolchain binaries carry PDB
|
|
477
|
+
debug info that neither `gdb -i dap` nor this release's probes read). `tdb` does
|
|
478
|
+
not compile, instrument, or auto-detect Rust programs. Core debugging
|
|
479
|
+
(breakpoints, stepping, stacks, variables, remote attach) works with any
|
|
480
|
+
rustc that emits debug info; the concurrency inspector's layout-specific
|
|
481
|
+
*ownership evidence* additionally requires the current stable Rust
|
|
482
|
+
**1.98** standard-library layout — on other versions the workspace still
|
|
483
|
+
opens with stack-based wait classification and a compatibility warning.
|
|
484
|
+
Build with debug information and no optimization for the most useful
|
|
485
|
+
source locations:
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
cargo rustc -- -C debuginfo=2 -C opt-level=0
|
|
489
|
+
# Equivalent direct rustc settings: rustc -C debuginfo=2 -C opt-level=0 src/main.rs
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
A panic that terminates the debuggee opens the error modal with the parsed
|
|
493
|
+
panic message and backtrace; `tdb` injects `RUST_BACKTRACE=1` into launched
|
|
494
|
+
programs (your own value wins if you set one) so the frames are present.
|
|
495
|
+
|
|
496
|
+
The common commands are:
|
|
497
|
+
|
|
498
|
+
```bash
|
|
499
|
+
cargo build
|
|
500
|
+
tdb --lang rust target/debug/app
|
|
501
|
+
tdb --lang rust --adapter lldb-dap --run target/debug/app
|
|
502
|
+
tdb --lang rust --adapter lldb-dap --terminal xterm target/debug/app
|
|
503
|
+
tdb --lang rust --adapter gdb --remote-attach host:2345 target/debug/app
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
`--run` and normal stopped-on-entry launch work with both adapters. On Linux,
|
|
507
|
+
use GDB (the default) or `lldb-dap`; on macOS, use `lldb-dap` (the default).
|
|
508
|
+
External terminals are LLDB-only: GDB's DAP mode cannot provide terminal
|
|
509
|
+
integration. The mode/platform matrix is:
|
|
510
|
+
|
|
511
|
+
| Platform | Normal / `--run` | `--terminal` | `--remote-attach` |
|
|
512
|
+
|----------|------------------|--------------|-------------------|
|
|
513
|
+
| Linux | GDB or `lldb-dap` | `lldb-dap` only | GDB or `lldb-dap` |
|
|
514
|
+
| macOS | `lldb-dap` | `lldb-dap` only | `lldb-dap` |
|
|
515
|
+
|
|
516
|
+
Remote attach connects to a GDB-remote server already running on the target.
|
|
517
|
+
Pass the matching **local, unmodified executable with debug symbols** as the
|
|
518
|
+
program argument; `tdb` requires it for symbols and Rust concurrency evidence.
|
|
519
|
+
When source paths differ, pair `--local-root` with `--remote-root`. Do not
|
|
520
|
+
expose the remote debug port to an untrusted network: prefer an SSH tunnel,
|
|
521
|
+
for example `ssh -L 2345:127.0.0.1:2345 host`, then attach to `127.0.0.1:2345`.
|
|
522
|
+
|
|
523
|
+
In a Rust session the Threads action (`Alt+T`, or the Threads menu entry)
|
|
524
|
+
opens the Rust Concurrency workspace while the debuggee is stopped — a
|
|
525
|
+
fresh, bounded snapshot of threads, wait edges, and findings. The graph is
|
|
526
|
+
best effort: `confirmed` evidence is directly observed by the debugger,
|
|
527
|
+
`probable` is a supported inference, and `unknown` means ownership could not
|
|
528
|
+
be established. A deadlock is confirmed only when every edge in its cycle is
|
|
529
|
+
confirmed. A suspected cycle or whole-program stall is a diagnostic lead, not
|
|
530
|
+
a proof: it means a cycle has incomplete evidence, or all observed application
|
|
531
|
+
threads are blocked while the graph cannot safely invent an owner. Refresh
|
|
532
|
+
after the next stop to collect a new snapshot.
|
|
533
|
+
|
|
534
|
+
The built-in evidence recognizes current `std` synchronization layouts. A
|
|
535
|
+
future helper crate may expose stable, application-provided synchronization
|
|
536
|
+
metadata for broader primitives and stronger ownership evidence.
|
|
537
|
+
|
|
376
538
|
### Perl
|
|
377
539
|
|
|
378
540
|
`tdb` bundles its own Perl adapter (`perl-tdb`) so only need
|
|
@@ -549,6 +711,269 @@ text directly in the paused shell. It can inspect *and mutate* state
|
|
|
549
711
|
(`set name = value` takes effect immediately), and a syntax error in
|
|
550
712
|
evaluated text can terminate the debuggee; there is no isolation.
|
|
551
713
|
|
|
714
|
+
### Ruby
|
|
715
|
+
|
|
716
|
+
tdb debugs Ruby via the [debug gem](https://github.com/ruby/debug)'s
|
|
717
|
+
`rdbg` (Ruby >= 3.1 ships it; otherwise `gem install debug`; tdb needs
|
|
718
|
+
debug >= 1.9). `rdbg` must be on PATH, or point tdb at it with
|
|
719
|
+
`{"adapters": {"rdbg": "/path/to/rdbg"}}` in config.json.
|
|
720
|
+
|
|
721
|
+
```bash
|
|
722
|
+
tdb script.rb # launch, stop at first line
|
|
723
|
+
tdb --run script.rb # run immediately, debug on demand
|
|
724
|
+
tdb --terminal script.rb # program I/O in its own terminal
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Remote attach: start the program with
|
|
728
|
+
`rdbg --open --port 5678 --host 0.0.0.0 script.rb` (add `--nonstop` to
|
|
729
|
+
let it run before you attach), then `tdb -r HOST:5678 --lang ruby`.
|
|
730
|
+
Note: rdbg's `--cookie` authentication is not part of DAP and is not
|
|
731
|
+
supported; bind to localhost and tunnel over SSH instead.
|
|
732
|
+
`--local-root`/`--remote-root` path mappings are not supported for Ruby
|
|
733
|
+
yet. Bundler projects work when your environment resolves `rdbg`
|
|
734
|
+
(`gem install debug` into the project's Ruby); there is no `bundle
|
|
735
|
+
exec` integration yet.
|
|
736
|
+
|
|
737
|
+
> **Startup note:** the debug gem's `rdbg` has an occasional handshake
|
|
738
|
+
> race on launch; tdb detects a stalled/corrupted handshake and retries
|
|
739
|
+
> once automatically with a fresh `rdbg`, so this is usually invisible.
|
|
740
|
+
|
|
741
|
+
### OCaml
|
|
742
|
+
|
|
743
|
+
`tdb` debugs OCaml through two independent adapters, chosen automatically
|
|
744
|
+
from how the executable was built:
|
|
745
|
+
|
|
746
|
+
- **Native** (`ocamlopt`/dune's default build) → **`lldb-dap`** (default;
|
|
747
|
+
`--adapter gdb` also works). OCaml 5's domains show up as threads.
|
|
748
|
+
- **Bytecode** (`ocamlc -g`) → **`ocamlearlybird`** (`opam install
|
|
749
|
+
earlybird`). Single-domain only, but with rich, real OCaml locals.
|
|
750
|
+
|
|
751
|
+
**Build requirement:** compile with `-g` (dune's dev profile already
|
|
752
|
+
does). Always pass the **built executable** to `tdb`, never the `.ml`
|
|
753
|
+
source, as in `tdb ./_build/default/bin/main.exe`, not `tdb main.ml` (which
|
|
754
|
+
errors with this exact guidance).
|
|
755
|
+
|
|
756
|
+
Earlybird additionally as a fragile relative path matching so for
|
|
757
|
+
best results provide a fully quallified path to the source files.
|
|
758
|
+
|
|
759
|
+
```
|
|
760
|
+
ocamlc -g -o my_program.byte "$PWD/my_program.ml"
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Then, to ensure transition from bytecode to OCaml source in the
|
|
764
|
+
Code view, provide an explicit temporary breakpoint (`-t`)
|
|
765
|
+
at the first line of execution:
|
|
766
|
+
|
|
767
|
+
```
|
|
768
|
+
tdb --lang ocaml --adapter ocamlearlybird -t "$PWD/my_program.ml:2" ./my_program.byte
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
**OCaml version:** tdb requires **OCaml ≥ 4.12**. Older runtimes print
|
|
772
|
+
`Printexc` backtraces without function names, which the fatal-error
|
|
773
|
+
modal's parser does not understand (frames would be dropped and the
|
|
774
|
+
modal would wrongly suggest recompiling with `-g`).
|
|
775
|
+
|
|
776
|
+
With native GDB, the default entry stop is translated to the first
|
|
777
|
+
executable line in project OCaml source; the generated C/ELF startup code is
|
|
778
|
+
not shown.
|
|
779
|
+
Unfortunately OCaml's native debug information does not always identify
|
|
780
|
+
tihs line correctly.
|
|
781
|
+
`--no-stop-on-entry` and explicit CLI breakpoints retain their
|
|
782
|
+
usual behavior.
|
|
783
|
+
|
|
784
|
+
A stripped native binary that byte-checking can't identify as OCaml falls
|
|
785
|
+
back to C/C++; force it with `--lang ocaml`. Override the adapter or point
|
|
786
|
+
at a non-`PATH` install in `config.json` (see
|
|
787
|
+
[Configuration](#configuration)):
|
|
788
|
+
|
|
789
|
+
```json
|
|
790
|
+
{
|
|
791
|
+
"adapters": {"ocamlearlybird": "/path/to/ocamlearlybird"},
|
|
792
|
+
"default_adapters": {"ocaml": "gdb"}
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
**Domains as threads (native only):** OCaml 5's domains are presented in
|
|
797
|
+
the Threads modal (`Alt+T` or the **Threads (N)** menu label) as `Domain 0
|
|
798
|
+
(main)`, `Domain 1`, and so on, in creation order. The runtime's internal
|
|
799
|
+
"backup thread" (one per domain, used for I/O blocking) is hidden by
|
|
800
|
+
default since it's never running user code; press `a` in the Threads
|
|
801
|
+
modal to reveal it alongside the domains. Breakpoints, stepping, continue,
|
|
802
|
+
and pause all work normally against any domain. In both the Stack view
|
|
803
|
+
and the Threads modal, OCaml frame names are demangled from the
|
|
804
|
+
runtime's raw `camlModule__name_NNN` convention into readable
|
|
805
|
+
`Module.name` form (e.g. `camlOcaml_domains.worker_297` displays as
|
|
806
|
+
`Ocaml_domains.worker`); runtime C frames (`caml_start_program`,
|
|
807
|
+
`caml_callback_exn`, and the like) are shown as-is, unchanged.
|
|
808
|
+
|
|
809
|
+
**Variables view (native):** stock OCaml 5.4 native DWARF shows **no
|
|
810
|
+
named locals**. The `scopes`/`variables` round trip succeeds, but every
|
|
811
|
+
OCaml frame's `Locals` and `Globals` scopes come back empty; only a
|
|
812
|
+
`Registers` scope has data (the raw register file, not decoded OCaml
|
|
813
|
+
values). This is an upstream OCaml compiler/DWARF limitation on the
|
|
814
|
+
verified toolchain (OCaml 5.4.0 / lldb 21), not a `tdb` bug. If you need
|
|
815
|
+
to inspect local variables, use the bytecode adapter instead.
|
|
816
|
+
|
|
817
|
+
**Variables view (bytecode):** `ocamlearlybird` reports real local names
|
|
818
|
+
and values, exactly like Python locals.
|
|
819
|
+
|
|
820
|
+
**Evaluate console:** the two adapters give fundamentally different
|
|
821
|
+
consoles. Native (`lldb-dap`) evaluates **lldb/C-level expressions**.
|
|
822
|
+
This is runtime spelunking (registers, raw memory, C symbol names), not
|
|
823
|
+
OCaml expression evaluation. Bytecode (`ocamlearlybird`) is meant to
|
|
824
|
+
evaluate real OCaml expressions in scope, but in the verified
|
|
825
|
+
`ocamlearlybird` 1.3.6 release its `evaluate` request never responds (a
|
|
826
|
+
confirmed upstream limitation, not specific to `tdb`); the console
|
|
827
|
+
silently returns nothing for any expression.
|
|
828
|
+
|
|
829
|
+
**Uncaught exceptions:** native sessions set a breakpoint on
|
|
830
|
+
`caml_fatal_uncaught_exception` so the debugger stops there, and `tdb`
|
|
831
|
+
also parses the `OCAMLRUNPARAM=b` backtrace it injects into the debuggee's
|
|
832
|
+
environment once the process exits, opening the same error modal Python
|
|
833
|
+
tracebacks get. Bytecode sessions do **not** get this: `ocamlearlybird`
|
|
834
|
+
intercepts the uncaught exception itself and only reports a generic
|
|
835
|
+
"Program exited due to Uncaught_exc" message, so the real exception text
|
|
836
|
+
never reaches `tdb`. Run the program outside the debugger
|
|
837
|
+
(`OCAMLRUNPARAM=b ./main.byte`) to see its backtrace.
|
|
838
|
+
|
|
839
|
+
**Limitations (v1):** no Windows support; no remote attach; bytecode
|
|
840
|
+
sessions can't `pause` a running program (so `--run` is unavailable for
|
|
841
|
+
bytecode. Native sessions support `--run` normally); `Unix.fork` and Eio
|
|
842
|
+
fibers are out of scope (only OCaml 5 domains are presented as threads).
|
|
843
|
+
|
|
844
|
+
### Go
|
|
845
|
+
|
|
846
|
+
`tdb` debugs Go through [Delve](https://github.com/go-delve/delve)'s own
|
|
847
|
+
DAP server, `dlv dap` (Delve ≥ 1.21). Install it with:
|
|
848
|
+
|
|
849
|
+
```bash
|
|
850
|
+
go install github.com/go-delve/delve/cmd/dlv@latest
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
`dlv` must be on `PATH`, or point tdb at it with
|
|
854
|
+
`{"adapters": {"dlv": "/path/to/dlv"}}` in `config.json`.
|
|
855
|
+
|
|
856
|
+
**Launch modes** — `tdb` picks the right Delve mode automatically:
|
|
857
|
+
|
|
858
|
+
```bash
|
|
859
|
+
tdb main.go # source file: `go run`-style debug mode
|
|
860
|
+
tdb ./pkg # package directory: `go run`-style debug mode
|
|
861
|
+
tdb ./binary # pre-built Go binary (buildinfo-detected): exec mode
|
|
862
|
+
tdb --test ./pkg # Go test package: Delve test mode
|
|
863
|
+
tdb -a PID # attach to a running local Go process by pid
|
|
864
|
+
tdb -r host:port --lang go # attach to a `dlv dap --listen` already running remotely
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
`tdb --test ./pkg` debugs the package's tests under Delve's `test` mode;
|
|
868
|
+
pass test-binary flags after `--`, e.g. `tdb --test ./pkg -- -run TestFoo`.
|
|
869
|
+
`-a`/`--attach` currently supports Go only; on Linux, and only on Linux,
|
|
870
|
+
`tdb` can identify the target as Go from `/proc/PID/exe`'s buildinfo
|
|
871
|
+
without `--lang` (elsewhere pass `--lang go` alongside `-a`). Attaching
|
|
872
|
+
stops the process immediately so you get control right away.
|
|
873
|
+
|
|
874
|
+
**Remote attach:** start Delve's own DAP server against your program
|
|
875
|
+
first —
|
|
876
|
+
|
|
877
|
+
```bash
|
|
878
|
+
dlv dap --listen=host:port ./binary
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
— then connect from `tdb`:
|
|
882
|
+
|
|
883
|
+
```bash
|
|
884
|
+
tdb -r host:port --lang go
|
|
885
|
+
```
|
|
886
|
+
|
|
887
|
+
Do not expose the port to an untrusted network; prefer an SSH tunnel.
|
|
888
|
+
|
|
889
|
+
**Goroutine inspection:** in a Go session the Threads action (`Alt+T`, or
|
|
890
|
+
the **Goroutines (N)** menu label) opens the Goroutines workspace while
|
|
891
|
+
the debuggee is stopped — a fresh, bounded snapshot of goroutines, wait
|
|
892
|
+
edges, and findings, the same shape as the Rust Concurrency workspace.
|
|
893
|
+
Goroutines parked entirely in Go-runtime internals (GC workers,
|
|
894
|
+
finalizers, netpoll) are hidden by default; press `a` to reveal them
|
|
895
|
+
alongside the rest. The **Wait Graph** tab groups goroutines by the
|
|
896
|
+
channel, mutex, or `WaitGroup` they're blocked on; the **Findings** tab
|
|
897
|
+
surfaces stuck channels, mutex convoys, and likely leaks with a
|
|
898
|
+
confidence level (`confirmed` vs `probable`) — Go mutexes never record an
|
|
899
|
+
owner, so, unlike Python's Lock/Semaphore inspector, findings can name
|
|
900
|
+
what's blocked but not who holds it. The snapshot collects up to 150
|
|
901
|
+
goroutines; a busier program reports the header
|
|
902
|
+
`Goroutines (150) — N more not collected` rather than silently truncating.
|
|
903
|
+
Refresh (`r`) after the next stop to collect a new snapshot.
|
|
904
|
+
|
|
905
|
+
**Limitations (v1):** `--terminal` is not supported (`dlv dap` has no
|
|
906
|
+
terminal-routing mode); a goroutine parked in a `select` is classified but
|
|
907
|
+
contributes no wait edge (Delve can't tell which case it's waiting on);
|
|
908
|
+
no mutex-holder identification (impossible for Go's runtime); goroutines
|
|
909
|
+
spawned indirectly via `exec.Command` child OS processes are not
|
|
910
|
+
automatically attached; buildinfo-based binary detection scans only the
|
|
911
|
+
first 16MB of the file (`--lang go` overrides for anything larger); `-a`'s
|
|
912
|
+
`/proc`-based language auto-detection is Linux-only (pass `--lang go`
|
|
913
|
+
alongside `-a` on macOS/Windows).
|
|
914
|
+
|
|
915
|
+
### PowerShell
|
|
916
|
+
|
|
917
|
+
tdb debugs PowerShell 7 scripts through [PowerShell Editor Services](https://github.com/PowerShell/PowerShellEditorServices)
|
|
918
|
+
(PSES), the Debug Adapter Protocol server behind the VS Code PowerShell
|
|
919
|
+
extension. You need `pwsh` (>= 7.2; https://aka.ms/powershell) on PATH
|
|
920
|
+
and the PSES module. tdb looks for the module in this order:
|
|
921
|
+
|
|
922
|
+
1. `{"adapters": {"pses": "/path/to/PowerShellEditorServices"}}` in `config.json`
|
|
923
|
+
2. the `TDB_PSES_PATH` environment variable
|
|
924
|
+
3. the copy bundled with an installed VS Code PowerShell extension
|
|
925
|
+
(`~/.vscode/extensions/ms-vscode.powershell-*/modules/PowerShellEditorServices`)
|
|
926
|
+
|
|
927
|
+
Without VS Code, download the release once:
|
|
928
|
+
|
|
929
|
+
```bash
|
|
930
|
+
mkdir -p ~/.local/share/tdb/pses && cd ~/.local/share/tdb/pses
|
|
931
|
+
curl -sLO https://github.com/PowerShell/PowerShellEditorServices/releases/download/v4.7.0/PowerShellEditorServices.zip
|
|
932
|
+
unzip -q PowerShellEditorServices.zip
|
|
933
|
+
export TDB_PSES_PATH=~/.local/share/tdb/pses/PowerShellEditorServices
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
A `pwsh` that isn't on PATH can be named with `{"adapters": {"pwsh": "/path/to/pwsh"}}`.
|
|
937
|
+
|
|
938
|
+
```bash
|
|
939
|
+
tdb script.ps1 # launch, stop at the first statement
|
|
940
|
+
tdb --run script.ps1 # run immediately, debug on demand (pause works)
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
Notes:
|
|
944
|
+
|
|
945
|
+
- Entry stop lands on the first statement of your script (comments and
|
|
946
|
+
function definitions are skipped): PSES has no native `stopOnEntry` for
|
|
947
|
+
this launch shape, so tdb sets a synthetic breakpoint on the bundled
|
|
948
|
+
launcher, steps in, and clears it — no line-1 breakpoint appears in the
|
|
949
|
+
Breakpoint view.
|
|
950
|
+
- The script runs inside that small bundled launcher (`tdb_launch.ps1`) so
|
|
951
|
+
tdb can report the script's exit code. In the Stack view, top to bottom:
|
|
952
|
+
PSES's `<Breakpoint>` marker frame (the frame to inspect — it tracks the
|
|
953
|
+
accurate current position), your script's own frames, the launcher's
|
|
954
|
+
`<ScriptBlock>`, and a source-less `Interactive Session` frame at the
|
|
955
|
+
bottom.
|
|
956
|
+
- Stepping is statement-granular, as in VS Code: a line containing a
|
|
957
|
+
`$( ... )` subexpression takes two `next` presses to clear, and `stepIn`
|
|
958
|
+
first lands on the called function's declaration line before its body.
|
|
959
|
+
- An uncaught terminating error ends the script with exit code 1 and opens
|
|
960
|
+
the fatal-error modal from pwsh's concise error text. Non-terminating
|
|
961
|
+
errors (`Write-Error`, failing cmdlets without `-ErrorAction Stop`) print
|
|
962
|
+
the same concise error block to the Console as stderr and let the script
|
|
963
|
+
continue with exit code 0, as in pwsh itself; there is no break-on-error
|
|
964
|
+
yet. The error block names the launcher's `& $Script` line rather than
|
|
965
|
+
your script's actual line for some error kinds (a known cosmetic
|
|
966
|
+
limitation).
|
|
967
|
+
- The fatal-error modal is gated on a non-zero exit code, since pwsh prints
|
|
968
|
+
the identical block for terminating and non-terminating errors. A script
|
|
969
|
+
that reports a non-terminating error and then `exit 3` can therefore still
|
|
970
|
+
raise the modal, showing the last error block that names a file of yours;
|
|
971
|
+
blocks attributed to tdb's own `tdb_launch.ps1` are skipped, so a bare
|
|
972
|
+
`Write-Error` before the `exit` opens no modal at all.
|
|
973
|
+
- `--terminal` and remote attach are not supported for PowerShell yet.
|
|
974
|
+
- Windows PowerShell 5.1 is not supported (pwsh 7 only). Running tdb *on*
|
|
975
|
+
Windows against pwsh is designed for but not yet verified (experimental).
|
|
976
|
+
|
|
552
977
|
## Layout
|
|
553
978
|
|
|
554
979
|
```
|
|
@@ -604,6 +1029,11 @@ A cursor line (blue) tracks your position; the current execution line is highlig
|
|
|
604
1029
|
| `Alt+A` | Async Tasks |
|
|
605
1030
|
| `Alt+H` | Help (Documentation, About) |
|
|
606
1031
|
|
|
1032
|
+
File > Open works for every supported language: the file picker filters to
|
|
1033
|
+
the current session's language (by extension) and refuses a pick that
|
|
1034
|
+
detects as a different language, so you can only switch to another script
|
|
1035
|
+
written in the same language as the one currently being debugged.
|
|
1036
|
+
|
|
607
1037
|
**Navigation (vim-style by default):**
|
|
608
1038
|
|
|
609
1039
|
By default the Code View is in Debug mode. Hit `Escape` to switch to Navigate mode
|
|
@@ -661,7 +1091,7 @@ results = await asyncio.gather(
|
|
|
661
1091
|
fetch(2, 1),
|
|
662
1092
|
fetch(3, 3),
|
|
663
1093
|
)
|
|
664
|
-
print(results)
|
|
1094
|
+
print(results) # next stop lands here, not on each sub-line above
|
|
665
1095
|
```
|
|
666
1096
|
|
|
667
1097
|
lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
|
|
@@ -670,7 +1100,9 @@ stops on each physical line--useful for inspecting how a complex expression is b
|
|
|
670
1100
|
The choice is saved to `~/.config/tdb/config.json`.
|
|
671
1101
|
|
|
672
1102
|
Statement mode requires a source-language model and is currently Python-only;
|
|
673
|
-
other languages
|
|
1103
|
+
other languages step at their debugger's native granularity — per line,
|
|
1104
|
+
except PowerShell, whose debugger stops per statement, see
|
|
1105
|
+
[PowerShell](#powershell) (the Step Mode menu says so if you try).
|
|
674
1106
|
|
|
675
1107
|
### Breakpoints
|
|
676
1108
|
|
|
@@ -771,6 +1203,7 @@ need to launch through `tdb` up front. Install the hook once at the top of your
|
|
|
771
1203
|
```python
|
|
772
1204
|
import sys
|
|
773
1205
|
import tdb
|
|
1206
|
+
|
|
774
1207
|
sys.excepthook = tdb.exception_hook
|
|
775
1208
|
```
|
|
776
1209
|
|
|
@@ -819,6 +1252,7 @@ continuing--use `tdb.breakpoint()`:
|
|
|
819
1252
|
```python
|
|
820
1253
|
import tdb
|
|
821
1254
|
|
|
1255
|
+
|
|
822
1256
|
def compute(n):
|
|
823
1257
|
total = sum(range(n))
|
|
824
1258
|
tdb.breakpoint() # pause here and drop into tdb
|
|
@@ -961,6 +1395,7 @@ where you want to attach the debugger:
|
|
|
961
1395
|
```python
|
|
962
1396
|
# In the target program:
|
|
963
1397
|
import debugpy
|
|
1398
|
+
|
|
964
1399
|
debugpy.listen(("0.0.0.0", 5678))
|
|
965
1400
|
print("Waiting for tdb to attach on port 5678...")
|
|
966
1401
|
debugpy.wait_for_client() # optional: pause until debugger connects
|
|
@@ -1028,15 +1463,19 @@ tdb --terminal xterm my_tui_app.py
|
|
|
1028
1463
|
```
|
|
1029
1464
|
|
|
1030
1465
|
`--terminal` works for every language `tdb` can *launch* (as opposed to
|
|
1031
|
-
attach to): Python, Perl, Bash, Tcsh, and C/C++
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1466
|
+
attach to): Python, Perl, Bash, Tcsh, Ruby, and C/C++ or native OCaml
|
|
1467
|
+
sessions via `--adapter lldb-dap`. Neither `gdb -i dap` (the default C/C++
|
|
1468
|
+
adapter, and an alternate for native OCaml) nor `ocamlearlybird` (the
|
|
1469
|
+
bytecode OCaml adapter) has any terminal integration -- `tdb` rejects
|
|
1470
|
+
`--terminal` up front for both, with an error pointing at `--adapter
|
|
1471
|
+
lldb-dap` instead. Go and PowerShell don't support `--terminal` either
|
|
1472
|
+
(`dlv dap` has no terminal-routing mode; PSES likewise). `--terminal` also
|
|
1473
|
+
only applies when `tdb` launches the program itself; it is rejected for
|
|
1474
|
+
remote-attach (`-r`), since there's no program for `tdb` to spawn a
|
|
1475
|
+
terminal around.
|
|
1037
1476
|
|
|
1038
1477
|
The debuggee runs in a separate window of the specified terminal, including
|
|
1039
|
-
all of its stdin/stdout/stderr
|
|
1478
|
+
all of its stdin/stdout/stderr. Keyboard input, program output, and
|
|
1040
1479
|
anything the program itself draws to the terminal all happen in that
|
|
1041
1480
|
window, not in `tdb`'s Console View. Supported choices:
|
|
1042
1481
|
`xterm`, `konsole`, `gnome-terminal`, `ghostty`, `kitty`, `iterm2`, `warp`,
|
|
@@ -1048,9 +1487,17 @@ This feature only works in graphical environments where external terminals are a
|
|
|
1048
1487
|
|
|
1049
1488
|
### Run Mode (`--run`)
|
|
1050
1489
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1490
|
+
`tdb`'s run mode invokes an unmodified program nearly at full speed, without bringing up the TUI.
|
|
1491
|
+
At any point afterwards, hitting `Ctrl-C` in that terminal pauses the program
|
|
1492
|
+
and drops you into the full TUI.
|
|
1493
|
+
From there you can inspect the program's state, navigate the stack, set and continue
|
|
1494
|
+
to breakpoints, and so on. After you finish inspecting, hitting `q` to quit brings up
|
|
1495
|
+
a modal that lets you either detach from the TUI and let the program resume running,
|
|
1496
|
+
or lets you terminate it.
|
|
1497
|
+
|
|
1498
|
+
The primary use cases for run mode are: (1) allowing inspection of a program that
|
|
1499
|
+
appears hung, and (2) finding where a program execution path lands after it
|
|
1500
|
+
receives a problematic input.
|
|
1054
1501
|
|
|
1055
1502
|
```bash
|
|
1056
1503
|
tdb --run my_program.py args...
|
|
@@ -1066,7 +1513,7 @@ tdb --run my_program.py; echo $? # my_program.py's own exit code
|
|
|
1066
1513
|
**Interrupting:** press Ctrl-C in the terminal (any platform), or, on Unix, send
|
|
1067
1514
|
`SIGUSR1` to `tdb`'s pid from another terminal: `kill -USR1 <tdb pid>`. Either one pauses
|
|
1068
1515
|
the debuggee at its currently executing line and opens the TUI with full debugging
|
|
1069
|
-
available
|
|
1516
|
+
available (breakpoints, stepping, variable inspection, the evaluate console). The
|
|
1070
1517
|
debuggee itself never receives the signal (`tdb`'s adapter runs in its own process
|
|
1071
1518
|
group), so its own `SIGINT` handling is undisturbed.
|
|
1072
1519
|
|
|
@@ -1084,8 +1531,11 @@ nonzero `sys.exit()`, which `debugpy` treats as an uncaught `SystemExit` -- `tdb
|
|
|
1084
1531
|
the TUI at the point of failure instead of exiting silently, so you can inspect the
|
|
1085
1532
|
crash. Exit-code passthrough applies only to a clean exit during the headless phase.
|
|
1086
1533
|
|
|
1087
|
-
Supported languages: Python, Perl, Bash, Tcsh,
|
|
1088
|
-
|
|
1534
|
+
Supported languages: Python, Perl, Bash, Tcsh, Ruby, PowerShell 7, C/C++
|
|
1535
|
+
(both `gdb` and `lldb-dap`), and native OCaml (both `gdb` and `lldb-dap`;
|
|
1536
|
+
bytecode/`ocamlearlybird` sessions don't support pause, so `--run` is
|
|
1537
|
+
unavailable for those). `--run` is rejected up front for any other
|
|
1538
|
+
language.
|
|
1089
1539
|
|
|
1090
1540
|
**Limitation:** pausing is cooperative. If the debuggee is blocked inside a single
|
|
1091
1541
|
blocking external call or syscall, the pause can't land until that call returns --
|
|
@@ -1094,6 +1544,48 @@ blocking external call or syscall, the pause can't land until that call returns
|
|
|
1094
1544
|
**Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--server`,
|
|
1095
1545
|
`--headless`, `--mcp`, `--terminal`.
|
|
1096
1546
|
|
|
1547
|
+
### Eval Mode (`-e`/`--eval`)
|
|
1548
|
+
|
|
1549
|
+
Eval mode automates a common debugging loop--set a breakpoint, run to it,
|
|
1550
|
+
evaluate an expression in the Evaluate console, continue--without
|
|
1551
|
+
opening the TUI. `-e` takes two arguments, a location and an expression:
|
|
1552
|
+
|
|
1553
|
+
```bash
|
|
1554
|
+
tdb --eval examples/digits_of_pi.py:25 "print(f'{nr=}')" examples/digits_of_pi.py
|
|
1555
|
+
```
|
|
1556
|
+
|
|
1557
|
+
sets a breakpoint at line 25, runs the program, and each time that line is
|
|
1558
|
+
reached evaluates `print(f'{nr=}')` in the stopped frame, then continues.
|
|
1559
|
+
Program output and evaluation output both stream to the terminal; when the
|
|
1560
|
+
program exits, `tdb` exits with the same code (and with `1` if the session
|
|
1561
|
+
ends without one--as with a crash or killed adapter--so a scripted `tdb -e ...
|
|
1562
|
+
&& next` can trust the exit status). `Ctrl-C` stops the program and exits
|
|
1563
|
+
`130`. Under `multiprocessing`, an eval point placed in child code is
|
|
1564
|
+
evaluated in each child process that reaches it.
|
|
1565
|
+
|
|
1566
|
+
- The location is `FILE:LINE`, or a bare `LINE` of the program being debugged,
|
|
1567
|
+
and is snapped to the start of a logical statement just like `-k`.
|
|
1568
|
+
- `-e` may be repeated to plant several eval points in one run.
|
|
1569
|
+
- The expression is evaluated through the debug adapter (DAP `evaluate`,
|
|
1570
|
+
context `repl`), just like the Evaluate console: side effects are real
|
|
1571
|
+
and persist in the running program, for example
|
|
1572
|
+
`-e my_program.py:25 "limit = 10"` changes `limit` from line 25 onward.
|
|
1573
|
+
- A bare expression's result is printed to stdout; statement-style
|
|
1574
|
+
expressions (`print(...)`, assignments) print nothing beyond their own
|
|
1575
|
+
output. An expression error is reported on stderr and the run continues --
|
|
1576
|
+
a typo isn't fatal, matching the Evaluate console.
|
|
1577
|
+
- Saved breakpoints are ignored, and any other stop (e.g. an
|
|
1578
|
+
uncaught-exception stop) is continued untouched, so the program runs to
|
|
1579
|
+
completion unattended.
|
|
1580
|
+
- For non-Python debuggees the expression must be in the debug adapter's
|
|
1581
|
+
own syntax, for example gdb's `print x` / `set var x=3` for C/C++, and not
|
|
1582
|
+
necessarily the debuggee's language. The adapter may bind the breakpoint
|
|
1583
|
+
to the next executable line (gdb moves one off a declaration or brace);
|
|
1584
|
+
the eval point matches that bound line, so the expression still runs.
|
|
1585
|
+
|
|
1586
|
+
**Incompatible flags:** `--run`, `-r`, `-a`, `-k`/`-t`, `--record`,
|
|
1587
|
+
`--replay`, `--server`, `--headless`, `--mcp`, `--terminal`.
|
|
1588
|
+
|
|
1097
1589
|
### Keybinding Schemes
|
|
1098
1590
|
|
|
1099
1591
|
```bash
|
|
@@ -1129,7 +1621,9 @@ Both the interactive TUI and the JSON-RPC server run simultaneously.
|
|
|
1129
1621
|
### RPC Protocol
|
|
1130
1622
|
|
|
1131
1623
|
Send POST requests with `{"action": "...", "params": [...]}`. Responses return
|
|
1132
|
-
`{"timestamp": "...", "success": true/false, "value": "..."}`.
|
|
1624
|
+
`{"timestamp": "...", "success": true/false, "value": "..."}`. Actions with a
|
|
1625
|
+
structured result (today only `rust_concurrency`) additionally carry a `data`
|
|
1626
|
+
object holding the full JSON payload; `value` then holds a one-line summary.
|
|
1133
1627
|
|
|
1134
1628
|
```bash
|
|
1135
1629
|
# Check status
|
|
@@ -1187,6 +1681,7 @@ curl -s -X POST http://127.0.0.1:8150/rpc \
|
|
|
1187
1681
|
| `list_tasks` | `[]` | List all asyncio tasks |
|
|
1188
1682
|
| `inspect_task` | `["task_name"]` | Inspect a specific asyncio task |
|
|
1189
1683
|
| `wait_graph` | `[]` | Show wait graph + any deadlock cycles |
|
|
1684
|
+
| `rust_concurrency` | `[]` | Structured Rust thread/wait/deadlock snapshot in `data` (Rust sessions, stopped) |
|
|
1190
1685
|
| `restart` | `[]` | Restart session (preserves breakpoints) |
|
|
1191
1686
|
| `quit` | `[]` | Shut down |
|
|
1192
1687
|
|
|
@@ -1269,7 +1764,7 @@ point), `tdb --mcp` (the main CLI with the `--mcp` switch), and
|
|
|
1269
1764
|
`python -m tdb.mcp` (module form). Pick whichever matches how your MCP
|
|
1270
1765
|
client expects to launch servers.
|
|
1271
1766
|
|
|
1272
|
-
### Tool surface (
|
|
1767
|
+
### Tool surface (17 tools, curated)
|
|
1273
1768
|
|
|
1274
1769
|
| Cluster | Tools |
|
|
1275
1770
|
|---------|-------|
|
|
@@ -1277,7 +1772,7 @@ client expects to launch servers.
|
|
|
1277
1772
|
| Control | `control(action, timeout_s=30)` where `action ∈ {continue, next, step_in, step_out, pause, wait_for_stop}` |
|
|
1278
1773
|
| Inspection | `inspect(expressions)`, `read_source(file_path)`, `stack_trace()`, `status()`, `get_output()` |
|
|
1279
1774
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
1280
|
-
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
1775
|
+
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()`, `rust_concurrency()` |
|
|
1281
1776
|
|
|
1282
1777
|
`control` is intentionally one tool that takes an action enum. The six
|
|
1283
1778
|
underlying RPC actions share a return shape, and agents perform
|
|
@@ -1288,9 +1783,10 @@ single optional argument for the same reason.
|
|
|
1288
1783
|
`debug_launch` accepts optional `lang` and `adapter` parameters mirroring the
|
|
1289
1784
|
CLI's `--lang`/`--adapter`; when omitted, the language is auto-detected from
|
|
1290
1785
|
`program`, so an agent can hand it a compiled binary directly. The
|
|
1291
|
-
|
|
1786
|
+
exception is Rust: compiled native binaries require explicit `lang="rust"`.
|
|
1787
|
+
The `tasks`/`processes`/`wait_graph` tools stay registered for every language but
|
|
1292
1788
|
return a structured "not supported when debugging C/C++"-style error for
|
|
1293
|
-
non-Python debuggees.
|
|
1789
|
+
non-Python debuggees; `rust_concurrency` does the same for non-Rust debuggees.
|
|
1294
1790
|
|
|
1295
1791
|
### Agent flow for a long-running step
|
|
1296
1792
|
|
|
@@ -1385,6 +1881,10 @@ found; it's Python code, not an external executable), so
|
|
|
1385
1881
|
`{"adapters": {"perl": "/path/to/perl"}}`. Use this when the `perl` on
|
|
1386
1882
|
`PATH` is too old (< 5.18) or you need a specific `perlbrew`/`plenv` version.
|
|
1387
1883
|
|
|
1884
|
+
**PowerShell** follows the same pattern with two keys: `adapters.pwsh` names
|
|
1885
|
+
the interpreter and `adapters.pses` names the PowerShell Editor Services
|
|
1886
|
+
module directory (see [PowerShell](#powershell)).
|
|
1887
|
+
|
|
1388
1888
|
Breakpoints are saved on exit and restored when debugging a program in the same
|
|
1389
1889
|
directory. Each project's breakpoints are independent. Breakpoints set with
|
|
1390
1890
|
`-t`/`--to-line` are the exception: they behave like `-k` breakpoints during
|
|
@@ -1408,6 +1908,8 @@ fires as expected.
|
|
|
1408
1908
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
1409
1909
|
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation for Python
|
|
1410
1910
|
- [gdb](https://sourceware.org/gdb/) / [lldb-dap](https://lldb.llvm.org/resources/lldbdap.html) : optional, user-installed DAP adapters for C/C++
|
|
1911
|
+
- [debug gem](https://github.com/ruby/debug) (`rdbg`) : optional, user-installed DAP adapter for Ruby
|
|
1912
|
+
- [ocamlearlybird](https://github.com/hackwaly/ocamlearlybird) : optional, user-installed DAP adapter for OCaml bytecode (native OCaml reuses `gdb`/`lldb-dap`)
|
|
1411
1913
|
- [pygments](https://pygments.org/) : Syntax highlighting
|
|
1412
1914
|
- [FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/) : JSON-RPC server
|
|
1413
1915
|
|