In today’s post, we’ll take a look at some of the options available to us when using DML (Debugger Markup Language). DML is a very simple markup language that helps discover and execute new commands based on the output of existing commands. Many WinDbg commands (and extension commands as well) have support for DML. For example, here’s the lm D command, which displays DML output:
In the command output above, when I clicked the “SillyThreadPool” link, the debugger executed another command for me, lmDvmSillyThreadPool, which displays module information. Again, there’s a bug of links that help me explore the symbols and functions present in that module.
First things first. You don’t have to remember a bunch of weird command suffixes to get DML output. There’s a global switch you can turn, .prefer_dml 1, which causes many built-in commands and extension commands to display DML output. For example, here is the output from the kn command after turning on that switch:
When clicked, the links here will switch to that frame and display the source code and local variables (the executed command is .frame 0nN; dv /t /v).
Your debugger scripts and extensions can also produce DML output. In a debugger script, simply use the .printf /D command, and embed a DML link in it. In a debugger extension, you can output DML using the IDebugClient::ControlledOutput function. For example, the following displays a link that executes another command when clicked:
.printf /D "<exec cmd=\"lm m ntdll\">lm ntdll</exec>\n\n"
Here’s something I bet you didn’t know. Your application itself can output DML commands to the debugger! All it takes is to use the OutputDebugString API, and embed in it the magic string <?dml?>. Everything that comes after that magic token will be interpreted as a DML string and will be displayed accordingly in the debugger. For example, suppose we have the following code somewhere in our application:
OutputDebugString(L"Entered thread pool demo app.\n<?dml?><exec cmd=\"!uniqstack\">Dump unique stacks</exec>\n");
Then, the debugger will display a command link when it encounters this debug output:
The next command is .dml_flow. This command is intended to make it easier to read disassembled functions, by splitting them into code blocks and helping navigate between the blocks using DML links. It’s easier for you to experiment with this command yourself than for me to explain it in words, but the general idea is that you provide two addresses – a start and a target – and the command helps you understand the code paths that can reach the target from the start address.
The links in the preceding screenshot link to the jump paths taken into and out of the basic code block displayed on the screen.
One final command that has to do with DML is a discovery command, .dml_start. This command takes a file that contains a number of DML links and command descriptions, and presents it in the debugger window (this is handy in combination with the Command Browser window). For example, suppose you have the following file:
Load SOS according to the CLR version that is currently in the process.
<link cmd=".loadby sos clr; .loadby sos mscorwks">Load SOS</link>
Display the last event and CLR exception.
<link cmd=".lastevent">Last debugger event</link>
<link cmd="!PrintException">Last CLR exception</link>
Display the CLR call stack for a specific thread.
Example: <link cmd="~0s; !CLRStack">~0s; !CLRStack</link>
Executing .browse .dml_start dn.dml produces the following:
This is now a handy command browser that you can use to begin an investigation. I also think it can be very useful for explaining the steps you have taken through a dump analysis session – and in fact, I will try this approach for one or two exercises in my debugging courses and see how it goes.
I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn