By Casey Muratori
If you watch Handmade Hero regularly, you know I’m constantly complaining about Microsoft Visual Studio’s deteriorating debugger. In the late 90’s, circa version 6, it was decent. It had a reasonable watch window that updated instantly when you stepped through your code, it could switch between executables quickly without showing long “loading” dialogs, it could show the values of variables that went out of scope, etc. Sure, there are tons of things I would have loved to add to it, but it was a completely usable everyday debugger.
Today, none of these things are true. The debugger in Visual Studio 2017 is a mess. Stepping through code is excruciatingly slow in many circumstances. The watch window takes seconds to update even for simple displays, and it doesn’t even show you that it’s busy refreshing, so if the values don’t change, you don’t even know if it’s done updating or not! Switching projects takes multiple seconds even if there’s literally nothing in them but the executable target. And any time you want to look at a variable that’s just gone out of scope, you can’t. This last one is especially maddening, since often the only way to see the side effects of the last line of code before a close brace is to manually set the instruction pointer back to that line, inspect it, then set it back.
It’s grim.
However, Visual Studio isn’t the only debugger Microsoft ships.
If you ever pick through the debugging tools provided with the Windows Platform SDK, you know there is another debug engine used for kernel and device driver debugging. It even comes with a GUI called WinDBG.
In many ways, WinDBG is actually the better debugger, even for non-kernel debugging. It’s much more powerful than Visual Studio’s built-in debugger. It has features Visual Studio doesn’t, and it’s much smaller than Visual Studio. And unlike Visual Studio, it doesn’t require a huge several-minute bloated installation process. You can just copy the WinDBG directory to a machine, and it will run.
So why have I been using Visual Studio this whole time instead of WinDBG?
Sadly, there were certain usability problems that made WinDBG too inconvenient for daily use. It lacked basic features that are critical to efficient debugging, so even though it can do everything you need, the amount of UI busywork it took ended up costing too much time.
But recently, Microsoft announced they’d be spending time improving the usability of WinDBG. They released a new version called WinDBG Preview that makes a number of changes to the UI, and they posted requests for feedback.
So naturally, I wondered:
Has WinDBG Preview improved enough that I can switch to it as my everyday debugger?
As I’ve done many times with WinDBG in the past, I spent some time this week trying to use WinDBG Preview as my daily debugger. I’m delighted to report that, although it didn’t seem like it at first, once I dug in, WinDBG Preview really does appear to be usable as an everyday debugger! This is great news for everyone who’s been chafing under Visual Studio’s deteriorating debugger for the past fifteen years.
Since Microsoft has been asking for feedback, I thought I’d take a minute to list all the things I noticed that made it more difficult to use WinDBG than I would like:
There needs to be a keyboard shortcut for re-running an unloaded executable. This is the #1 thing that bothers me about using WinDBG at the moment. If the executable is still loaded, you can hit CTRL-SHIFT-F5 at any time to restart it, and it will preserve everything perfectly: breakpoints, command line arguments, working directory, the whole nine. But once you unload it (SHIFT-F5), presumably to rebuild it with some changes, CTRL-SHIFT-F5 no longer works. This really needs to be fixed, because the only way around it that I have found is to manually go to the File menu, select “Recent”, and then select the executable again. Thankfully, this still brings back your breakpoints and command line arguments, but it’s still way too many steps just to run the executable again. I would suggest doing the same thing Visual Studio does, which is that if the executable is unloaded, hitting F5 (which is normally “continue”) reloads it and starts it running.
There need to be keyboard bindings for automation scripts. WinDBG allows you to script its behavior via a scripting interface. I could see this eventually being useful for customizing the debugger for specific workflows. But at the moment, it seems very limited, because you cannot actually bind scripts to keyboard shortcuts. Instead, you have to manually switch to the command window, type the execution command, and then type the entire name of the script. This is much too cumbersome to make it useful for user interface improvement. If there was some kind of script keybindings file you could create, that would allow you to bind all your keys to scripts you’ve written to perform your common tasks. This would make scripting immediately much more powerful.
Break-command-continue should to be automated. Right now, you cannot invoke most debugger operations when the target is actively running. Even if you want to do a common operation, like set a breakpoint and wait until it is hit, you can’t do it directly. Instead, you must break the target (ALT-DEL), then set the breakpoint (ALT-B A), then continue (F5). Not a showstopper, but there’s really no reason for the user to be doing this manually. If the debugger can’t set breakpoints while the target is running, just automatically invoke the break-set-continue for the user when they ask for a new breakpoint.
Setting a new breakpoint by name should be a single keystroke. This is a weird oversight, but for some reason, it doesn’t seem like there’s any way to add a breakpoint by name with a direct keyboard shortcut. Although F9 will set a breakpoint on the current line with a single keystroke, setting a breakpoint by name requires you to open the breakpoints ribbon (ALT-B) and then hit A to execute the “Add Breakpoint” operation. There should be a dedicated keyboard shortcut for this, as it’s a very common operation (in Visual Studio, both ALT-F9 and CTRL-B will do this).
Unresolved breakpoints should retain their original names. If WinDBG understands the breakpoint you’re trying to set, the breakpoints window will list it with a descriptive name that makes sense. However, if it doesn’t (like if it’s in a module that hasn’t been loaded yet, so the symbols aren’t there), then it just lists the breakpoint as “0x0”, which makes it impossible to tell which breakpoint is which. It’d be nice if the breakpoint window always listed breakpoints with something user-recognizable, like the original text the user typed in, so it’s clear which breakpoints are which even if some of them can’t be set yet.
Single-stepping shortcuts need to be improved. WinDBG currently has shortcuts for “step in”, “step out”, and “step over”, which is great. But “step in” is unfortunately a broad category, and WinDBG doesn’t seem to support shortcuts for all the variants you might want. Specifically, you want “step to next machine instruction”, “step to next source code line”, “step into first function call on this source code statement”, and “step into last function call on this source code statement”. Ideally these are not modal, they are all always available, just bound to separate keys. In WinDBG at the moment, only “step to next machine instruction” and “step to next source code line” are bound to a key, but they’re bound to the same key (F11), and you have to use a modal switch to select which one to do.
The register window needs work. Modern processors have a lot of registers. A lot. The register window can’t be just a giant uncustomizable list, or it’s not really feasible to use it. Ideally, there would be some kind of register view that would allow the user to quickly toggle which registers appear (as Visual Studio does via a right-click menu), and perhaps also has a “locals” section that shows all the registers involved in an n-instruction window around the current IP.
PDB hunting could be a lot better. If you use the /RELEASE and /PDBALTPATH switches to the linker, you will probably not have much trouble getting WinDBG to read your symbols automatically. This is great! But in more complicated scenarios, where the EXE and PDB don’t match exactly (for example, if the PDB has been moved or renamed), WinDBG doesn’t seem to try very hard to find it. This forces the user to do a bunch of busywork to load symbols that the debugger probably could have found itself if it did a little bit of searching.
Loading and saving the window layout should be a separate operation. WinDBG’s persistent configuration is a little hard to understand at the moment. It would be nice if it was more clearly delineated into two pieces: UI and target. Ideally, you want to be able to load targets independently of UI layouts and keyboard configurations, because the target is about what you are debugging, and the layout is about how you are debugging. In the best possible world, you could make several UI configurations irrespective of the target, and they would be immediately available at all times for rapid switching. Targets, on the other hand, are just configurations of which executables and DLLs to load, where to find the symbols, and how to configure everything (working directory, parameters, etc.) While it’s nice if they save which UI configuration they were last using, that’s about all they should do, and layouts shouldn’t be coupled to targets in any other way.
The file “menu” is cumbersome and weird. Most of the UI in WinDBG is pretty straightforward. I don’t care for “ribbons”, but thankfully you can just collapse the ribbon and use the keyboard shortcuts for everything… well, almost everything. Unfortunately, the File menu is something you do have to use, to set up executables, change settings, etc. And it’s very weird  —  it doesn’t work the way any of the other UI works, replaces the entire window so you can’t see anything you were doing while you use it, and just generally feels really out of place. I would recommend not going down this path, and replacing the File menu with a regular menu system that doesn’t do anything fancy.
There should be a ZIP-based distribution. Currently, WinDBG preview is only available via the Windows Store. While that might have been a deal killer, fortunately it doesn’t require an account or any fussing. You can just download it directly from the store, then ZIP the resulting directory yourself, creating a nice distribution you can put on any machine quickly. But obviously, it would be an improvement if Microsoft provided such a ZIP directly, and committing to such a deployment would ensure that bloated installer creep couldn’t happen (like it has for Visual Studio).
My fingers are crossed.
I don’t know how much effort Microsoft is interested in putting into WinDBG usability. But I’m really hoping they’re interested enough to polish up what they’ve got a little bit more. I’m already thinking about ditching Visual Studio for good and using WinDBG exclusively. If some of the minor issues I listed were addressed, I think it would be slam-dunk.
 —  Casey
PS. If you like my blog and want to see what I’m working on these days, here are some links to my current projects:
Meow the Infinite
The feline space opera you’ve been waiting for, presented in serial comic form.
Handmade Hero
A complete, professional-quality game and engine, coded from scratch on a live stream.
A fully interactive story about the criminal underworld of 1930s New York City and the prosecutors charged with bringing them down.