Rreverrse Debugging
huonw.github.io
huonw.github.io
Years ago, I would've been floored by a comment like this. But lately I find myself using them a little less often. These days, the codebases I interact with leverage more and more small-scope unit tests. This usually means that an unexpected test failure requires much less imagination to explain.
But debuggers remain a terribly simple way to identify the cause of a segfault/bus error. Even with code I've never seen -- if armed with just a stack trace I can identify a system misconfiguration or a workaround to avoid the error.
Sadly, most of the visual debuggers on linux don't meet my minimum standards for "good" (crashy, slow, typically have trouble inspecting certain types (mysteriously, since they're GDB frontends and GDB has no issue with it), etc...), and successive update to MSVC makes it's debugger worse and worse (although it's still the best I'm aware of at the moment)...
Moving on from my own personal intellectual deficiencies, one nice thing about Visual Studio (that everybody should copy, in my view) is that running your program under the debugger is the default. So any time you see anything unusual happen, or there's a crash, you can start debugging straight away.
This is also good when combined with automated tests. Get your tests to stop the debugger at the point of failure (for VC++, something like "if(IsDebuggerPresent()){__debugbreak();}" in your test macro(s) will do the trick) just before they abort or throw or whatever. Then when you have a failing test, you have all the information you'd have normally - and the option of some post-mortem examination. Sometimes, you won't need it, but sometimes, you will. The latter situations are always a bit more stressful and I think it makes sense to optimise for that.
Then I got into js development, the Chrome one was night and day different. I could actually see what was happening, it displays where it is stopping every time. You can see that picture you need to paint in your head on the screen without trying to remember which letter to press, which bits of code you have to store in RAM in your brain. I have many complaints about it still, but it works pretty well for most of the things I need it for.
Then I was shown pdb, which is very much like GDB from what I remember of it. Now armed with my knowledge of how debuggers work from Chrome, I am much more confident in pdb, but it's still a pain in the ass compared to something more "visual".
Once I started writing tons of tests, I found I didn't need the debugger as often. When your methods are less than ten lines, they're much easier to reason about, and a method becomes a pretty decent 'unit' to check out, no need to step through.
However, this also probably has to do with my relative skill levels and the languages and tools involved too. Ruby debugging has gotten better, but only in the last couple of years. And I didn't really know how to write tests nearly as well when I was doing Java.
Typically, instead of unit tests, I write state tracking and visualization code. This goes a long way towards helping track down bugs and keeping me out of the debugger, but honestly, a lot of that is just an indication of debugging tools being crap in general.
EDIT: Grammar.
So it's always nice seeing advances in the industrial art come out, but a little wistful, knowing what once was.
The real interesting thing with rr is how it's done at the bare metal with very low overhead, using deep hardware-level tricks involving the performance counters on modern x86 CPUs. It's relatively easy to do this when you have a VM, but doing it on native code running directly on the CPU is significantly more interesting.
* TOD: http://pleiad.cl/tod/index.html
* Chronon (commercial): http://chrononsystems.com/
* Jive: http://www.cse.buffalo.edu/jive/
* Whyline (research): http://www.cs.cmu.edu/~NatProg/whyline-java.html
* Omniscient Debugger (discontinued?): http://www.lambdacs.com/debugger/
And even without: an IDE like NetBeans (and probably any major Java IDE) can revert to a certain stack frame and even apply code changes on the fly - up to a certain degree of freedom only, but okayish for normal programmer life, where you need this only rarely if you have many smaller scope unit tests in place.
pure science fiction - instead of recording the change produced by each instruction they are recording what changed between system calls (result of system call is recorded) and scheduling points.
They do record the result of each system call and somehow manage to count the number of instructions per scheduled thread (they can only do that on new intel processors - counting the number of branches not instructions as instruction counter is not reliable. They are doing their own scheduling since the VM is all running in a single thread. It is also very Linux specific - for general case they use ptrace to record the system calls and their result, but tracing of some operating system calls is optimized by injecting stuff into the kernel (!)) - that's the reason why the recorded data is of minimal size.
I wonder how they are dealing with epoll - here the result is passed via shared memory and not via the system call interface. Still i guess they are lucky that there is no kqueue like interface on Linux - with kqueue it would have been even harder to track when the event result comes in.
Step 1. Find problematic code
Step 2. Step back to before problematic statement
Step 3. Change problematic data value and/or code to hypothesized good one (while debugger is active and paused)
Step 4. Continue execution and observe if output is as desired
Step 5. Write test case.
Easy peasy. I'm glad to see the Rust community doing something similar, as the benefits of ease of development are not to be discounted, and Rust seems like a pretty nifty language.
Also, rr has nothing to do with Rust in particular, although this article shows how to use it with Rust.
Sounds more like IntelliTrace to me (if you're not familiar with it, it's worth mentioning it's only available in Visual Studio Ultimate).
"Visual Studio (2010, 2012, 2013 Ultimate only .. does not support C++"
:(
Also, I'm sure there's a large chunk of people like me, who don't use debuggers much and have no idea what a good one is capable of.
For example, could you record gdb traces with a GPU in a PC with hUMA?
http://www.tomshardware.com/news/AMD-HSA-hUMA-APU,22324.html
That could allow for gdb traces to be recorded constantly without a CPU performance hit (traces could be truncated if/when the size grew too large).
I'm eager to give it a try in a real project.
Maybe there's some special things I forgot to do, but out of the box GUD definitely felt (too) minimal for me.
Lately I've used LLDB when working on the .NET framework, and that seems like quite a reasonable thing to work with too at this point. I'd love some emacs-magic for this too :)
That being said, I hope that lldb will catch on and there will be some decent front ends for it. The GDB-MI (machine interface) used in debugger frontends is quite limited and clumsy. The lldb debugger should be a lot easier to embed in a project as a library (as opposed to using pipes and gdb-mi).