Live data from Hacker News

What a good debugger can do

werat.dev

141–150 of 208 posts

Re: What a good debugger can do

#141

I use GDB almost daily, and used Visual Studio pretty deeply for many years (and still a little bit, nowadays), but I must say I am still a "printf debugging" aficionado (or better: real logging). I like many of the features that debuggers can provide, and I think this is a good article to set aspirational goals for what is possible. But my lived experience has generally been that it's a buggy, fuzzy, moving target i…

> It is simple and trustworthy. This sounds so naive for someone with 20+ years in the field... Linux, for decades, couldn't get logging to the point that it at least doesn't lose messages (the problem with tail / logrotate that is quite obvious once you think about it, but it took many years to give up the approach). I recently hit a bug where NVidia's driver abuses Linux kernel logging in some tight loop by spammin…

> Many things are simple, when your task is simple. Logging is just one of those things.

I agree with much of what you said, and of course "logging" is not just a single point in the solution space — there is some function "troubleshooting_pain = f(your_project, your_approach)". I was trying to say that for "your_approach=logging" that function tends to return smaller values than for "your_approach=debugging", all other things being equal, in my experience.

Whereas your comments seem more oriented towards the "your_project" factor. Of course using logs is harder on a distributed system. But so is using a debugger, or just about anything else.

Perhaps I should have said "It is relatively simple and trustworthy, even if it can still get hairy at the extremes."

Re: What a good debugger can do

#142
post #37

If someone's preferred language/framework/environment doesn't have a good debugger, or if they simply don't know how to set it up, some percentage of them will start insisting that they don't even want one anyway. This is the basic Sour Grapes concept.

Debugger is a tool, not a goal. I can reach a GOAL without debugger, using my software development skills only. I prefer to invest into quality of code, write more comments and documentation, perform refactoring, delete unused code, write test case to reproduce the bug, add more command line parameters, write better error messages with more data, and so on, than to invest time into a debugger. I'm the Software Developer, not a Software Debugger.

Re: What a good debugger can do

#143

It's sad that Python does not really support some of these debugging methods. E.g. you cannot really watch variable changes. There are some workarounds, like writing a custom __setattr__ or __setattribute__ in case of an object, or checking all STORE_* operations. https://youtrack.jetbrains.com/issue/PY-30387 https://github.com/gaogaotiantian/watchpoints Reverse debugging is also sth I would like to have, and there a…

Python debugger is really sad for many more reasons:

1. Cannot interrupt a running program to get debugger prompt, you have to code that functionality in yourself.

2. Cannot deal with threads or multiple child processes because it gets confused by where its output should go, and so it appears to be stuck, prompt doesn't show up, or input isn't being accepted.

3. If someone writes an overly general except, debugger won't ever be called because in order to be called it relies on exceptions.

4. Debugger cannot evaluate comprehensions correctly due to scoping issues (not as much of a debugger fault as much of the language fault).

5. Debugger cannot consistently modify variables inside the function call. Depending on circumstances if you execute an assignment statement in debugger, the value may or may not be set to the variable in current stack frame.

6. Debugger doesn't step into iterator implementation (iirc, I might be confusing with tracing).

Re: What a good debugger can do

#144
post #131

Earlier quoted context omitted.

Debugging issues with multithreaded code can be difficult because you could be looking at race condition that only happens when the code is running at full speed and debugging pausing one or all threads could give you an different experience than the real world.

(Debug) logging can also change the frequency/order/synchronization of threads masking over race conditions.

Yeah, I have fought with this occasionally. It's one of the handful of "gotchas" you need to think of when designing logging, and interpreting its results.

Sometimes you can improve the situation by sticking things in a bigger memory buffer and tightening control of when things get flushed to disk, but there's always that fundamental "observing the system will change it" problem. Similar issues arise with a debugger too, of course.

Re: What a good debugger can do

#145

Earlier quoted context omitted.

> Time-travelling debuggers is really a game changer Core dumps have existed forever. They give you a stack trace and register values at the time of crash. Even better, you don't need a debugger running at the time of crash and you can dig into dumps sent from nontechnical users. Sure, Bret Victor's demo was cool. But time travel debugging is so completely oversold at this point that I can't take anyone seriously tha…

I've debugged core dumps before. It's not been a particularly pleasant experience--good luck trying to do something like `call V->dump()` (dump out an easy-to-understand representation of a complex value to stdout... oh that doesn't exist anymore, can't use that functionality!) The most useful aspect of time-travel debugging for me, personally, has been when the test case that causes a crash is refusing to be reduced…

Something else that time-travel debugging helps a lot with, is that in an awful lot of cases, what you have in the crash dump is a broken state, with no way to identify how that state happened to be. Like "why the hell does this variable have this value?". Sure, you can do the whole digging work to find what can possibly change that variable, and try different scenarios to hit them in a debugger at the moment the problem might appear in a new session that is not even guaranteed to produce the same crash. But with record-and-replay type things, you just set a watchpoint on the value, continue backwards, and there you go, you find where the value comes from.

Now, imagine you did do that manually and spent a lot of time finding that location. In many cases, that only gets you one step closer to the root cause, and you have to repeat the operation multiple times. Yes, you _can_ do that without record-and-replay, but do you really want to? Do you want to spend hours doing something that could take you minutes?

(And that's not even mentioning even worse cases, where the value you're tracking goes between processes via IPC)

Re: What a good debugger can do

