1. 52
    1. 9

      Good debugger support is my #2 biggest wish for Rust. I’d love to be able to use gdb, but unfortunately even simple things are “broken”. For example, here’s a simple program that has a string and a struct and an enum containing a string:

      #[derive(Debug)]
      struct MyStruct {
          my_inner_string: String,
      }
      
      #[derive(Debug)]
      enum MyEnum {
          Str(String),
      }
      
      fn main() {
          let s = "Hello, debugger!".to_string();
          let t = MyStruct { my_inner_string: s.clone() };
          let e = MyEnum::Str(s.clone());
          println!("{} {:?} {:?}", s, t, e);
      }
      

      A String in Rust is also a struct (pointer, length, capacity), but I can print it nicely in rust-gdb:

      (gdb) print s
      $1 = "Hello, debugger!"
      

      However, when I print a struct or an enum containing a string, here’s what it looks like:

      (gdb) print t
      $2 = dbg::MyStruct {my_inner_string: alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x5555555a79f0}, _marker: core::marker::PhantomData<u8>}, cap: 16, alloc: alloc::alloc::Global}, len: 16}}}
      
      $3 = dbg::MyEnum::Str(alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x5555555a7a10}, _marker: core::marker::PhantomData<u8>}, cap: 16, alloc: alloc::alloc::Global}, len: 16}})
      

      Since most data in a real Rust program sits in structs and enums, the debugger experience is made almost useless because looking at data is really hard. I’m not sure also that rust-gdb can deal with async code (please teach me if it can).

      1. 2

        I’m not sure also that rust-gdb can deal with async code (please teach me if it can).

        I started playing with Rust a couple of months ago, so still very new to the game, but I’ve been using Tokio Console and it has been pretty cool so far! (This assumes that you are using Tokio, of course)

      2. 1

        I’ve only played with Rust a bit, but is that with rust-gdb? Even if not, it seems like something GDB’s Python scripting could fix easily enough.

    2. 4

      And yet linux still doesn’t have a good UI for all these fancy options. :(

      1. 3

        I think the JetBrains tools provide a pretty good one. Or at least PyCharm and Clion do. Honestly, those two debugger UIs are half the reason I’m willing to pay their toolbox renewal every year.

        The integration between the python repl and the debugger UI feels like pure magic. And being able to step from python into C++ and back has been wildly useful in the past too.

      2. 2

        I tried all of the gdb wrappers ~5 years ago and cgdb was by far the best. You might have to compile from git because they don’t release very often.

    3. 3

      It’s interesting how a VM like python and its debugger pdb are still stuck with the most basic feature and are not even able to be good at them. Debugging async(io) code is a complete farce. In the meantime, native debugger dealing with process and CPU can go back in time, trace and deal with concurrency.

      What happened? Are Python developer just not using debugger? Working with these “modern” language feel so backward in term of tooling.

    4. 3

      Tracing breakpoints (or tracepoints). But what if breakpoints didn’t break? 🤔 Say no more, instead of stopping the execution, we can print a message to the output. And not just a simple string literal like “got here lol”; the message can contain expressions to calculate and embed values from the program, e.g. “iteration #{i}, current monster is {monster->name}”. Essentially, we’re injecting printf calls to random places in our program without rebuilding and restarting it. Neat, right?

      This made me laugh out loud. Even if you think that print statements are better than debuggers, you should still use a debugger to manage your print statements!

      More generally, this article is making me think about the different between low-skill/“easy” and high-skill/“hard” tools. Anybody who can program can add print statements, but you have to actively learn how to use a debugger well. Relatedly people always say “profile before you optimize” but profilers are high-skill tools, so most people can’t use it. The only widespread high-skill tool I can think of is git, which 1) is far, far more impactful than profilers or debuggers, and 2) forces the whole team to know it.

      1. 4

        I don’t think the widespread usage of git is high-skill, though. Or it’s not any higher-skill than sourcesafe was in 1999. It doesn’t force anyone to know more than pull, add, commit, push, and (maybe) checkout.

        I cheerfully grant your point that it’s more impactful, but the skill level with which most programmers use git is on par with the skill level with which they use tar or zip, in my opinion.

      2. 3

        I find this analysis a bit confusing.

        I think anyone can run a debugger and start single-stepping from the entrypoint (if there is one), and make sense of the results (however useful—or not—they be). More sophisticated use of a debugger might entail more skill, in just the same fashion as successfully implementing or modifying large applications with few bugs might require more skill at writing code than does writing small scripts. One might further say that debugging and writing code are different skills; and this might explain someone’s being skilled at writing code but finding debuggers unhelpful (because they are not skilled in their use). But none of this means that debugging is a harder skill than writing code.

      3. 2

        The problem with this approach is that it relies on the thing that I want to print not having been optimised away. I generally end up with print statements where the thing I want is an intermediate result that the compiler doesn’t emit sufficient debug info for the debugger to materialise.

      4. 2

        I do think that the time travel or omniscient debugger would have helped me locate my hardest bug (took over a month to locate–this about 20 years ago) but I do wonder at the resource cost. The bug would cause the program I was writing to crash in under an hour on the production server, but maybe a day or two on the development server (I got to the point where I left it running long enough on the development server under a heavy load). It was a single process with a single thread, and even then, core dumps were useless as the program would never crash in the same place twice, so running it under a debugger to catch the crash wouldn’t have helped (at least, debuggers at the time).

        Generally, for non-trivial bugs, I find using the scientific method—forming a hypothesis and testing it, to work, and it works with either debuggers or printf() style.