textual-debugger 0.2.4__tar.gz → 0.2.8__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.4 → textual_debugger-0.2.8}/PKG-INFO +360 -38
- {textual_debugger-0.2.4/src/tdb → textual_debugger-0.2.8}/README.md +359 -37
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/pyproject.toml +2 -1
- {textual_debugger-0.2.4 → textual_debugger-0.2.8/src/tdb}/README.md +359 -37
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/__init__.py +1 -1
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/server.py +114 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/session.py +139 -35
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/tdb_harness.sh +15 -5
- textual_debugger-0.2.8/src/tdb/adapters/ocaml/lldb_formatters.py +153 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/helpers.pl +22 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/server.py +235 -15
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/session.py +100 -19
- textual_debugger-0.2.8/src/tdb/adapters/ruby/__init__.py +1 -0
- textual_debugger-0.2.8/src/tdb/adapters/ruby/__main__.py +23 -0
- textual_debugger-0.2.8/src/tdb/adapters/ruby/server.py +1120 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/breakpoints.py +8 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/guardian.py +210 -40
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/inspect.py +9 -3
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/instrumenter.py +20 -6
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/models.py +1 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/runtime.py +15 -5
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/server.py +275 -15
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/session.py +442 -87
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/transport.py +107 -21
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app.py +131 -19
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_handlers/dap_events.py +3 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_handlers/inspection.py +101 -1
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_handlers/routing.py +36 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_handlers/ui_panels.py +39 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/cli.py +106 -5
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/dap/client.py +16 -1
- textual_debugger-0.2.8/src/tdb/dap/reverse.py +54 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/base.py +69 -1
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/bash.py +5 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/cpp.py +61 -7
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/errors.py +216 -0
- textual_debugger-0.2.8/src/tdb/languages/ocaml.py +324 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/perl.py +5 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/python.py +7 -4
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/registry.py +71 -9
- textual_debugger-0.2.8/src/tdb/languages/ruby.py +117 -0
- textual_debugger-0.2.8/src/tdb/languages/rust.py +158 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/tcsh.py +5 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/mcp/server.py +41 -9
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/mcp/session.py +29 -5
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/replay.py +12 -2
- textual_debugger-0.2.8/src/tdb/run_mode.py +271 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/__init__.py +41 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/analyzer.py +505 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/classifier.py +255 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/collector.py +337 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/models.py +269 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/__init__.py +18 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/base.py +166 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/gdb.py +27 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/gdb_script.py +238 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/lldb.py +35 -0
- textual_debugger-0.2.8/src/tdb/rust_concurrency/probes/lldb_script.py +276 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/server/app.py +1 -1
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/server/handlers.py +21 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/server/rpc_types.py +17 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/server/runner.py +15 -3
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/controller.py +143 -13
- textual_debugger-0.2.8/src/tdb/session/errors.py +23 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/event_bus.py +49 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/inspect_service.py +24 -15
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/recorder.py +3 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/state.py +2 -0
- textual_debugger-0.2.8/src/tdb/widgets/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/_inspection_modal.py +11 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/modals.py +65 -10
- textual_debugger-0.2.8/src/tdb/widgets/rust_concurrency_modal.py +397 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/stack_view.py +6 -2
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/threads_modal.py +55 -8
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/textual_debugger.egg-info/PKG-INFO +360 -38
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/textual_debugger.egg-info/SOURCES.txt +23 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/LICENSE +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/setup.cfg +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/__main__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/_timeouts.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/__main__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/bash/declares.py +0 -0
- {textual_debugger-0.2.4/src/tdb/adapters/perl → textual_debugger-0.2.8/src/tdb/adapters/ocaml}/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/Devel/TdbCompile.pm +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/Devel/TdbRemote.pm +0 -0
- {textual_debugger-0.2.4/src/tdb/dap → textual_debugger-0.2.8/src/tdb/adapters/perl}/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/__main__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/protocol.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/perl/refs.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/__main__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/cli.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/protocol.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/adapters/tcsh/scanner.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_handlers/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/app_helpers.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/breakpoint_hook.py +0 -0
- {textual_debugger-0.2.4/src/tdb/server → textual_debugger-0.2.8/src/tdb/dap}/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/dap/messages.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/dap/protocol.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/dap/types.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/inspection.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/inspection_full.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/keybindings/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/languages/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/mcp/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/mcp/__main__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/persist.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/post_mortem.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/processes_cache.py +0 -0
- {textual_debugger-0.2.4/src/tdb/session → textual_debugger-0.2.8/src/tdb/server}/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/server/event_handler.py +0 -0
- {textual_debugger-0.2.4/src/tdb/widgets → textual_debugger-0.2.8/src/tdb/session}/__init__.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/child_processes.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/messages.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/post_mortem_loader.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/statement_stepper.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/terminal.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/session/textual_handler.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/source_analysis.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/async_tasks_modal.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/breakpoint_view.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/code_view.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/console_view.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/evaluate_console.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/full_contents_modal.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/menu_bar.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/processes_modal.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/status_bar.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/tdb/widgets/variable_view.py +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/textual_debugger.egg-info/dependency_links.txt +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/textual_debugger.egg-info/entry_points.txt +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/src/textual_debugger.egg-info/requires.txt +0 -0
- {textual_debugger-0.2.4 → textual_debugger-0.2.8}/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.8
|
|
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:
|
|
@@ -73,16 +73,16 @@ 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))
|
|
79
82
|
|
|
80
83
|
`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
|
|
84
|
+
DAP to a pluggable debug adapter.
|
|
85
|
+
It provides a rich interactive interface for stepping through
|
|
86
86
|
code, inspecting variables, managing breakpoints, and evaluating expressions in
|
|
87
87
|
complex programs.
|
|
88
88
|
|
|
@@ -96,10 +96,13 @@ MIT License. Copyright 2026 by Al Danial.
|
|
|
96
96
|
`tdb`:
|
|
97
97
|
|
|
98
98
|
- 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
|
-
|
|
99
|
+
the richest feature set), C/C++ (via `gdb -i dap` or `lldb-dap`), Rust (via `gdb` or
|
|
100
|
+
`lldb-dap`), Perl (via `perl -d`),
|
|
101
|
+
Bash (via bash's own `DEBUG` trap), Tcsh (via source instrumentation of a
|
|
102
|
+
stock `tcsh`), Ruby (via the debug gem's `rdbg`), and OCaml (native via
|
|
103
|
+
`lldb-dap`/`gdb`, bytecode via ocamlearlybird). Most languages are
|
|
104
|
+
auto-detected from the target; Rust intentionally requires `--lang rust`
|
|
105
|
+
(ref. [Multi-Language Debugging](#multi-language-debugging)).
|
|
103
106
|
|
|
104
107
|
- supports debugging of synchronous, asynchronous, multi-threaded, and multi-process Python code.
|
|
105
108
|
It specifically supports modules
|
|
@@ -107,7 +110,7 @@ It specifically supports modules
|
|
|
107
110
|
- `threading` (with a thread inspector)
|
|
108
111
|
- `multiprocessing` / `concurrent.futures` (with automatic child process attachment and a process inspector)
|
|
109
112
|
|
|
110
|
-
- supports remote attachment to
|
|
113
|
+
- supports remote attachment to Python, Perl, Ruby, Rust, and C/C++ programs
|
|
111
114
|
|
|
112
115
|
- includes a JSON-RPC server mode, an MCP mode, and a `SKILL.md` file that enable
|
|
113
116
|
programmatic debug control, making it suitable for
|
|
@@ -142,6 +145,9 @@ as open source.
|
|
|
142
145
|
- OpenAI, for providing access to Codex through the
|
|
143
146
|
[Codex for Open Source](https://developers.openai.com/community/codex-for-oss) program.
|
|
144
147
|
|
|
148
|
+
This project was inspired by Andreas Klöckner's excellent [pudb](https://pypi.org/project/pudb/)
|
|
149
|
+
Python debugger.
|
|
150
|
+
|
|
145
151
|
## Gallery
|
|
146
152
|
<p align="center">
|
|
147
153
|
<img src="https://github.com/AlDanial/tdb/blob/main/gallery/async_breakpoint.png" alt="at breakpoint" width="300">
|
|
@@ -244,32 +250,49 @@ python -m tdb my_program.py
|
|
|
244
250
|
|
|
245
251
|
## Multi-Language Debugging
|
|
246
252
|
|
|
247
|
-
`tdb` debugs any language that has a Debug Adapter Protocol backend.
|
|
253
|
+
`tdb` debugs any language that has a Debug Adapter Protocol backend. Eight
|
|
248
254
|
languages are supported out of the box:
|
|
249
255
|
|
|
250
256
|
| Language | Adapter(s) | Dependencies | Feature level |
|
|
251
257
|
|----------|------------|------------------------|---------------|
|
|
252
258
|
| Python | `debugpy` (default) | Python ≥ 3.11 | everything in this README |
|
|
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 |
|
|
259
|
+
| 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) |
|
|
260
|
+
| 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 |
|
|
254
261
|
| Perl | perl-tdb (bundled) | perl ≥ 5.18 on PATH | core debugging + remote attach |
|
|
255
262
|
| Bash | bash-tdb (bundled) | bash ≥ 4.4 on PATH | core debugging (no remote attach) |
|
|
256
263
|
| Tcsh | tcsh-tdb (bundled) | tcsh on PATH | core debugging (no remote attach, no conditional breakpoints, no pause) |
|
|
264
|
+
| Ruby | `rdbg` (the [debug gem](https://github.com/ruby/debug)) | `rdbg` ≥ 1.9 on PATH | core debugging + remote attach |
|
|
265
|
+
| OCaml (native executable) | `lldb-dap` (default), `gdb` (alternate) | OCaml ≥ 4.12; `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 |
|
|
266
|
+
| OCaml (bytecode executable) | `ocamlearlybird` (default) | OCaml ≥ 4.12; `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 |
|
|
257
267
|
|
|
258
268
|
### Language detection and selection
|
|
259
269
|
|
|
260
270
|
The language is auto-detected from the debug target:
|
|
261
271
|
|
|
262
272
|
1. File extension: `.py` → Python; `.pl` / `.pm` / `.t` → Perl; `.sh` / `.bash`
|
|
263
|
-
→ Bash; `.csh` / `.tcsh` → Tcsh.
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
273
|
+
→ Bash; `.csh` / `.tcsh` → Tcsh; `.rb` → Ruby. (`.ml` / `.mli` do *not*
|
|
274
|
+
auto-select OCaml, see point 5.)
|
|
275
|
+
2. Native executables (ELF, Mach-O, PE magic bytes) → C/C++, unless
|
|
276
|
+
byte-sniffing finds an OCaml marker, either a native binary's
|
|
277
|
+
`caml_program`/`caml_startup` runtime symbols, a bytecode file's
|
|
278
|
+
trailing `Caml1999` marker, or a `#!...ocamlrun` shebang, in which case
|
|
279
|
+
→ OCaml (native or bytecode respectively). A stripped native OCaml
|
|
280
|
+
binary that byte-sniffing can't identify falls back to C/C++; force it
|
|
281
|
+
with `--lang ocaml`. Rust is never inferred from an executable; select
|
|
282
|
+
it explicitly with `--lang rust`.
|
|
283
|
+
3. A `#!...python`, `#!...perl`, `#!...bash`, `#!...csh`/`#!...tcsh`, or
|
|
284
|
+
`#!...ruby` shebang → Python / Perl / Bash / Tcsh / Ruby respectively.
|
|
267
285
|
4. C/C++/Rust *source* files (`.c`, `.cpp`, `.rs`, …) produce an error with a
|
|
268
286
|
hint: compile with debug info (`g++ -g -O0`) and debug the binary.
|
|
269
|
-
5.
|
|
287
|
+
5. `.ml` / `.mli` (OCaml source) produce an error too: build the project
|
|
288
|
+
first (dune's dev profile keeps debug info) and pass the **built
|
|
289
|
+
executable** to `tdb` (`tdb ./_build/default/bin/main.exe`), never the
|
|
290
|
+
`.ml` file.
|
|
291
|
+
6. Anything else produces an error naming the `--lang` override.
|
|
270
292
|
|
|
271
293
|
`--lang` forces the language; `--adapter` picks a non-default adapter within
|
|
272
|
-
it (`tdb --lang cpp --adapter lldb-dap ./myprog`).
|
|
294
|
+
it (`tdb --lang cpp --adapter lldb-dap ./myprog`). Rust always requires the
|
|
295
|
+
explicit language selection (`tdb --lang rust target/debug/app`).
|
|
273
296
|
|
|
274
297
|
> **Migration note:** extensionless Python scripts without a `python` shebang
|
|
275
298
|
> were previously assumed to be Python; they now require `--lang python`.
|
|
@@ -302,12 +325,17 @@ process inspectors and wait graph, the evaluate console's trailing-`?` help,
|
|
|
302
325
|
`--python`/`--pv`, `--no-subprocess`, automatic child-process attachment, and
|
|
303
326
|
the post-mortem / `tdb.breakpoint()` hooks (those hooks live inside Python
|
|
304
327
|
programs by nature). Remote attach (`-r`) also works for Perl (see
|
|
305
|
-
[Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`),
|
|
306
|
-
|
|
307
|
-
|
|
328
|
+
[Perl](#perl), `Devel::TdbRemote` in place of `debugpy.listen()`), Ruby
|
|
329
|
+
(see [Ruby](#ruby), `rdbg --open` in place of `debugpy.listen()`), and for
|
|
330
|
+
Rust and C/C++ native binaries (against a gdbserver/lldb-server stub, with
|
|
331
|
+
a local symbol-bearing executable; see [Rust](#rust) — the same flags work
|
|
332
|
+
for a C/C++ target without `--lang`), but not for Bash, Tcsh, or OCaml. `--terminal` works for every launch-mode
|
|
333
|
+
language — Python, Perl, Bash, Tcsh, Ruby, and C/C++, OCaml native, or Rust
|
|
334
|
+
sessions via `--adapter lldb-dap` — see
|
|
335
|
+
[External Terminal Support](#external-terminal-support).
|
|
308
336
|
|
|
309
337
|
**Bash limitations (v1):** the bash adapter uses bash's own `DEBUG` trap and
|
|
310
|
-
has a smaller feature
|
|
338
|
+
has a smaller feature set than Python:
|
|
311
339
|
|
|
312
340
|
- Debuggee code that installs its own `DEBUG` trap clobbers the harness;
|
|
313
341
|
debugging silently degrades to free-running.
|
|
@@ -351,9 +379,30 @@ paths and line numbers are preserved in everything tdb displays):
|
|
|
351
379
|
|
|
352
380
|
See [Tcsh](#tcsh) below for launch details.
|
|
353
381
|
|
|
382
|
+
**OCaml limitations (v1):** OCaml has two independent adapters with
|
|
383
|
+
different, non-overlapping gaps; see [OCaml](#ocaml) below for the full
|
|
384
|
+
picture:
|
|
385
|
+
|
|
386
|
+
- **Native (`lldb-dap`/`gdb`):** the Variables view shows no named OCaml
|
|
387
|
+
locals in an OCaml frame (only a `Registers` scope). This is an
|
|
388
|
+
upstream OCaml/DWARF limitation on stock OCaml 5.4, not a `tdb` bug; use
|
|
389
|
+
the bytecode adapter when you need to inspect locals. The evaluate
|
|
390
|
+
console evaluates lldb/C-level expressions (runtime spelunking), not
|
|
391
|
+
OCaml expressions.
|
|
392
|
+
- **Bytecode (`ocamlearlybird`):** single-domain only (no multicore); no
|
|
393
|
+
`pause` while running (so `--run` is unavailable); the evaluate console
|
|
394
|
+
never gets a response for any expression (an `ocamlearlybird` 1.3.6
|
|
395
|
+
limitation); and the fatal-error modal doesn't appear for an uncaught
|
|
396
|
+
exception (`ocamlearlybird` swallows the real exception text before it
|
|
397
|
+
reaches `tdb`). Run the program outside the debugger to see the
|
|
398
|
+
backtrace instead.
|
|
399
|
+
- No Windows support, no remote attach, and a stripped native binary that
|
|
400
|
+
byte-sniffing can't identify needs `--lang ocaml`.
|
|
401
|
+
|
|
354
402
|
### C/C++ tips
|
|
355
403
|
|
|
356
|
-
- Compile with `-g` (ideally `-g -O0`
|
|
404
|
+
- Compile with `-g` (ideally `-g -O0` or `-g3 -O0`).
|
|
405
|
+
If no breakpoint in a file can be
|
|
357
406
|
bound, `tdb` prints a console warning suggesting the program may lack
|
|
358
407
|
debug info.
|
|
359
408
|
- Stack frames pointing into system libraries often have no source on disk;
|
|
@@ -366,6 +415,75 @@ See [Tcsh](#tcsh) below for launch details.
|
|
|
366
415
|
commands, so evaluate expressions with an explicit `print`, e.g.
|
|
367
416
|
`print x` rather than bare `x` (bare `x` collides with GDB's
|
|
368
417
|
examine-memory command). `lldb-dap` evaluates bare expressions directly.
|
|
418
|
+
- `--terminal` (see [External Terminal Support](#external-terminal-support))
|
|
419
|
+
requires `--adapter lldb-dap`; GDB's DAP mode has no terminal integration
|
|
420
|
+
and `tdb` refuses `--terminal` with the default `gdb` adapter.
|
|
421
|
+
|
|
422
|
+
### Rust
|
|
423
|
+
|
|
424
|
+
Rust debugging is intentionally explicit: build a normal debug executable,
|
|
425
|
+
leave it unmodified, and pass that executable with `--lang rust`. Linux and
|
|
426
|
+
macOS are supported; Windows is not yet (MSVC-toolchain binaries carry PDB
|
|
427
|
+
debug info that neither `gdb -i dap` nor this release's probes read). `tdb` does
|
|
428
|
+
not compile, instrument, or auto-detect Rust programs. Core debugging
|
|
429
|
+
(breakpoints, stepping, stacks, variables, remote attach) works with any
|
|
430
|
+
rustc that emits debug info; the concurrency inspector's layout-specific
|
|
431
|
+
*ownership evidence* additionally requires the current stable Rust
|
|
432
|
+
**1.98** standard-library layout — on other versions the workspace still
|
|
433
|
+
opens with stack-based wait classification and a compatibility warning.
|
|
434
|
+
Build with debug information and no optimization for the most useful
|
|
435
|
+
source locations:
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
cargo rustc -- -C debuginfo=2 -C opt-level=0
|
|
439
|
+
# Equivalent direct rustc settings: rustc -C debuginfo=2 -C opt-level=0 src/main.rs
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
A panic that terminates the debuggee opens the error modal with the parsed
|
|
443
|
+
panic message and backtrace; `tdb` injects `RUST_BACKTRACE=1` into launched
|
|
444
|
+
programs (your own value wins if you set one) so the frames are present.
|
|
445
|
+
|
|
446
|
+
The common commands are:
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
cargo build
|
|
450
|
+
tdb --lang rust target/debug/app
|
|
451
|
+
tdb --lang rust --adapter lldb-dap --run target/debug/app
|
|
452
|
+
tdb --lang rust --adapter lldb-dap --terminal xterm target/debug/app
|
|
453
|
+
tdb --lang rust --adapter gdb --remote-attach host:2345 target/debug/app
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`--run` and normal stopped-on-entry launch work with both adapters. On Linux,
|
|
457
|
+
use GDB (the default) or `lldb-dap`; on macOS, use `lldb-dap` (the default).
|
|
458
|
+
External terminals are LLDB-only: GDB's DAP mode cannot provide terminal
|
|
459
|
+
integration. The mode/platform matrix is:
|
|
460
|
+
|
|
461
|
+
| Platform | Normal / `--run` | `--terminal` | `--remote-attach` |
|
|
462
|
+
|----------|------------------|--------------|-------------------|
|
|
463
|
+
| Linux | GDB or `lldb-dap` | `lldb-dap` only | GDB or `lldb-dap` |
|
|
464
|
+
| macOS | `lldb-dap` | `lldb-dap` only | `lldb-dap` |
|
|
465
|
+
|
|
466
|
+
Remote attach connects to a GDB-remote server already running on the target.
|
|
467
|
+
Pass the matching **local, unmodified executable with debug symbols** as the
|
|
468
|
+
program argument; `tdb` requires it for symbols and Rust concurrency evidence.
|
|
469
|
+
When source paths differ, pair `--local-root` with `--remote-root`. Do not
|
|
470
|
+
expose the remote debug port to an untrusted network: prefer an SSH tunnel,
|
|
471
|
+
for example `ssh -L 2345:127.0.0.1:2345 host`, then attach to `127.0.0.1:2345`.
|
|
472
|
+
|
|
473
|
+
In a Rust session the Threads action (`Alt+T`, or the Threads menu entry)
|
|
474
|
+
opens the Rust Concurrency workspace while the debuggee is stopped — a
|
|
475
|
+
fresh, bounded snapshot of threads, wait edges, and findings. The graph is
|
|
476
|
+
best effort: `confirmed` evidence is directly observed by the debugger,
|
|
477
|
+
`probable` is a supported inference, and `unknown` means ownership could not
|
|
478
|
+
be established. A deadlock is confirmed only when every edge in its cycle is
|
|
479
|
+
confirmed. A suspected cycle or whole-program stall is a diagnostic lead, not
|
|
480
|
+
a proof: it means a cycle has incomplete evidence, or all observed application
|
|
481
|
+
threads are blocked while the graph cannot safely invent an owner. Refresh
|
|
482
|
+
after the next stop to collect a new snapshot.
|
|
483
|
+
|
|
484
|
+
The built-in evidence recognizes current `std` synchronization layouts. A
|
|
485
|
+
future helper crate may expose stable, application-provided synchronization
|
|
486
|
+
metadata for broader primitives and stronger ownership evidence.
|
|
369
487
|
|
|
370
488
|
### Perl
|
|
371
489
|
|
|
@@ -379,6 +497,9 @@ hood, so it works with any Perl already on the system.
|
|
|
379
497
|
tdb script.pl
|
|
380
498
|
```
|
|
381
499
|
|
|
500
|
+
`--terminal` is supported (see
|
|
501
|
+
[External Terminal Support](#external-terminal-support)).
|
|
502
|
+
|
|
382
503
|
**Compile-time code (`BEGIN` blocks):** Perl runs `BEGIN` blocks and the
|
|
383
504
|
`use` statements that are themselves `BEGIN` blocks while it is still
|
|
384
505
|
*compiling* your program, before stock `perl5db` ever stops. `tdb` arms the
|
|
@@ -500,7 +621,8 @@ Most notably, a breakpoint can't be set on a `func() {` line itself (the
|
|
|
500
621
|
`DEBUG` trap never fires there), stops never land inside subshells or
|
|
501
622
|
pipeline segments, child bash processes run uninstrumented, and only the
|
|
502
623
|
innermost frame's locals are inspectable. There is no remote-attach mode for
|
|
503
|
-
Bash.
|
|
624
|
+
Bash. `--terminal` is supported (see
|
|
625
|
+
[External Terminal Support](#external-terminal-support)).
|
|
504
626
|
|
|
505
627
|
The Variables view shows three scopes for bash: Locals (innermost frame
|
|
506
628
|
only), Globals (unexported shell variables), and Environment (exported
|
|
@@ -529,7 +651,8 @@ stack navigation across `source` nesting, variable inspection, and the
|
|
|
529
651
|
evaluate console with the v1 caveats listed in
|
|
530
652
|
[What works for non-Python languages](#what-works-for-non-python-languages),
|
|
531
653
|
most notably: no conditional breakpoints, no pause of a free-running
|
|
532
|
-
script, and stepping is per logical source line.
|
|
654
|
+
script, and stepping is per logical source line. `--terminal` is supported
|
|
655
|
+
(see [External Terminal Support](#external-terminal-support)).
|
|
533
656
|
|
|
534
657
|
The Variables view shows four scopes for tcsh: Shell Variables (`set`),
|
|
535
658
|
Environment (`setenv`), Aliases, and Arguments (`argv`). All of them show
|
|
@@ -538,6 +661,119 @@ text directly in the paused shell. It can inspect *and mutate* state
|
|
|
538
661
|
(`set name = value` takes effect immediately), and a syntax error in
|
|
539
662
|
evaluated text can terminate the debuggee; there is no isolation.
|
|
540
663
|
|
|
664
|
+
### Ruby
|
|
665
|
+
|
|
666
|
+
tdb debugs Ruby via the [debug gem](https://github.com/ruby/debug)'s
|
|
667
|
+
`rdbg` (Ruby >= 3.1 ships it; otherwise `gem install debug`; tdb needs
|
|
668
|
+
debug >= 1.9). `rdbg` must be on PATH, or point tdb at it with
|
|
669
|
+
`{"adapters": {"rdbg": "/path/to/rdbg"}}` in config.json.
|
|
670
|
+
|
|
671
|
+
```bash
|
|
672
|
+
tdb script.rb # launch, stop at first line
|
|
673
|
+
tdb --run script.rb # run immediately, debug on demand
|
|
674
|
+
tdb --terminal script.rb # program I/O in its own terminal
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
Remote attach: start the program with
|
|
678
|
+
`rdbg --open --port 5678 --host 0.0.0.0 script.rb` (add `--nonstop` to
|
|
679
|
+
let it run before you attach), then `tdb -r HOST:5678 --lang ruby`.
|
|
680
|
+
Note: rdbg's `--cookie` authentication is not part of DAP and is not
|
|
681
|
+
supported; bind to localhost and tunnel over SSH instead.
|
|
682
|
+
`--local-root`/`--remote-root` path mappings are not supported for Ruby
|
|
683
|
+
yet. Bundler projects work when your environment resolves `rdbg`
|
|
684
|
+
(`gem install debug` into the project's Ruby); there is no `bundle
|
|
685
|
+
exec` integration yet.
|
|
686
|
+
|
|
687
|
+
> **Startup note:** the debug gem's `rdbg` has an occasional handshake
|
|
688
|
+
> race on launch; tdb detects a stalled/corrupted handshake and retries
|
|
689
|
+
> once automatically with a fresh `rdbg`, so this is usually invisible.
|
|
690
|
+
|
|
691
|
+
### OCaml
|
|
692
|
+
|
|
693
|
+
`tdb` debugs OCaml through two independent adapters, chosen automatically
|
|
694
|
+
from how the executable was built:
|
|
695
|
+
|
|
696
|
+
- **Native** (`ocamlopt`/dune's default build) → **`lldb-dap`** (default;
|
|
697
|
+
`--adapter gdb` also works). OCaml 5's domains show up as threads.
|
|
698
|
+
- **Bytecode** (`ocamlc -g`) → **`ocamlearlybird`** (`opam install
|
|
699
|
+
earlybird`). Single-domain only, but with rich, real OCaml locals.
|
|
700
|
+
|
|
701
|
+
**Build requirement:** compile with `-g` (dune's dev profile already
|
|
702
|
+
does). Always pass the **built executable** to `tdb`, never the `.ml`
|
|
703
|
+
source, as in `tdb ./_build/default/bin/main.exe`, not `tdb main.ml` (which
|
|
704
|
+
errors with this exact guidance).
|
|
705
|
+
|
|
706
|
+
**OCaml version:** tdb requires **OCaml ≥ 4.12**. Older runtimes print
|
|
707
|
+
`Printexc` backtraces without function names, which the fatal-error
|
|
708
|
+
modal's parser does not understand (frames would be dropped and the
|
|
709
|
+
modal would wrongly suggest recompiling with `-g`).
|
|
710
|
+
|
|
711
|
+
```bash
|
|
712
|
+
tdb ./_build/default/bin/main.exe # native, lldb-dap
|
|
713
|
+
tdb --adapter gdb ./_build/default/bin/main.exe # native, gdb
|
|
714
|
+
tdb ./_build/default/bin/main.byte # bytecode, ocamlearlybird
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
A stripped native binary that byte-sniffing can't identify as OCaml falls
|
|
718
|
+
back to C/C++; force it with `--lang ocaml`. Override the adapter or point
|
|
719
|
+
at a non-`PATH` install in `config.json` (see
|
|
720
|
+
[Configuration](#configuration)):
|
|
721
|
+
|
|
722
|
+
```json
|
|
723
|
+
{
|
|
724
|
+
"adapters": {"ocamlearlybird": "/path/to/ocamlearlybird"},
|
|
725
|
+
"default_adapters": {"ocaml": "gdb"}
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Domains as threads (native only):** OCaml 5's domains are presented in
|
|
730
|
+
the Threads modal (`Alt+T` or the **Threads (N)** menu label) as `Domain 0
|
|
731
|
+
(main)`, `Domain 1`, and so on, in creation order. The runtime's internal
|
|
732
|
+
"backup thread" (one per domain, used for I/O blocking) is hidden by
|
|
733
|
+
default since it's never running user code; press `a` in the Threads
|
|
734
|
+
modal to reveal it alongside the domains. Breakpoints, stepping, continue,
|
|
735
|
+
and pause all work normally against any domain. In both the Stack view
|
|
736
|
+
and the Threads modal, OCaml frame names are demangled from the
|
|
737
|
+
runtime's raw `camlModule__name_NNN` convention into readable
|
|
738
|
+
`Module.name` form (e.g. `camlOcaml_domains.worker_297` displays as
|
|
739
|
+
`Ocaml_domains.worker`); runtime C frames (`caml_start_program`,
|
|
740
|
+
`caml_callback_exn`, and the like) are shown as-is, unchanged.
|
|
741
|
+
|
|
742
|
+
**Variables view (native):** stock OCaml 5.4 native DWARF shows **no
|
|
743
|
+
named locals**. The `scopes`/`variables` round trip succeeds, but every
|
|
744
|
+
OCaml frame's `Locals` and `Globals` scopes come back empty; only a
|
|
745
|
+
`Registers` scope has data (the raw register file, not decoded OCaml
|
|
746
|
+
values). This is an upstream OCaml compiler/DWARF limitation on the
|
|
747
|
+
verified toolchain (OCaml 5.4.0 / lldb 21), not a `tdb` bug. If you need
|
|
748
|
+
to inspect local variables, use the bytecode adapter instead.
|
|
749
|
+
|
|
750
|
+
**Variables view (bytecode):** `ocamlearlybird` reports real local names
|
|
751
|
+
and values, exactly like Python locals.
|
|
752
|
+
|
|
753
|
+
**Evaluate console:** the two adapters give fundamentally different
|
|
754
|
+
consoles. Native (`lldb-dap`) evaluates **lldb/C-level expressions**.
|
|
755
|
+
This is runtime spelunking (registers, raw memory, C symbol names), not
|
|
756
|
+
OCaml expression evaluation. Bytecode (`ocamlearlybird`) is meant to
|
|
757
|
+
evaluate real OCaml expressions in scope, but in the verified
|
|
758
|
+
`ocamlearlybird` 1.3.6 release its `evaluate` request never responds (a
|
|
759
|
+
confirmed upstream limitation, not specific to `tdb`); the console
|
|
760
|
+
silently returns nothing for any expression.
|
|
761
|
+
|
|
762
|
+
**Uncaught exceptions:** native sessions set a breakpoint on
|
|
763
|
+
`caml_fatal_uncaught_exception` so the debugger stops there, and `tdb`
|
|
764
|
+
also parses the `OCAMLRUNPARAM=b` backtrace it injects into the debuggee's
|
|
765
|
+
environment once the process exits, opening the same error modal Python
|
|
766
|
+
tracebacks get. Bytecode sessions do **not** get this: `ocamlearlybird`
|
|
767
|
+
intercepts the uncaught exception itself and only reports a generic
|
|
768
|
+
"Program exited due to Uncaught_exc" message, so the real exception text
|
|
769
|
+
never reaches `tdb`. Run the program outside the debugger
|
|
770
|
+
(`OCAMLRUNPARAM=b ./main.byte`) to see its backtrace.
|
|
771
|
+
|
|
772
|
+
**Limitations (v1):** no Windows support; no remote attach; bytecode
|
|
773
|
+
sessions can't `pause` a running program (so `--run` is unavailable for
|
|
774
|
+
bytecode. Native sessions support `--run` normally); `Unix.fork` and Eio
|
|
775
|
+
fibers are out of scope (only OCaml 5 domains are presented as threads).
|
|
776
|
+
|
|
541
777
|
## Layout
|
|
542
778
|
|
|
543
779
|
```
|
|
@@ -593,6 +829,11 @@ A cursor line (blue) tracks your position; the current execution line is highlig
|
|
|
593
829
|
| `Alt+A` | Async Tasks |
|
|
594
830
|
| `Alt+H` | Help (Documentation, About) |
|
|
595
831
|
|
|
832
|
+
File > Open works for every supported language: the file picker filters to
|
|
833
|
+
the current session's language (by extension) and refuses a pick that
|
|
834
|
+
detects as a different language, so you can only switch to another script
|
|
835
|
+
written in the same language as the one currently being debugged.
|
|
836
|
+
|
|
596
837
|
**Navigation (vim-style by default):**
|
|
597
838
|
|
|
598
839
|
By default the Code View is in Debug mode. Hit `Escape` to switch to Navigate mode
|
|
@@ -650,7 +891,7 @@ results = await asyncio.gather(
|
|
|
650
891
|
fetch(2, 1),
|
|
651
892
|
fetch(3, 3),
|
|
652
893
|
)
|
|
653
|
-
print(results)
|
|
894
|
+
print(results) # next stop lands here, not on each sub-line above
|
|
654
895
|
```
|
|
655
896
|
|
|
656
897
|
lands on `print(results)`, not on each interior sub-line of the `gather` call. Switch to
|
|
@@ -760,6 +1001,7 @@ need to launch through `tdb` up front. Install the hook once at the top of your
|
|
|
760
1001
|
```python
|
|
761
1002
|
import sys
|
|
762
1003
|
import tdb
|
|
1004
|
+
|
|
763
1005
|
sys.excepthook = tdb.exception_hook
|
|
764
1006
|
```
|
|
765
1007
|
|
|
@@ -808,6 +1050,7 @@ continuing--use `tdb.breakpoint()`:
|
|
|
808
1050
|
```python
|
|
809
1051
|
import tdb
|
|
810
1052
|
|
|
1053
|
+
|
|
811
1054
|
def compute(n):
|
|
812
1055
|
total = sum(range(n))
|
|
813
1056
|
tdb.breakpoint() # pause here and drop into tdb
|
|
@@ -950,6 +1193,7 @@ where you want to attach the debugger:
|
|
|
950
1193
|
```python
|
|
951
1194
|
# In the target program:
|
|
952
1195
|
import debugpy
|
|
1196
|
+
|
|
953
1197
|
debugpy.listen(("0.0.0.0", 5678))
|
|
954
1198
|
print("Waiting for tdb to attach on port 5678...")
|
|
955
1199
|
debugpy.wait_for_client() # optional: pause until debugger connects
|
|
@@ -1007,22 +1251,94 @@ application directory and a shared library directory) in one invocation.
|
|
|
1007
1251
|
|
|
1008
1252
|
### External Terminal Support
|
|
1009
1253
|
|
|
1010
|
-
Some
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1254
|
+
Some programs, notably text user interfaces, use terminal control codes and
|
|
1255
|
+
require direct access to the terminal to function properly. Such programs
|
|
1256
|
+
can be debugged with `tdb` by having it launch the debuggee in a separate
|
|
1257
|
+
terminal:
|
|
1014
1258
|
|
|
1015
1259
|
```bash
|
|
1016
1260
|
tdb --terminal xterm my_tui_app.py
|
|
1017
1261
|
```
|
|
1018
1262
|
|
|
1019
|
-
|
|
1263
|
+
`--terminal` works for every language `tdb` can *launch* (as opposed to
|
|
1264
|
+
attach to): Python, Perl, Bash, Tcsh, Ruby, and C/C++ or native OCaml
|
|
1265
|
+
sessions via `--adapter lldb-dap`. Neither `gdb -i dap` (the default C/C++
|
|
1266
|
+
adapter, and an alternate for native OCaml) nor `ocamlearlybird` (the
|
|
1267
|
+
bytecode OCaml adapter) has any terminal integration -- `tdb` rejects
|
|
1268
|
+
`--terminal` up front for both, with an error pointing at `--adapter
|
|
1269
|
+
lldb-dap` instead. `--terminal` also only applies when `tdb` launches the
|
|
1270
|
+
program itself; it is rejected for remote-attach (`-r`), since there's no
|
|
1271
|
+
program for `tdb` to spawn a terminal around.
|
|
1272
|
+
|
|
1273
|
+
The debuggee runs in a separate window of the specified terminal, including
|
|
1274
|
+
all of its stdin/stdout/stderr -- keyboard input, program output, and
|
|
1275
|
+
anything the program itself draws to the terminal all happen in that
|
|
1276
|
+
window, not in `tdb`'s Console View. Supported choices:
|
|
1020
1277
|
`xterm`, `konsole`, `gnome-terminal`, `ghostty`, `kitty`, `iterm2`, `warp`,
|
|
1021
1278
|
`wezterm`, `terminator`. The selected terminal must be on `PATH`. Debugging
|
|
1022
|
-
|
|
1279
|
+
(breakpoints, stepping, variable inspection, the evaluate console) proceeds
|
|
1280
|
+
as usual in the terminal where `tdb` was invoked.
|
|
1023
1281
|
|
|
1024
1282
|
This feature only works in graphical environments where external terminals are available.
|
|
1025
1283
|
|
|
1284
|
+
### Run Mode (`--run`)
|
|
1285
|
+
|
|
1286
|
+
`tdb`'s run mode invokes an unmodified program nearly at full speed, without bringing up the TUI.
|
|
1287
|
+
At any point afterwards, hitting `Ctrl-C` in that terminal pauses the program
|
|
1288
|
+
and drops you into the full TUI.
|
|
1289
|
+
From there you can inspect the program's state, navigate the stack, set and continue
|
|
1290
|
+
to breakpoints, and so on. After you finish inspecting, hitting `q` to quit brings up
|
|
1291
|
+
a modal that lets you either detach from the TUI and let the program resume running,
|
|
1292
|
+
or lets you terminate it.
|
|
1293
|
+
|
|
1294
|
+
The primary use cases for run mode are: (1) allowing inspection of a program that
|
|
1295
|
+
appears hung, and (2) finding where a program execution path lands after it
|
|
1296
|
+
receives a problematic input.
|
|
1297
|
+
|
|
1298
|
+
```bash
|
|
1299
|
+
tdb --run my_program.py args...
|
|
1300
|
+
```
|
|
1301
|
+
|
|
1302
|
+
The debuggee's stdout/stderr stream straight to the terminal. If the program exits on
|
|
1303
|
+
its own, `tdb` exits with the same code:
|
|
1304
|
+
|
|
1305
|
+
```bash
|
|
1306
|
+
tdb --run my_program.py; echo $? # my_program.py's own exit code
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
**Interrupting:** press Ctrl-C in the terminal (any platform), or, on Unix, send
|
|
1310
|
+
`SIGUSR1` to `tdb`'s pid from another terminal: `kill -USR1 <tdb pid>`. Either one pauses
|
|
1311
|
+
the debuggee at its currently executing line and opens the TUI with full debugging
|
|
1312
|
+
available -- breakpoints, stepping, variable inspection, the evaluate console. The
|
|
1313
|
+
debuggee itself never receives the signal (`tdb`'s adapter runs in its own process
|
|
1314
|
+
group), so its own `SIGINT` handling is undisturbed.
|
|
1315
|
+
|
|
1316
|
+
**Quitting an adopted session** adds a third choice to the usual quit dialog:
|
|
1317
|
+
- `d` (or `q`) -- detach and resume: the program keeps running headlessly; interrupt it
|
|
1318
|
+
again later the same way.
|
|
1319
|
+
- `t` -- terminate the program and quit `tdb`.
|
|
1320
|
+
- `Esc` -- cancel, stay in the TUI.
|
|
1321
|
+
|
|
1322
|
+
A breakpoint set during one of these episodes stays live after you detach; if it's hit,
|
|
1323
|
+
`tdb` reopens the TUI there, just like an interrupt.
|
|
1324
|
+
|
|
1325
|
+
If the program instead dies on an unhandled exception -- in Python this includes a
|
|
1326
|
+
nonzero `sys.exit()`, which `debugpy` treats as an uncaught `SystemExit` -- `tdb` opens
|
|
1327
|
+
the TUI at the point of failure instead of exiting silently, so you can inspect the
|
|
1328
|
+
crash. Exit-code passthrough applies only to a clean exit during the headless phase.
|
|
1329
|
+
|
|
1330
|
+
Supported languages: Python, Perl, Bash, Tcsh, Ruby, C/C++ (both `gdb` and
|
|
1331
|
+
`lldb-dap`), and native OCaml (both `gdb` and `lldb-dap`; bytecode/
|
|
1332
|
+
`ocamlearlybird` sessions don't support pause, so `--run` is unavailable
|
|
1333
|
+
for those). `--run` is rejected up front for any other language.
|
|
1334
|
+
|
|
1335
|
+
**Limitation:** pausing is cooperative. If the debuggee is blocked inside a single
|
|
1336
|
+
blocking external call or syscall, the pause can't land until that call returns --
|
|
1337
|
+
`tdb` prints a notice and opens the TUI once the stop actually arrives.
|
|
1338
|
+
|
|
1339
|
+
**Incompatible flags:** `-r`, `-k`/`-t`, `--record`, `--replay`, `--server`,
|
|
1340
|
+
`--headless`, `--mcp`, `--terminal`.
|
|
1341
|
+
|
|
1026
1342
|
### Keybinding Schemes
|
|
1027
1343
|
|
|
1028
1344
|
```bash
|
|
@@ -1058,7 +1374,9 @@ Both the interactive TUI and the JSON-RPC server run simultaneously.
|
|
|
1058
1374
|
### RPC Protocol
|
|
1059
1375
|
|
|
1060
1376
|
Send POST requests with `{"action": "...", "params": [...]}`. Responses return
|
|
1061
|
-
`{"timestamp": "...", "success": true/false, "value": "..."}`.
|
|
1377
|
+
`{"timestamp": "...", "success": true/false, "value": "..."}`. Actions with a
|
|
1378
|
+
structured result (today only `rust_concurrency`) additionally carry a `data`
|
|
1379
|
+
object holding the full JSON payload; `value` then holds a one-line summary.
|
|
1062
1380
|
|
|
1063
1381
|
```bash
|
|
1064
1382
|
# Check status
|
|
@@ -1116,6 +1434,7 @@ curl -s -X POST http://127.0.0.1:8150/rpc \
|
|
|
1116
1434
|
| `list_tasks` | `[]` | List all asyncio tasks |
|
|
1117
1435
|
| `inspect_task` | `["task_name"]` | Inspect a specific asyncio task |
|
|
1118
1436
|
| `wait_graph` | `[]` | Show wait graph + any deadlock cycles |
|
|
1437
|
+
| `rust_concurrency` | `[]` | Structured Rust thread/wait/deadlock snapshot in `data` (Rust sessions, stopped) |
|
|
1119
1438
|
| `restart` | `[]` | Restart session (preserves breakpoints) |
|
|
1120
1439
|
| `quit` | `[]` | Shut down |
|
|
1121
1440
|
|
|
@@ -1198,7 +1517,7 @@ point), `tdb --mcp` (the main CLI with the `--mcp` switch), and
|
|
|
1198
1517
|
`python -m tdb.mcp` (module form). Pick whichever matches how your MCP
|
|
1199
1518
|
client expects to launch servers.
|
|
1200
1519
|
|
|
1201
|
-
### Tool surface (
|
|
1520
|
+
### Tool surface (17 tools, curated)
|
|
1202
1521
|
|
|
1203
1522
|
| Cluster | Tools |
|
|
1204
1523
|
|---------|-------|
|
|
@@ -1206,7 +1525,7 @@ client expects to launch servers.
|
|
|
1206
1525
|
| Control | `control(action, timeout_s=30)` where `action ∈ {continue, next, step_in, step_out, pause, wait_for_stop}` |
|
|
1207
1526
|
| Inspection | `inspect(expressions)`, `read_source(file_path)`, `stack_trace()`, `status()`, `get_output()` |
|
|
1208
1527
|
| Breakpoints | `set_breakpoint(spec, condition?, hit_condition?)`, `remove_breakpoint(spec)`, `list_breakpoints()` |
|
|
1209
|
-
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()` |
|
|
1528
|
+
| Differentiators | `threads(thread_id?)`, `tasks(task_name?)`, `processes(name_or_pid?)`, `wait_graph()`, `rust_concurrency()` |
|
|
1210
1529
|
|
|
1211
1530
|
`control` is intentionally one tool that takes an action enum. The six
|
|
1212
1531
|
underlying RPC actions share a return shape, and agents perform
|
|
@@ -1217,9 +1536,10 @@ single optional argument for the same reason.
|
|
|
1217
1536
|
`debug_launch` accepts optional `lang` and `adapter` parameters mirroring the
|
|
1218
1537
|
CLI's `--lang`/`--adapter`; when omitted, the language is auto-detected from
|
|
1219
1538
|
`program`, so an agent can hand it a compiled binary directly. The
|
|
1220
|
-
|
|
1539
|
+
exception is Rust: compiled native binaries require explicit `lang="rust"`.
|
|
1540
|
+
The `tasks`/`processes`/`wait_graph` tools stay registered for every language but
|
|
1221
1541
|
return a structured "not supported when debugging C/C++"-style error for
|
|
1222
|
-
non-Python debuggees.
|
|
1542
|
+
non-Python debuggees; `rust_concurrency` does the same for non-Rust debuggees.
|
|
1223
1543
|
|
|
1224
1544
|
### Agent flow for a long-running step
|
|
1225
1545
|
|
|
@@ -1337,6 +1657,8 @@ fires as expected.
|
|
|
1337
1657
|
- [textual](https://github.com/Textualize/textual) : TUI framework
|
|
1338
1658
|
- [debugpy](https://github.com/microsoft/debugpy) : Debug Adapter Protocol implementation for Python
|
|
1339
1659
|
- [gdb](https://sourceware.org/gdb/) / [lldb-dap](https://lldb.llvm.org/resources/lldbdap.html) : optional, user-installed DAP adapters for C/C++
|
|
1660
|
+
- [debug gem](https://github.com/ruby/debug) (`rdbg`) : optional, user-installed DAP adapter for Ruby
|
|
1661
|
+
- [ocamlearlybird](https://github.com/hackwaly/ocamlearlybird) : optional, user-installed DAP adapter for OCaml bytecode (native OCaml reuses `gdb`/`lldb-dap`)
|
|
1340
1662
|
- [pygments](https://pygments.org/) : Syntax highlighting
|
|
1341
1663
|
- [FastAPI](https://fastapi.tiangolo.com/) + [uvicorn](https://www.uvicorn.org/) : JSON-RPC server
|
|
1342
1664
|
|