#146

Earlier quoted context omitted.

Just curious how does one build the tools you talked about? I'm referencing both hw and sw: hw part I guess is "on chip trace capabilities" and sw is "break on registers or peripheral access". I'm not an embedded dev neither am I a debugger developer but I'm playing with toy OS dev so just curious.

The setup I'm most familiar with is ARM-based microcontrollers, here's an overview from their docs: https://developer.arm.com/documentation/ihi0014/q/Introducti... and the debugger from Keil (used to be independent, now part of ARM): https://www2.keil.com/mdk5/debug

Ah thanks, I thought they are yet to be made.

Re: What a good debugger can do

#147

I'm missing a few other items on this list that I use daily in Pharo - being able to open the debugger directly from the program. What the "debugger" command does in JavaScript. Conditional breakpoints are easier to work with if they can be directly included in the source code - be able to open another debugger on top of the code I see in the debugger. I'm doing the stepping, I'm at a certain point in the method, and…

> Conditional breakpoints are easier to work with if they can be directly included in the source code

The following code (probably, haven't tested it) allows to create a conditional breakpoint only when a certain method is called by tracing down the call stack

  debuggerIsInMethod: aMethodName
  ctx := GRPlatform current thisContext. "grab callstack"
 
  [ctx isNotNil] whileTrue: [
    (aMethodName asSymbol = ctx method selector) ifTrue: [ ^ true ].
    ctx := ctx sender ] ].
  ^ false
So in another method you can send (call the method) that's deeper in the call stack by doing:

  someMethod
    "do work"
    debuggerIsInYourMethod: 'aMethodHigherUpTheCallStack' ifTrue: [ 1 halt ].
    "do more work"
Use case: Suppose someMethod is being sent/called from everywhere, but you only want to debug it when aMethodHigherUpTheCallStack is sent/called. With this conditional breakpoint (in code), you can :)

Re: What a good debugger can do

#148
post #49

Earlier quoted context omitted.

> Debuggers need to do more things It's true that coming up with an interface for an abstract debugger is harder, but it's not impossible. Microsoft created Debug Adapter Protocol ( https://microsoft.github.io/debug-adapter-protocol/ ), which is conceptually similar to LSP. It's not perfect, but covers most basic operations pretty well, while leaving to the debugger to deal with the implementation details.

If I'm coming up with a new language, let's call it Drustzig, I can implement the LSP and get support for IDEs (and possibly xref tools and the like) essentially for free. Now to get debugging support for my language... I have to traipse around through every major debugger and beg them to merge Drustzig patches to make it work. The protocol you've linked (or the similar gdbserver protocol) essentially implements an I…

I agree that language server and debugger are different beasts, but both LSP and DAP serve a purpose of re-using the same server (xrefs or debugger) with different IDEs.

> I can implement the LSP and get support for IDEs essentially for free I mean, technically same is true for DAP... You can implement DAP and get support for IDE for free. But I agree that in general case implementing a good debugger is harder than implementing a good language server.

If Drustzig requires a special debugger (e.g. because it uses acustom format of debug information), then you'd need to implement it, yes. However, existing debuggers can support new languages relatively easy if those follow standard conventions (e.g. use PDB and DWARF). For example, Rust support in LLDB basically comes down to a custom demangler.

Again, I'm not saying that DAP is perfect and solves debugging, but IMO it's a step in the right direction. Make it popular, make it extensible. Debuggers can be mostly language agnostic (within reasonable bounds), but they don't _have_ to be.

Re: What a good debugger can do

#149

I use GDB almost daily, and used Visual Studio pretty deeply for many years (and still a little bit, nowadays), but I must say I am still a "printf debugging" aficionado (or better: real logging). I like many of the features that debuggers can provide, and I think this is a good article to set aspirational goals for what is possible. But my lived experience has generally been that it's a buggy, fuzzy, moving target i…

I have been programming professionally since 1986 and still nothing beats logging or having chunks of specialized code to do dumps of some data to files so you can analyze them with tools better suited for the purpose. Ideally though you don't want to have to modify the code to diagnose the problem especially if it's a crash caught in the wild and you have a chance to live debug it. I would love more useful visualiza…

Most of the data I work with can't be visualized by printing. (I mostly work on 3D and video.) But I have found it invaluable to log data, then read it into another program. Sometimes I can just bing it into a spreadsheet and plot it, other times I need to write something to display it or analyze it. It's definitely an under-utilized technique!

Re: What a good debugger can do

#150

I use GDB almost daily, and used Visual Studio pretty deeply for many years (and still a little bit, nowadays), but I must say I am still a "printf debugging" aficionado (or better: real logging). I like many of the features that debuggers can provide, and I think this is a good article to set aspirational goals for what is possible. But my lived experience has generally been that it's a buggy, fuzzy, moving target i…

I think one problem I have with gdb and to a lesser extent lldb is that when using them with an IDE, it's just a janky connection between a command-line program and a GUI program. Back in my macOS 7-9 days, using something like CodeWarrior, or even Vusal C++ on Windows, stepping was so fast and smooth. It would respond instantaneously. I can now press the step button like 5 times and watch as it steps to each line. My machine is a bazillion times more powerful, so I have to wonder if that interface between the UI and the debugger is part of the problem. I realize there's also protected memory and separate processes, and all that. But man it's insane how much faster our machines are and how much worse just single stepping is.
Post reply on HN