Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Uscope, a new Linux debugger written from scratch (github.com/jcalabro)
262 points by jcalabro 42 days ago | hide | past | favorite | 132 comments
Hi! I've been building a debugger on my nights and weekends because it's fun, and I personally need a better debugger for my work. GDB and LLDB pain me greatly; we can and will do better!

As explained in the README, it's still very early-days and it's not ready for use yet, but check back often because it's improving all the time!

Check out https://calabro.io/uscope for a more detailed explanation.

Thanks for taking a look!




> The available Linux debuggers are gdb and lldb. They both suck. They crash all the time, don't understand the data types I care about, and they don't make the data I need available at my fingertips as quickly as possible.

quote from https://calabro.io/uscope

Of course gdb, lldb have their problems (e.g. smashing tui with app output, what can be easily fixed, or very very very very long tab-tab completion, and crashing of course), but I dont know anything better. I am forced to use visual studio at work and its debugger really sucks - it can't even compare strings in conditional breakpoint, it cant even skip all std::function / std::bind garbage to let me step in callback, it can't watch evaluated expressions. Probably it can evaluate exprs (immediate window?), but there are very little guides about this.

So, gdb is winner for me now. rr (record-repeat)[0] also looks very nice, but it require hardware support(((

[0] https://rr-project.org/


If you're willing to deal with enterprise pricing, Undo [0] implements something reasonably comparable to rr without the hardware timer requirements.

[0] https://undo.io/


Are you aware of solutions for multi-threaded and relative time-accurate recordings, for example by using user-selected synchronization points? Afaiu, rr and undo do simulation of threads on one CPU core, which rules out detecting timing issues.


Co-founder of Undo here. This is a common misunderstanding, and just not true -- neither for Undo nor rr. Most races will reproduce at least as easily in Undo, especially if you use our "thread fuzzing" feature (rr has something similar, called chaos mode).

Sure, there will always be some races/timing issues that just won't repro under recording (Heisenberg principal and all that), but in fact most races are _more likely_ to occur under recording. Part of this is because you slow down the process being recorded, which is equivalent to speeding up the outside world.

And of course, when you do have your gnarly timing issue captured in a recording, it's usually trivial to root-cause exactly what happened. Our customers tell us that races and timing issues are a major use-case.


Thanks for clarification. I have not been aware of thread fuzzing and chaos mode before.


Multiplexing onto a single thread is sufficient to observe and record concurrency errors. If that is not sufficient, then I am assuming you want to observe and record errors caused by true parallelism. If so, then you need a full memory trace. That restricts you to either hardware that supports full memory trace connected to a hardware trace probe or instrumented software full memory trace.

The former basically only exists for embedded boards and the latter does not exist (at say less than a 10x slowdown) for Linux or any other common desktop operating system as far as I am aware.


So the only way to trace probe consumer desktop CPUs and possibly GPUs is by the hardware vendors them-self or specialized facilities/laboratories? For Intel I can find https://www.lauterbach.com/supported-platforms/architectures..., but nothing for trace probing AMD or later versions.


You can trace consumer desktop CPUs using instrumented software full memory trace, but that requires OS + debugger + compiler support which is not available for Linux, Windows, Mac, etc.

You can trace hardware that exposes trace functionality usually via a debug port of some kind. Many chips have trace functionality in their production design, but no debug connector is physically present in off-the-shelf boards (to reduce manufacturing cost). You can usually physically modify the board to get access to this functionality which is routinely done when porting software to a new chip/board.

Trace functionality comes in two major flavors, control flow trace and memory trace. Control flow trace only records control flow, so the contents of memory are unknown which is not very useful for your desired use case. Memory trace records memory accesses, so the contents of memory are known. Unfortunately, memory trace is very resource intensive, so most systems that support trace only implement control flow trace. As far as I am aware, it is very unlikely that any desktop or server CPU has memory trace.

The major manufacturers of trace probes and solutions that I know of are Green Hills Software, Lauterbach, and Segger.


Thanks for your write-up, this is very helpful for understanding.


While the single-threaded execution means that issues from thread interleaving on the scale of nanoseconds will effectively not happen, multiple threads are still allowed and will be context-switched between. rr also has a chaos mode to intentionally make the context switching unfair.


What kind/class of issues are caused by "thread interleaving on the scale of nanoseconds"? Faulty CPU bit flips due to radiation/quantum effects or what are you referring to? Just curious.


Not doing things atomically when they should be (incl. missing locks around tiny ops) would be a pretty large class.

With native multithreading data can pass from thread to thread millions of times per second, and you're much less likely to hit obscure interactions when limited instead to maybe a couple hundred context switches per second.


Exactly right. Undo has "thread fuzzing" which is similar concept to chaos mode, but more targeted.


Antithesis is the only general purpose system I've seen for that. It takes the same single threaded approach, but can scale to N separate systems and fault injecting possible orderings.


eh, thanks

> How can I persuade my boss to pay for Undo?

fun quote.. but my boss will never pay for it because I am the only one who use gdb in our company, unfortunately)


For what it's worth we do offer a more printf-y interface for people who don't like a debugger - https://docs.undo.io/PostFailureLogging.html

And CLion / VS Code for people who prefer an IDE interface.

But a lot of people do really want to stick with their printf debugging.

If your boss won't buy you an Undo you can still use https://rr-project.org/ - or on Windows the built in time travel debug of WinDbg.


  > gdb(..) smashing tui with app output
this got me losing my mind. How/why propose this tempting TUI mode when the result looks like a broken arcade game ??

How do you people comfortably debug C in Linux ? I know VSCode looks nice but by principle I can't accept to use such a beast to basically edit code..


> How do you people comfortably debug C in Linux?

same way I debug everything, everywhere: logging.


That not very environmentally friendly.


> How do you people comfortably debug C in Linux ?

I just got comfortable using gdb/lldb from the terminal. Once you get used to it, it's fine (albeit not pretty).


The advantage for text based interfaces is that they work over ssh/tmate over trans atlantic connections whereas the GUI tools would suffer greatly. It just works everywhere and if you learn it, it will be just as good as a gui debugger. Potentially even more ergonomic without hunting for options with a mouse.


I‘m using cgdb, which is a minimal ncurses wrapper around gdb. It‘s a lot better than the TUI of gdb.


Termdebug works great with gdb, and I get my usual editor features as well as the full functionality of gdb. Seems fine to me.

Before I switched from emacs I had an equivalently good setup with dap-mode.


Use Emacs to drive gdb (through the GUD mode) gives a much more ergonomic interface. It highlights the line of code being traced in the code window.


as I said - this easy to fix once and for ever

Also not all apps write to stdout/stderr by default.

> How do you people comfortably debug C in Linux ?

It depends on what comfortable is for you. Most of my pc experience is terminal and browser and this is comfortable for me. I just use gdb for debugging. Sometimes trying lldb


emacs. Worked great for decades and works great today. Learn it.


rr should work on any remotely modern Intel system, and generally on AMD's Zen CPUs too. Unless you're in a virtualized environment (some of which are supported) or a more esoteric architecture rr probably works on your silicon.


I have AMD Ryzen 5 3500U with Radeon Vega Mobile Gfx (8) @ 2.100GHz.

As I remember - it is should work according to documentation, but I couldn't launch it. Probably I'm not spend enough time to solve errors


You probably need the fix from this page: https://github.com/rr-debugger/rr/wiki/Zen


Which visual studio are you using?

It’s been a number of years since I’ve used it but Visual Studio PRO could do all these things - at least as long as I was using it (since visual c++ 5).

VS Code on the other hand is no where near as featured or powerful.


I use VS2022 Enterprise

If you know solutions, I will be very thankful for any info.

P.S.

Note, though I meet all of this problems, probably I don't spent enough time to find a solution (maybe tried first links at google and so on). E.g. tried `strcmp` for breakpoints, tried to write .natstepfilter.

So, if VS really can do all of this, I'm sorry for my hurry.


I don't know for c but for C# you can write a custom expression that get evaluated for the condition.


Man, if you read my comments lately you would think I'm a Microsoft fanboy, sheesh.

But honestly, in all my years, Visual Studio has been (by far) the best non-commercial (or should I say built-in?) debugger that I've used, and that includes gdb.

I am not a huge c++ on Windows guy though, so YMMV.

Here are a few guides that you may find helpful (and I am also going to include the beginner one, but please do not take that as an indictment of your skill level, I am including only for completeness).

These are all for VS2022:

C++ Debugging Tutorial: https://learn.microsoft.com/en-us/visualstudio/debugger/gett...

C++ Breakpoint Debugging: https://learn.microsoft.com/en-us/visualstudio/debugger/usin...

Breakpoint/Watch Expressions (pay attention to the debugger intrinsics): https://learn.microsoft.com/en-us/visualstudio/debugger/expr...

High Level Debugger Tour: https://learn.microsoft.com/en-us/visualstudio/debugger/debu...

VS2022 Debugging TOC: https://learn.microsoft.com/en-us/visualstudio/debugger/?vie...

My apologies if you've already found these references and they don't do you any good, but your issues just don't sound like the types of issues I've ever experienced with the debugger, and sometimes MS' documentation is just disorganized and incomplete.


I'm a UNIX guy through and through, literally everything I ever do is writing code on Linux or macOS which targets Linux and/or macOS. I loathe almost everything about the whole Windows ecosystem, from Microsoft as a company to the way they build their UIs to the technical foundations of Windows.

However I have to give them one thing: their developer tooling with Visual Studio and other first-party tools seem vastly superior than anything on macOS/Linux when it comes to debugging. I would never use it as a code editor, but it's clear that a lot of effort has been invested into the debugging experience.


very thanks, this will be useful to simplify my debugging!

> and I am also going to include the beginner one, but please do not take that as an indictment of your skill level

Don't worry, I am really feel myself as newbie in windows


Out of interest what are your main use cases for needing conditional breakpoints?


For example for debugging gui apps. Let's say we have function `on_event(event_type)` and you want to examine execution if `event_type == mouse_up`.

In reality conditional breakpoint is the same as simple, but simple require support from code:

``` void on_event(event_type type) { if (type == mouse_up) { // set breakpoint here } } ```

Also useful to break depending on call stack[0]

[0] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Conve...


Yeah, I was specifically wondering about cases where you can't or don't want to change the source code. Sometimes that happens when I need to explore the state after a long process e.g. loading a large file. Generally though I avoid them like the plague as they make the code so slow. Curious to know what other people use it for.


  > Build as a library so other people can build other interesting things as well 
I LOVE this!

I firmly believe so much tech has gone to shit because things are no longer hackable. We say "move fast and break things" but we try so hard to prevent that that when we do break things we just create bigger messes and debt, so no one cleans it up. It seems slower to write hackable code but that's in the moment. In the long run it is much faster. Not to mention you get added benefits of others being able to contribute more easily with a lower likelihood of actually breaking shit.


Is gdb another thing like gcc where the un-hackability and un-extendability was a deliberate choice by rms to ensure nobody would ever build proprietary toolchains on top of it?


I don't know if it was deliberate, but writing code that interfaces with GDB is unpleasant enough that I opted to build our debugger-like tooling in eBPF + pyelftools instead.


No, GDB has a pretty good Python extension framework


That's not comparable. That lets you extend GDB with your own additions. Having the debugger work as a library means being able to incorporate the debugger's functionality into other systems.


Yes, this. I write a lot of my own GDB tooling for debugging my kernel.


gdb is a bit old and my comment is really more about building things in general.

You should always make things hackable, not just for others, but for you. One truth to coding is that the final thing will never end up where you think it will. So if you don't make your code flexible (i.e. hackable) then you're going to keep breaking it while fixing it. Things will continue to be patches and quick fixes. Nothing is more permanent than a temporary fix that works.

Truthfully, this is part of the unix philosophy. Make your programs small and integratable. The strategy is not to be finished, because there is no end, the strategy is to be adaptable, because there is no end.


This is great to see. It'd be lovely if Linux gets a decent debugger. Another project to keep an eye on is https://github.com/EpicGamesExt/raddebugger Although, they haven't expanded much beyond Windows, yet.


They fully plan to support Linux.


Author just did a podcast about Uscope a few minutes ago, where they mention this HN post:

https://youtu.be/stWBTv6grBc

Mentioned at : https://youtu.be/stWBTv6grBc?t=456


Looks promising -- it's about time, I haven't been satisfied with any debugger since the days of Periscope!

https://www.os2museum.com/files/docs/periscope/periscope-man...


Somehow this brought the memory of Numega's awesome SoftICE!


Oh yea, we used both SoftICE and Periscope. I loved the pushbutton to fire off an NMI directly on the ISA bus. It was sad when your device driver crashed but it was a fun experience to push that button.


I've used only few times back then, but it was impressive (previous experience was with Borland's / Turbo debuggers which was nice also, but Numega was just another class)


Yay this is awesome! GDB is a buggy (https://sourceware.org/bugzilla/show_bug.cgi?id=18772 https://sourceware.org/bugzilla/show_bug.cgi?id=9425) mess and rough code quality, I've wanted a do something like this for a while.

To be 100% clear, it's not using gdb/gdbserver under the hood right?

The bugs I linked above are over a decade old, and I have to patch them every time I compile GDB server. Ultimately (IIRC) GDB needs to rework how it handles signals (to their credit, ptrace is a horribly stupid API, especially before PTRACE_SEIZE, so I don't blame them for having issues)


Interesting, LLDB also has a serious bug related to ^c! In LLDB, if you run 'lldb -o run /path/to/executable', it won't pause on SIGINT. As a result, you can't have an ergonomic setup where you have e.g a make target to run your software under LLDB, you always need to manually type 'run' for ^c to work.


This is definitely an ambitious project, and I worry that you are biting off more than you can chew in doing so. (I've attempted my fair share of debugger projects in the past).

At a low level, one of the main problems is that Linux's kernel interfaces for debugging are just absolute trash. (I see you have multithreaded support mentioned as a future task item, and that's one of the areas where you discover just how bad it really is). And of course ptrace composes somewhat poorly with, well, anything else, so if you want to use perf_event or eBPF to help drive the low-level stuff, well, combining everything into a single event loop is just painful. (Oh, and the documentation for all of this stuff sucks.)

At the medium level, everything is hampered by the number of secret handshakes that go on between the compiler, the linker, the runtime loader, the debugger. And the chronic issue that, in the debugger, you have to be prepared for the possibility that everything is just catastrophically wrong: your stack might be garbage (or downright nonexistent), the thread-local storage register might be a garbage value, variables may have values that don't make sense. After all, you're resorting to a debugger when things don't work, and part of the reason why it might not be working is because you've accidentally corrupted everything.

And at the high level, there's the UI which, as someone who doesn't work on UI, I find terrifying in its own right.

Trying to solve not one of these issues, but all of them, at once, in a new project is ambitious. I'd personally prefer a lot more a project that only tried to tackle one slice of the stack, not all of it.


Yup, Linux is nowhere the Unix successor we deserved. I have started multiple systems projects in Linux and gave always given up due to how shoddy the foundations are. It seems like the kernel just copies whatever cool feature they find in Solaris, BSD, Plan 9 or even NT without paying any attention to their composability, while the user space people are just a clique trying to force their way on everyone (why is the loader part of libc again?).


There are a few things where Linux has been the innovator (eBPF comes to mind).

But process control is not one of them, and almost any other operating system manages to have a more sane interface. Personally, if I were writing a debugger, I think the OS with the sanest kernel interface is probably Fuchsia, partially because everything is handle-based and partially because pretty much every syscall takes in a handle to the process to operate on, so you can do things like manipulate memory maps of another process without driving yourself insane.


He's live on twitch right now demoing this on zig showtime: https://www.twitch.tv/kristoff_it



Nice project!

One killer feature would be the ability to connect to the debugger via a socket and control it. Gdb has this interface and for some use cases it's great.

As one of those long-tail "native" languages, Virgil might benefit from this. So far, I've had a student build a DWARF backend, and the experience from that is that DWARF is way too complicated and consequently implementations are broken and crappy in many ways. I think DWARF draws the wrong dividing line here. Control of the machine and customizing the source-level support to the language is probably better.


Speaking as a Java guy, remote debugging is SO useful (at times anyway). Thankfully the JVM has built in support for a remote debugging protocol[1] and there are good debuggers that can connect to a running Java system (if it was started with the correct command line flags) and do symbolic debugging over the network.

There can be certain situations where the network latency can make things difficult, but generally speaking I find it an incredibly useful facility to have.

[1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jpda/...


Which debuggers do you like the most?


> the experience from that is that DWARF is way too complicated

The representation and the compression are far too intertwined :(


Oh, and there needs to be some sort of declarative, rules-based DWARF checker. Preferably one that doesn't only work on complete files (or collections of files) but also handles snippets.

If it's fast and can work on snippets before they are even written to disk, we can probably catch many compiler bugs.


Have it use the WebKit debugger protocol and we can use browser dev tools as the UI.

:p


Keep at it!

raddbg is one worth watching too (currently only Windows x64) https://github.com/EpicGamesExt/raddebugger


Very happy to see the increasing momentum in the zig community


Nice work! I remember meeting you at Systems Distributed in NYC where you mentioned this project, so cool to see the progress. Well done!


Everyone here seems to thing GDB is awful. It's been a while for me but I remember using front-ends like Eclipse's CDT or similar and didn't find that experience so bad. Do most people use GDB straight-up? I haven't done that in probably 15 years although it's nice to have a lightweight command line on small embedded systems.


> Everyone here seems to thing GDB is awful. It's been a while for me but I remember using front-ends like Eclipse's CDT or similar and didn't find that experience so bad. Do most people use GDB straight-up? I haven't done that in probably 15 years although it's nice to have a lightweight command line on small embedded systems.

the issue is not with gdb's UX - you can build as many cool UI / UX on top of it as you want. The problem is that gdb will sometimes take 5 minutes to start debugging (and that's without debuginfod), straight up crash, be unable to resolve obvious symbols etc. which are all back-end bugs. For me developing a medium-sized C++ app, it's really hell to use and usually printf debugging is MUCH faster in the sense that I have the time to find and fix my problem through an iterative recompile cycle sometimes before gdb has even finished parsing my binary


> The problem is that gdb will sometimes take 5 minutes to start debugging

If you run gdb-add-index on the relevant binaries ahead of time it should start up much faster.


Said binary is modified by me every time I change something while building (and I used to build with gdb-index but recently this caused crashes with another build flag so I had to disable it.. though maybe it's fixed with last gdb release?)


I do use GDB straight up for native programs and microcontrollers, mostly out of laziness. I haven't set up VS Code debugging at my current day job yet and it's been 6 months.

Out of the box GDB is kinda awful, especially for C++ codebases. I should probably look into scripting at some point, but meh. Even then, as far as I know I'm the best at using a debugger at work by a wide margin, but I attribute that more to my knowledge of low-level programming than my ability to use most of the basic GDB commands. Also, it tends to crash once a month or so.

If I needed to debug a userland program on a small Linux embedded system, I'd probably whip out gdbserver and attach gdb to the target remotely. I haven't done that in a while though.


example from today, timed with a stopwatch, on a 5950X 5GHz CPU: from the moment I click on "debug" in my IDE,

- lldb takes 40 seconds to reach "main"

- 2 minutes 36 total to reach the GUI and start being able to reproduce things

- gdb coredumps as soon as I want to put a breakpoint so it's unuseable

    $ lldb --version
    lldb version 19.1.7
    $ gdb  --version
    GNU gdb (GDB) 16.1


This is exciting! I use GDB and LLDB, but their TUIs/CLIs make certain things difficult (I feel like debugging seriously benefits from a proper GUI) and graphical front-ends I've tried are pretty janky. Looking forward to trying it out, but I'm excited to see something happening in this space.


This opinion is not backed by facts, any insight about linux (or even the languages in question), or even related to this post. Nevertheless, I wonder if it was a good idea to allow rust contributions to the linux project. From all of the bits and pieces I read about zig (including this project), I feel like it would have been better aligned (than rust) to pick up where the mainly C codebase left off.


Zig isn't 1.0 so..


Not really. Zig's answer to safety is mostly based on runtime panics, and the kernel really, really hates panics.

As such, the only thing left is better ergonomics, and that's not really worth the effort to switch.

Rust isn't being adopted because it's an easier language to code in, and in fact it's being adopted in spite of the fact that it's harder to code in. And that's because to some kernel devs, the promise of better security and fewer vulnerabilities is worth that much.

On the other hand, Zig is great for user-space applications. The stuff to replace GNU's coreutils with.


> Zig's answer to safety is mostly based on runtime panics

This statement is nonsensical.

Zig's answer to safety is based on a precise type system and a simple language that helps the programmer in their quest to write perfect code. If a kernel panics, that is either a bug or hardware failure.


> This statement is nonsensical.

You're right, my bad. It is hard to be precise in a comment where I'm trying to be as concise as possible.

I'm sure you know what I mean though, with regards to temporal memory safety (lifetimes), data races (Send/Sync traits), etc. Rust works by preventing many classes of bugs through compile errors, rather than panics.

> If a kernel panics, that is either a bug or hardware failure.

And this is where Rust differs; Rust will reduce the likelihood of bugs from happening in the first place. I'm not saying Zig doesn't also do that, Rust just does it more.

The Rust compiler devs, in their quest to make a type system that is powerful enough to catch most memory corruption errors, somehow came up with something that can be used to catch far more issues than just that.

The affine(ish) type system, coupled with lifetimes, makes modeling and maintaining correct states much easier than in Zig, for all sorts of objects and abstractions.

From what I've read from Linus on LKML/lore along the years, a kernel oops/panic is seen as one of the worst things that could happen to it; there is generally nothing the user can do at that point to debug it (they likely won't even see the console), and makes the machine unusable for all other tasks. Sometimes you might be lucky and just kill and collect the thread that panicked, but oftentimes you get the nuclear OOPS option. With Zig you don't even get the option to catch it via something like catch_unwind.


> And this is where Rust differs; Rust will reduce the likelihood of bugs from happening in the first place. I'm not saying Zig doesn't also do that, Rust just does it more.

I'd argue that it does this a LOT more. When it comes to spatial safety, Rust and Zig are on par. However in terms of temporal safety I think Zig lags far behind Rust... along with basically every other compiled systems language.

If you had to come up with a single good reason to use Rust over Zig, it would definitely be temporal safety. A majority of applications don't need this though, or can be designed such that they don't.

One of my main issues with Rust is that it makes it easy to write spaghetti code that uses reference counting all over the place. I don't recommend people to use Rust until they become a "N+1 programmer" that Casey Muratori describes as "grouped element thinking" [1]. At this point, most of that programmers problems are solved and suddenly the Zig vs Rust debate becomes much more nuanced.

[1] https://www.youtube.com/watch?v=xt1KNDmOYqA


> until they become a "N+1 programmer" that Casey Muratori describes as "grouped element thinking"

Thank you for this great link.


> When it comes to spatial safety

Only at the cost of runtime checks and/or misusable allocator passing.


> Only at the cost of runtime checks

And those checks are well worth paying for, enough that Rust also has them! I'm sure Rust would have even worse ergonomics if it insisted on no runtime bounds/unwrap checks. The performance cost is low enough that every systems programming language should have spatial safety. To illustrate, Google found that hardening libc++ by adding bounds checks only led to a 0.30% performance impact on their services [1]. It's not hard to imagine that a similar run-time cost affects Zig and Rust. Both languages make attempts to optimize the checks away if the operation is known-safe. Although, maybe Rust is more successful due to the borrow checker.

> and/or misusable allocator passing.

Could you clarify how allocator misuse might lead to a spatial safety violation?

[1] https://security.googleblog.com/2024/11/retrofitting-spatial...


I've done a couple of projects in Rust, and I can appreciate this sentiment.

I don't think my code was pretty and I know it wasn't idiomatic. But I have some experience in writing concurrent code, so I have an understanding of the reasoning behind Rust's borrowing semantics, why lifetimes are important, and the difference between boxed values, rc, arc, and I additionally understand the semantics of semaphores, mutexes, spinlocks, and critical sections.

(As an aside, I don't know if I'm an N+1 programmer. My code works, long term, requires very little maintenance, and generally stays out the way. Just the way I like it.)

But- I see these recurring themes in posts from Rustaceans along the lines of "the compiler tells you what's wrong" and "if it compiles, it's correct!"

These kinds of statements worry me. Not necessarily because I think their code is going to blow something up, but because I think a sizeable portion of the community does not really understand the guarantees Rust provides, and under what contexts they are valid. I mean, sure, you might not have a data race, but you sure as hell can code yourself into race condition or a deadlock, and from what I understand from HNers, these situations are not all that uncommon in Rust crates. I'm also led to believe that the panic handling situation in some crates isn't ideal.

You shouldn't just haphazardly Arc<Mutex<T>> all the things just because that gives you the Send + Sync that you think you're looking for (or the compiler is looking for). You should understand what the hell you're doing, be able to tell if those things are necessary, and understand the ramifications of using those abstractions.

I think there's a lot of good going on in the Rust ecosystem, and I wish I had more work in that area, but there's a lot of blind advocacy there that assumes the Rust approach is the best, but the language does have serious ergonomic limitations in certain low level scenarios. My whole career I've had to focus on scope and objects that outlive their scope, but now every other word I seem to hear from the Rust community is "Lifetimes" and "Ownership", like these concepts were completely unfamiliar to developers before and now the Rust Way(tm) is not only THE WAY, but THE ONLY RIGHT WAY.

I don't want to go too far off the rails, because I find the ecosystem intriguing, and I see tremendous value there. Whether those approaches stand the test of time isn't a given (although let's face it, they probably will because they are sound and they are gaining developer mindshare, which is the most important factor).

I just worry about ergonomics. Coding is not supposed to be easy, so please don't misunderstand- but coding, especially for those that do it day in and day out for decades, should not be a chore. There are definitely some QOL improvements that could be realized in the near term, although I'm not sure what those would look like.


I actually find that their comment makes a lot more sense than yours.


Andy Kelley's comment corrected unintentional flamebait. I don't see how his comment was confusing.


Rust also has runtime panics (e.g. indexing outside the bounds of a slice) - how does kernel Rust handle that?


It does not, for slice indexing Rust is just as bad. My best guess is that this will likely blow up into such a big issue that the Rust devs are going to be forced to implement a feature to disable indexing (and leave just the safe .get()), or the kernel devs will fork the core library.

But Rust prevents a myriad of other things that would be panics in Zig or undefined behavior in C. It has a really strong type system, capable of reducing a large amount of invalid states and keeping many invariants throughout very large codebases.


Static checks remove many more potential sources of panic. I suspect that with certain restraint one can write Rust code that is statically guaranteed to not panic.

Also, Rust's panics may be recoverable, it's not necessarily fatal.


Yes it would be better C, but compared to Rust, is that enough?


Congrats on this work -- writing a debugger from scratch is a big job. I have cloned the repo, will take a proper look this w/e.


How does it compare to gf?

https://github.com/nakst/gf


gf is a frontend to gdb. This is supposed to be a brand new debugger


orthogonal to the question


It's not clear to me why we'd need a new debugger instead of GDB enhancements. GDB has an extensible, modern C++ codebase with literal decades of hard earned knowledge baked into it.

How are we better off rewriting it, especially if the rewrite isn't memory safe?


> GDB has an extensible, modern C++ codebase with literal decades of hard earned knowledge baked into it.

I literally laughed outloud at this. Have you ever actually opened a GDB source file? It is, as a whole, extremely poor quality code. Almost all of it is doing C string manipulation and raw pointer arithmetic; almost none of it uses C++ smart pointers, nevermind the rest of "modern C++"; the vast majority is completely uncommented, and "literal decades of hard earned knowledge" can be better translated as "literal decades of historical baggage, cruft, and hacks". I regularly cause GDB to segfault in normal, mundane operations.


  > It's not clear to me why we'd need a new debugger
People build things for fun. Stop asking "why" and ask "why not?"

No one can really predict what's needed and where we need to go, so let people just explore. Sometimes they won't find things, but sometimes they do. And if they don't, they still gain useful knowledge that pays dividends later on anyways.

It's Hacker News, let people hack.


Consider this part of the post:

>I've been building a debugger on my nights and weeks because it's fun


I'm considering the part that says "GDB and LLDB pain me greatly". This project both says "I'm doing this for fun" and "the state of the art is bad, and I'm trying to fix it", so this is a fair question.

GDB is great. He says it crashes a lot, and cannot interpret some of his types. Maybe that's his experience, but I haven't had those issues after literally decades of using gdb. Some bug reports would be nice.


After literally decades of occasionally dipping into GDB only to quickly remember why I would rather use no debugger at all than that, it's hard to imagine what you could mean by "great". What are you comparing it to?


Decades for me as well, and we’ve had very different experiences : gdb is very powerful , but the user experience is atrocious and it does crash a lot.

To be fair, in a number of cases the type issues I had were not gdb’s fault but bad DWARF produced by the compiler.


GDB is awful and a replacement is sorely needed. It's buggy and slow and feature poor and has a terrible UI and a terrible API which makes all the frontends terrible in turn. I haven't looked at its code but I'm betting it's terrible too.


I haven't tried UScope yet (I shall), but I don't agree with you about GDB. I don't find it especially buggy unless doing niche things like non-stop debugging -- I guess you may well have a different experience though.

I think the UI is much maligned unfairly. It has a few quirks, but ever used git? For the most part it's fairly consistent and well thought through.

By terrible API you mean the Python? I admit it can be a bit verbose, but gives me what I find I need.

What features do you most miss? My experience is that most people use like 1% of the features, so not sure adding more will make a big difference to most people.


It's been a while since I bothered to try to use it because my experience has been so bad. So I don't remember all my specific complaints about bugs and features. I do remember multi process debugging was a big hole last time I looked. In contrast, I was able to get multi process debugging working really well in Visual Studio.

By terrible API I mean GDB/MI that frontends use. I'm sure people will come try to defend it but the proof is in the pudding and I don't think it's a coincidence that every GDB frontend sucks.


I'll +1 GDB/MI being utter garbage. Bespoke format (ordered multimap as the only keyed data structure, why), weird quoting requirements (or sometimes requirement of lack thereof) on input, extremely incomplete, and in some cases nearly unusable even for what it does support. Feels more like carelessly shoehorning some of the existing gdb commands with a different syntax (but sometimes not different) than an actual API.


If it's been a long time I recommend taking another look. TBF you can tell it hasn't had the millions of dollars of investment that the Microsoft debuggers have, but still it's come a long way over the last 5-10 years.

e.g. it now has decent multi-process support.

I agree MI is kinda horrid, but no need for it these days, you can do everything via the Python API, and the modern equivalent is Debug Adapter Protocol which GDB claims to support now (although I haven't tried).

There a million frontends, including both Visual Studio (via ssh) and VSCode, if you like those.

The perfect developer tool does not exist, but I believe that if you're debugging native code on Linux more than a few times per year then you should really know how to drive GDB. It won't always be the best tool for the job, but it often will be.


> What features do you most miss?

one time I wanted to write generic printers. E.g. printer of any type which support C++ iterators. But gdb can't call C++ functions from python api (excepting weird hacks like evaluating `print c.begin()` and catching it output). Although this is not very useful because most of types we use changes very rarely, that's why writing printers is only matter of time.

Another feature is breakpoints which sleep next N seconds. We have breakpoints which can skip next N triggering, but similar with time will be useful to me to debug mouse events in gui apps, etc.

Also the most new gdb still have problems with tab-tab completion (and even Ctrl-C don't return control immediately).

Also lately I often meet problem cannot insert breakpoint 0. Probably this is a bug, because answers from stackoverflow isn't relevant for me


> one time I wanted to write generic printers. E.g. printer of any type which support C++ iterators.

How would that work for types where the required functions are not instantiated, or not instantiated as a standalone function? Most iterators' operator++ are inlined and probably never instantiated as a distinct function.


> How would that work for types where the required functions are not instantiated

Obviously, it will not. But why not to try?)

> Most iterators' operator++ are inlined

Sure, it's sad.

But I'm still think that such feature - calling C++ functions from Python API - can be useful.


> excepting weird hacks like evaluating `print c.begin()` and catching it output)

Why do you consider that a weird hack instead of legitimate programming technique?


If this is not weird hack, why gdb provide api for getting C++ variables values instead of using this "legitimate programming technique"?


> a terrible API which makes all the frontends terrible in turn

I don't know the details. But nowadays gdb supports DAP, as any other debugger: https://www.sourceware.org/gdb/current/onlinedocs/gdb.html/D...

Are you talking about this, or the old https://www.sourceware.org/gdb/current/onlinedocs/gdb.html/G... ?


Thanks, I hadn't seen that, seems like it was just released a year ago. Seems like a step forward. I was talking about GDB/MI, which was the main (only?) option for decades and could still be considered the "native" frontend API of GDB.


Well, you can start by tearing down all the fences and firing that Chesterton guy's sorry ass. After all, even a 32-bit ARMv7 uses .eh_unwind sections to crawl the stack for a backtrace, right?

Then, you can focus on resolving edge cases that can cause papercuts. Make sure the solutions are at the expense of the happy path because that's all been solved long ago so there's no need to pay attention to it.


Super supportive as I really value debuggers as tools even tho they are horror shows to use!

> Similarly, the following features are non-goals of the project:

> Supporting non-native languages (i.e. Java, Python, etc.)

But I think that position is likely a mistake in terms of leaving killer features on the table and baking in architecture decisions that might continue to make these kinds of features impossible / very low-class experiences.

Properly integrating with the python interpreter to be able to debug python + c/cpp extensions running in the same process is a huge missing whole in the debugger market.

I don't know how other people do it but I 'solve' this problem by attaching either a python debugger or lldb to the python process -- meaning I can debug either python or the cpp but not both at the same time. The experience is very lacking. Even just seeing the python call-stack while paused at a cpp breakpoint would be huge.


We've got a prototype of debugging in python and C/C++ in GDB - https://undo.io/resources/how-i-debug-python-code-with-a-tim...

If you'd like to try it please get in touch, feedback is always useful.


One thing that as far as I know no single debuggers has (except FoxPro from DOS) is the ability to show a large list of things, but well

In general, if something is large (text, arrays, etc) all bets are off.

Basically, something like this:

https://github.com/okbob/pspg

---

The second thing that is very hard with debuggers, is to tell them what to skip.

In the normal sense of 'I don't wanna debug Rust std' but also 'What the heck, why is stepping into #[Debug]???'


GDB (I don't use LLDB) is fully programmable and has multiple user interfaces (TUI, Emacs, DDD, graphical frontends and various .gdbinit configurations that emulate SoftICE L&F).

It's a power tool and takes some time and effort to learn and master. Superficially dismissing it / wasting your time with something that in all likelihood will end up going nowhere while lacking most features that make GDB great, does not a good recommendation make.

At least you'll probably learn a thing or two while you implement it, but I'd rather not waste my time using it.


How entwined is it with Linux specific APIs? Eg, how hard would it be to port to FreeBSD?


TotalView (which I rep), Linaro DDT - thoughts? (Yes, they’re both proprietary)


how much do those cost approx? for an individual hobbyist developer


> The available Linux debuggers are gdb and lldb. They both suck. They crash all the time, don't understand the data types I care about, and they don't make the data I need available at my fingertips as quickly as possible.

Okay, so this is the author's answer to the most important question: "why?"

For me this is a serious issue, making strong statements without any single backing example. If you experience crashes, please report to the maintainers - i guarantee that you won't be ignored. You say that it's missing some data that you need? Fine, but be precise - what data?

Otherwise it sounds like a "yeah, let's make a project for fun and pretend that it's serious by finding sort-of-justification/use case" (i'm not telling that it is the case for you - i'm telling that it sounds like it, based on your own description).

Also, would you feel nice if i put in my project's README a note that the project of you, the one that you put your effort to, "sucks"?


There are almost 4000 open issues on gdb reported more than five years ago.

In this conversation are reports of an annoying bug that requires a user patch gdb and it's existed for almost twenty years.

It was years before anyone was even assigned because of a bug in their bug tracking system, and they haven't addressed any further comments over the decades.


I'd rather the time taken enumerating the deficiencies of existing debuggers be spent building something better instead. I doubt many people that have used gdb/lldb need convincing that that's possible. If it is needed, Microsoft's windbg (far from what's possible but light years ahead of gdb/lldb) is a proof by construction.


Bit of a possibly unpopular take but I very much disagree. The syntax of windbg/cdb is just... Really bad. I feel like I'm writing assembly and the mnemonics don't actually align with what the command does. So it's difficult for me to get confident with it. At least the commands in gdb make sense (and I wish gdb supported windows executables, but alas...)


windbg has no sane library api, which makes it by construction unsuitable for automation and inspection.

I'd personally prefer, if we would have the options of multiple time-travel debugging sessions based on synchronization points (if needed) being overlapped to single out bugs in interesting areas (not covered by static or dynamic analysis). Debugger would be essentially a virtual program slicer being able to hide unnecessary program parts or reduce it. However, so far we neither have the options for piece-wise time-accurate multi-threading recording, nor slicing overlays nor in-memory reducers (ideally also reducing AST). I may be mistaken on "piece-wise time-accurate multi-threading", since I've not checked what is possible with hardware yet.

Heck, we dont even have overview data for common bug classes and cost for verification or runtime-checking in academia etc.


Make it debug systemd config problems and I'd be thrilled.


To clarify “from scratch” as in from basic materials and not “in scratch” as in the MIT graphical programming g system[0]. It appears to be written in Zig[1], which I find interesting for analysis.

0. https://scratch.mit.edu/

1. https://github.com/jcalabro/uscope


lol, I think no one expected a linux debugger to be written in the visual programming language for kids.


I'd be very impressed if it were, though.


"written from scratch" is one of those phrases that seems to cause any submission to instantly hit HN frontpage, along with "for fun and profit", "considered harmful", and a couple others.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: