If you’re just starting out with WinDBG, there are some commands you must know:
g - “go”, means to continue until the next breakpoint is hit
p - “proceed”, executes the statement that’s currently highlighted
gu - “go up”, means to step out of the current function
F9 - adds a break point: open up your source code, click on a line and hit this key
ld - “load”, load a module. To do this, you must be in a thread that uses that module
sxe - use it like this “sxe ld UnitTestDllNameHere” to break once UnitTestDllNameHere is loaded
.sympath - shows you all the symbols that are within WinDBGs reach in an asterisk-separated list
Scenario: How I used WinDBG to debug a TAEF-based unit test written in C++
I had a test dll which contained a test I wanted to walk through with WinDBG because I was tired of using log statements. Side note: just do yourself a favor and set up WinDBG instead of adding logs, building code, testing it, changing another thing, building yet again, testing and so on with the unhealthy cycle. Anyhow.
First, I made sure I had windbg installed and added to my System Path. Symbols next. Thankfully, at some earlier, blessed point in time, I had correctly set up the symbols so I didn’t need to bother about that part.
Then, I typed “windbg -o TestDllNameHere /name:TestNameHere”.
-o - this flag means you want to break at each child process spawned off when this test dll is run. In a TAEF-based test, TE.exe which is the thread that kicks off the unit tests will be running first and it will spawn another thread for your TestDllNameHere dll. This is the thread you are interested in debugging.
/name - this flag can take regex so you can also do /name:*TestNa* and both TestNameHere and TestNameThere will be debugged.
Now windbg is up. But it’s broken at some weird point.
to continue to Te.exe. Now that it was in Te.exe, I did another
so that it tried to run the test.
It broke at some point where it had a sense of what it meant to break upon loading TestDllNameHere. Then I typed:
No complaints. Whew. Then,
to go until TestNameDllHere was loaded. It broke into the first line of the dll. At this point, I told WinDBG to load symbols from the dll so it could understand the dll.
No complaints. All was good. I proceeded to open up my source files (from the location in the repo where they were built from). Navigated to a line of interest and pressed
This highlighted the line to show that the breakpoint had been set. Did a
bl - to list out the breakpoints I had set so far
All good. Then I opened up a view of all the local variables so I could see what each variable and pointer contained by doing:
This view does all the nice casting so you can just see at a glance what is in your current context.
Then I used navigation commands I summarized at the beginning of this post to see if the suspect line got hit or not. And if it did get hit, I analyzed the locals to see where I was seeing unexpected values.
And that’s how I used WinDBG to find my first code vs. expectation disparity :)