For those interested in writing a debugger:
There are a series of tutorials on how to write a debugger from scratch
for Windows x86-64 using Rust [1].
Additionally, there is a book titled "Building a Debugger - Write a Native x64 Debugger From Scratch" by Sy Brand [2].
Didn't expect it to be posted, readme maybe doesn't have enough context. It just says "Essential features are there". What are those? Most of what I've ever used in any debugger:
* Showing code, disassembly, threads, stack traces, local variables.
* Watches, with a little custom expression language. E.g. you can do pointer arithmetic, type casts, turn a pointer+length into an array, show as hex, etc. Access to local and global variables, thread-local variables, registers. Type introspection (e.g. sizeof and offsets of fields).
* Pretty printers for most C++ and Rust standard library types. Probably fragile and version-dependent (e.g. fields names often changes across versions), please report when they don't work.
* Automatically down-casting abstract classes to concrete classes.
* Breakpoints, conditional breakpoints (but no data breakpoints yet).
* Stepping: into/over/out a source code line, into/over a disassembly instruction, over a source code column (when there are multple statements one line, e.g. to skip evaluation of arguments of a function call). All places where control can stop (statements) are highlighted in the code, so you usually don't get surprised by where a step takes you. (...except when there's garbage in debug info, and you end up temporarily on line 0 or something. This happens frustratingly often, and there's not much I can do about it. I already added quite a few workarounds to make stepping less janky in such cases. If a step takes you to an unexpected place, it usually under-steps rather than over-steps, so you can just step again until you end up in the correct place.)
* Various searches: file by name, function by name, function by address (like addr2line), type by name, global variable by name, thread by stack trace.
* Debugging core dumps. There's also a gdump-like tool built in (`nnd --dump-core`) that makes core dump of a running process without killing it; it uses fork to minimize downtime (usually around a second even if there are tens of GB of memory to dump).
* Customizable key bindings, see `nnd --help-files` or `nnd --help-state`.
As a curiosity, is there a more heuristic approach and/or toolchain integrated approach that could be used for disassembly of stdlib components?
For example, a crate that could be linked in to provide some "well-known" object shapes (hashmaps, vec, hashset, etc) with marker values that could be heuristically analyzed to understand the debuggability of those objects?
Alternatively, I'd love to have a crate with recognizers and/or heuristics that could be somewhat debugger-independent and could be worked on for the benefit of other users. I'm quite an experienced Rust developer, just not really with debuggers, happy to help if there's a sandbox project that this could be plugged into.
Looks great, reminds me of the GUD interface in emacs. I’m unable to get it to find the code for a crate in a rust workspace. I’ve tried pointing the -d argument at the crate subdirectory, but nothing shows up in the code window. Any tips for debugging this issue?
This looks great, thank you. I have been spending time in lldb the past couple days and lamenting how terrible of an experience it is compared to an IDE.
Do you know what would be involved in getting this to work on macOS?
I don't work with anything that would need this, but I love TUIs so I checked it out and saw this bit:
Operations that can't be instantaneous (loading debug info, searching for functions and types) should be reasonably efficient, multi-threaded, asynchronous, cancellable, and have progress bars.
I wish this were more common, especially the progress bars thing.
At my previous job, the product I worked on would open something like 200 DLL plugins on start-up. This would basically hang GDB while it's indexing the DWARF symbols, but LLDB gives you a very nice asynchronous progress indicator for that.
GDB already has a TUI.. it's pretty "vintage" though. I looked at the screenshot at the top of the repo README and it looks like it has a lot more creature comforts (read: any at all compared to GDB).
Fun fact: gdb tui was the last straw that made me start working on nnd. I tried it for the first time, and it was taking 2 seconds to respond to every input, and that made me so angry I started researching how to make a debugger :)
check out [cgdb](https://github.com/cgdb/cgdb) - ncurses based gdb tui, with vim bindings. It's no longer actively worked on, but is decently maintained with bugfixes etc AFAIK.
ClickHouse is a completely stand-alone binary that doesnt rely on any linked libraries. Not sure how much of this explains the large binary size, though.
People here might also be interested in pwndbg, which adds a lot of qol improvements to the typical gdb/lldb experience. Including splitting dialogs over tmux panes, a lot more context info added to debug lines like where do pointers point to. Heap inspection. Colorization. makes for a much more friendly debugging experience.
Awesome work. Reminds me of CodeView back in the day, which I've been wishing I could have back since, and no, a gigantic pile of Emacs or vim plugins is not the equivalent.
This is nice. I want something like this for python that I can use on remote servers and compute nodes of clusters. I've tried pudb but I find it doesn't behave well with terminal resizing and I wish the interface was a little more configurable.
Not related to this post, but why in the world is anyone using TUI. Either go with GUI or go with commandline. This no man's land in the middle is the worst of both worlds..
TUIs are often more responsive in general. Some of us like the terminal and want to minimize as much mouse usage as possible (yes hotkeys exist in good GUI apps, but they're still primarily built around the WIMP model).
Command line often requires a lot of switch memorization. Command Line doesn't offer the full interactive/graphical power in this sort of situation. Command line is great for scripts and long running apps, or super simple interfaces.
Different apps have different requirements. Not everything needs a TUI, not everything needs a GUI, and if you want something similar to a GUI while staying in the terminal. Perhaps you don't have access to a windowing environment for some reason; perhaps you want to keep your requirements low in general.
Finally, why do you care? Some people like it others don't. Nobody comes in and shits on any programs that are GUI if they don't like it, they just don't use it.
So, to quote The Dude: "That's just, like, your opinion man". Sorry for the snark, but... It really is, and you're free to have it. But it seems an irrelevant point, and there may be better forums/posts (maybe an "Ask HN" question would be a good option) to discuss this question in depth beyond snark.
IMHO TUIs are the best of both worlds. Generally light and responsive [0], transparent over SSH, neatly falls into a tab/pane/window in screen/tmux/zellij, offer essentially everything I wanted from a GUI except graphics [1] which isn't usually a problem, and delightfully free of the latest charming "innovations" in UI reinvention (GNOME, I am looking directly at you).
[0] It is if course possible to make a light GUI and a slow+bloated TUI, but both are less common than the alternative.
[1] Sixel et al. exist but IME they rarely work well. Sadly.
Short summary: No animations, No symbols, No touch optimization, no responsive design and I do most of the other stuff in the Terminal anyways so TUI is better "integration" YMMV :)
One common use case is remote debugging over serial or ssh.
edit: and a reason you would do this locally using ssh is debugging the UI layer itself. if you have to step through the window server, you can't be using the window server at the same time. Remote lldb/gdb debugging is often just flaky. I don't know why they're so unreliable, but they are.
I have many beloved TUI tools at this point, and I am considering investing further in TUI for some further projects I am building that I would want some kind of interface for beyond a command line. I'm not convinced by this argument. Would you mind elaborating on any specifics?
Back in my native android days I used cgdb to have a split screen view of the sources I debug. The vim like interface was exactly what I needed. Just thought about it after seeing this project.
Very cool! I have been using LLDB quite a bit lately so I am eager to try this out. The state of debuggers dev experience really hasn't caught up to what things like Cargo have done for build systems, so I am glad to see people working on things like this.
It is really crazy how limited debugger options are on macOS. Is it simply the case that there are not that many people writing code in systems languages on macOS outside of XCode?
[+] [-] hippospark|10 months ago|reply
[^1]: https://www.timdbg.com/posts/writing-a-debugger-from-scratch... [^2]: https://nostarch.com/building-a-debugger
[+] [-] al13n|10 months ago|reply
Didn't expect it to be posted, readme maybe doesn't have enough context. It just says "Essential features are there". What are those? Most of what I've ever used in any debugger:
* Showing code, disassembly, threads, stack traces, local variables.
* Watches, with a little custom expression language. E.g. you can do pointer arithmetic, type casts, turn a pointer+length into an array, show as hex, etc. Access to local and global variables, thread-local variables, registers. Type introspection (e.g. sizeof and offsets of fields).
* Pretty printers for most C++ and Rust standard library types. Probably fragile and version-dependent (e.g. fields names often changes across versions), please report when they don't work.
* Automatically down-casting abstract classes to concrete classes.
* Breakpoints, conditional breakpoints (but no data breakpoints yet).
* Stepping: into/over/out a source code line, into/over a disassembly instruction, over a source code column (when there are multple statements one line, e.g. to skip evaluation of arguments of a function call). All places where control can stop (statements) are highlighted in the code, so you usually don't get surprised by where a step takes you. (...except when there's garbage in debug info, and you end up temporarily on line 0 or something. This happens frustratingly often, and there's not much I can do about it. I already added quite a few workarounds to make stepping less janky in such cases. If a step takes you to an unexpected place, it usually under-steps rather than over-steps, so you can just step again until you end up in the correct place.)
* Various searches: file by name, function by name, function by address (like addr2line), type by name, global variable by name, thread by stack trace.
* Debugging core dumps. There's also a gdump-like tool built in (`nnd --dump-core`) that makes core dump of a running process without killing it; it uses fork to minimize downtime (usually around a second even if there are tens of GB of memory to dump).
* Customizable key bindings, see `nnd --help-files` or `nnd --help-state`.
* TUI with mouse support, tooltips, etc.
[+] [-] mmastrac|10 months ago|reply
For example, a crate that could be linked in to provide some "well-known" object shapes (hashmaps, vec, hashset, etc) with marker values that could be heuristically analyzed to understand the debuggability of those objects?
Alternatively, I'd love to have a crate with recognizers and/or heuristics that could be somewhat debugger-independent and could be worked on for the benefit of other users. I'm quite an experienced Rust developer, just not really with debuggers, happy to help if there's a sandbox project that this could be plugged into.
[+] [-] AtlasBarfed|10 months ago|reply
I cannot tell you how much respect I feel for you
[+] [-] mplanchard|10 months ago|reply
[+] [-] jonstewart|10 months ago|reply
Do you know what would be involved in getting this to work on macOS?
[+] [-] endorphine|10 months ago|reply
[+] [-] dec0dedab0de|10 months ago|reply
Operations that can't be instantaneous (loading debug info, searching for functions and types) should be reasonably efficient, multi-threaded, asynchronous, cancellable, and have progress bars.
I wish this were more common, especially the progress bars thing.
[+] [-] Conscat|10 months ago|reply
[+] [-] PTOB|10 months ago|reply
[+] [-] philsnow|10 months ago|reply
[+] [-] al13n|10 months ago|reply
[+] [-] mbeavitt|10 months ago|reply
[+] [-] shmerl|10 months ago|reply
[+] [-] alfanick|10 months ago|reply
[+] [-] zX41ZdbW|10 months ago|reply
(It shows only about 500 MB of machine code, and the rest of the gigabytes are debug info.)
[+] [-] mmoskal|10 months ago|reply
Not sure about ClickHouse though.
[+] [-] PhilipRoman|10 months ago|reply
[+] [-] mrazomor|10 months ago|reply
[+] [-] eclbg|10 months ago|reply
[+] [-] coldblues|10 months ago|reply
[+] [-] jpeeler|10 months ago|reply
https://github.com/EpicGamesExt/raddebugger/issues/23
[+] [-] tieze|10 months ago|reply
[+] [-] trollbridge|10 months ago|reply
[+] [-] jebarker|10 months ago|reply
[+] [-] sys_64738|10 months ago|reply
[+] [-] tw600040|10 months ago|reply
[+] [-] wormius|10 months ago|reply
Command line often requires a lot of switch memorization. Command Line doesn't offer the full interactive/graphical power in this sort of situation. Command line is great for scripts and long running apps, or super simple interfaces.
Different apps have different requirements. Not everything needs a TUI, not everything needs a GUI, and if you want something similar to a GUI while staying in the terminal. Perhaps you don't have access to a windowing environment for some reason; perhaps you want to keep your requirements low in general.
Finally, why do you care? Some people like it others don't. Nobody comes in and shits on any programs that are GUI if they don't like it, they just don't use it. So, to quote The Dude: "That's just, like, your opinion man". Sorry for the snark, but... It really is, and you're free to have it. But it seems an irrelevant point, and there may be better forums/posts (maybe an "Ask HN" question would be a good option) to discuss this question in depth beyond snark.
[+] [-] yjftsjthsd-h|10 months ago|reply
[0] It is if course possible to make a light GUI and a slow+bloated TUI, but both are less common than the alternative.
[1] Sixel et al. exist but IME they rarely work well. Sadly.
[+] [-] Linux-Fan|10 months ago|reply
Short summary: No animations, No symbols, No touch optimization, no responsive design and I do most of the other stuff in the Terminal anyways so TUI is better "integration" YMMV :)
[+] [-] al13n|10 months ago|reply
[+] [-] KerrAvon|10 months ago|reply
edit: and a reason you would do this locally using ssh is debugging the UI layer itself. if you have to step through the window server, you can't be using the window server at the same time. Remote lldb/gdb debugging is often just flaky. I don't know why they're so unreliable, but they are.
[+] [-] justinrubek|10 months ago|reply
[+] [-] JCattheATM|10 months ago|reply
Other times it's just a contrarian thing.
[+] [-] fsckboy|10 months ago|reply
[+] [-] udev|10 months ago|reply
It is incredible how small and well done that IDE was: hyperlinked (!) documentation, with examples (!!), and awesome debugger.
All with TUI.
[+] [-] larusso|10 months ago|reply
https://cgdb.github.io/
[+] [-] dvektor|10 months ago|reply
[+] [-] worldsavior|10 months ago|reply
[+] [-] Zambyte|10 months ago|reply
[+] [-] jcalabro|10 months ago|reply
[+] [-] unknown|10 months ago|reply
[deleted]
[+] [-] fcoury|10 months ago|reply
[+] [-] danhau|10 months ago|reply
[+] [-] FpUser|10 months ago|reply
[+] [-] Keyframe|10 months ago|reply
[+] [-] HexDecOctBin|10 months ago|reply
[+] [-] deagle50|10 months ago|reply
[+] [-] _bohm|10 months ago|reply