<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>A Hole In My Head : WinDBG/KD Fun</title><link>http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx</link><description>Tags: WinDBG/KD Fun</description><dc:language>en</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>MSDN link on how to set up a user or kernel debugger</title><link>http://blogs.msdn.com/doronh/archive/2009/01/29/msdn-link-on-how-to-set-up-a-user-or-kernel-debugger.aspx</link><pubDate>Thu, 29 Jan 2009 22:15:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9383543</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/9383543.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=9383543</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=9383543</wfw:comment><description>&lt;P&gt;This has got to be one of the top FAQs out there: &lt;FONT color=#0000ff&gt;&lt;STRONG&gt;&lt;EM&gt;&lt;FONT color=#990000&gt;how do I set up a kernel debugger?&lt;/FONT&gt;&lt;/EM&gt;&lt;/STRONG&gt;&amp;nbsp; &lt;/FONT&gt;I just stumbled across a link on MSDN which gives instructions not only on how to set up a kernel debugger on all transports (serial, 1394, usb2), but also how to set up a user mode debugger or how to attach to a virtual machine. Pretty cool.&amp;nbsp; This used to be an internal web page at Microsoft (and I think a topic in debugger.chm), it is great that it is now public&lt;/P&gt;
&lt;P&gt;The MSDN topic is &lt;A href="http://msdn.microsoft.com/en-us/library/cc266370.aspx" target=_blank mce_href="http://msdn.microsoft.com/en-us/library/cc266370.aspx"&gt;Starting the Debugger&lt;/A&gt;. Add it to your bookmarks and maybe we can create room in the FAQ for another question ;)&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9383543" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Debugger commands (.step_filter) that make my life easier</title><link>http://blogs.msdn.com/doronh/archive/2008/04/16/debugger-commands-step-filter-that-make-my-life-easier.aspx</link><pubDate>Thu, 17 Apr 2008 02:02:19 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8399699</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/8399699.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=8399699</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=8399699</wfw:comment><description>&lt;p&gt;This is a pretty cool and somewhat obscure debugger command.&amp;#160; It allows you to tell the debugger what functions to skip if you are using the &lt;a href="http://msdn2.microsoft.com/en-us/library/cc266759.aspx" target="_blank"&gt;trace command&lt;/a&gt; ('t').&amp;#160; I think of the trace command as the 'step into' command though, but that is just me.&amp;#160; Let's say we have the following simple application:&lt;/p&gt;  &lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;stdio.h&gt;

struct Foo {
    Foo() : m_value(0) { }

    int Increment() { return ++m_value; }
    static void Print(int i) { printf(&amp;quot;%d\n&amp;quot;, i); }

    int m_value;
};

int _cdecl main(int argc, char *argv[])
{
    Foo f;
    Foo::Print(f.Increment());
    return 0;
}&lt;/pre&gt;

&lt;p&gt;If I were to run the program under the debugger and use the 't' command for each line, it would step into every function. I typically use 't' instead of 'p' because I usually want to step into a function at some point in time and I tend to press 'p' one too many times ;). Here is an example of the debugger session:&lt;/p&gt;

&lt;pre&gt;0:000&amp;gt; g test!main
&amp;gt;   13: {
0:000&amp;gt; t
&amp;gt;   14:     Foo f;
0:000&amp;gt; t
&amp;gt;    4:     Foo() : m_value(0) { }
0:000&amp;gt; t
&amp;gt;   15:     Foo::Print(&lt;font color="blue"&gt;f.Increment()&lt;/font&gt;);
0:000&amp;gt; t
&amp;gt;    6:     int Increment() { return ++m_value; } [1]
0:000&amp;gt; t
&amp;gt;   15:     Foo::Print(f.Increment());
0:000&amp;gt; t
&amp;gt;    7:     static void Print(int i) { printf(&amp;quot;%d\n&amp;quot;, i); } [2]
0:000&amp;gt; gu
&amp;gt;   16:     return 0;
0:000&amp;gt; t
&amp;gt;   17: }
0:000&amp;gt; t
test!__mainCRTStartup+0x102:&lt;/pre&gt;

&lt;p&gt;Let's look at the statement Foo::Print(f.Increment()); When using the trace command, it will first step into Foo::Increment ([1]) before stepping into Foo::Print() ([2]). But let's say that I never want to step into Foo::Increment because I know that it is a simple function that I do not want to debug. I can tell the debugger to ignore trace commands into this function with the &lt;a href="http://msdn2.microsoft.com/en-us/library/cc266868.aspx" target="_blank"&gt;.step_filter&lt;/a&gt; command. The command takes a semi-colon delineated list of &lt;em&gt;fully qualified &lt;/em&gt;symbol names (which can include wildcards so you can filter out entire modules) to ignore. Let's see the debugger session again with this command:&lt;/p&gt;

&lt;pre&gt;0:000&amp;gt; g test!main
&amp;gt;   13: {
0:000&amp;gt; .step_filter &amp;quot;test!Foo::Increment&amp;quot;
Filter out code symbols matching:
  test!Foo::Increment
0:000&amp;gt; t
&amp;gt;   14:     Foo f;
0:000&amp;gt; t
&amp;gt;    4:     Foo() : m_value(0) { }
0:000&amp;gt; t
&lt;font color="red"&gt;&amp;gt;   15:     Foo::Print(f.Increment());&lt;/font&gt;
0:000&amp;gt; t
&amp;gt;    7:     static void Print(int i) { printf(&amp;quot;%d\n&amp;quot;, i); }
0:000&amp;gt; gu
&amp;gt;   16:     return 0;
0:000&amp;gt; t
&amp;gt;   17: }
0:000&amp;gt; t
test!__mainCRTStartup+0x102:&lt;/pre&gt;

&lt;p&gt;You will see now that when I trace into Foo::Print(f.Increment()); that the f.Increment() call is executed but not trace into (ignored is not the right word because it has run, I just didn't see it line by line) and I step directly into Foo::Print(). I think this is a pretty powerful debugger command, it can save you a lot of time if you are always accidentally stepping into the wrong function like I always do ;).&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8399699" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Getting 64 bit Vista to open my Inbox the way I want it to</title><link>http://blogs.msdn.com/doronh/archive/2008/03/11/getting-64-bit-vista-to-open-my-inbox-the-way-i-want-it-to.aspx</link><pubDate>Wed, 12 Mar 2008 02:00:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8162496</guid><dc:creator>doronh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/doronh/comments/8162496.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=8162496</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=8162496</wfw:comment><description>&lt;p&gt;A bit over a year ago I had to figure out why my Mail key started behaving differently on Vista vs XP and &lt;a href="http://blogs.msdn.com/doronh/archive/2006/11/30/vista-mail-client-quirk.aspx" target="_blank"&gt;wrote&lt;/a&gt; about how I fixed it.&amp;#160; Well, my dev box was so slow that I was able to employ enough sympathy that I got a new one.&amp;#160; While my old box was a 32 bit machine, the new one came preinstalled with 64 bit Vista.&amp;#160; &lt;em&gt;Cool&lt;/em&gt;. &lt;em&gt;&amp;#160;&lt;/em&gt;I finally had a 64 bit box that was powerful enough to develop on (previously all I had a very noisy 64 bit test machine).&amp;#160; &lt;/p&gt;  &lt;p&gt;When I get a new machine that I will be using for dev work I do the following:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Blow away the preinstalled OS and install the latest OS release (beta or RTM) that I can do work on.&amp;#160; In this case, I left the OS alone ;). &lt;/li&gt;    &lt;li&gt;Enlist in windows sources &lt;/li&gt;    &lt;li&gt;Install the latest WDK &lt;/li&gt;    &lt;li&gt;Install Office Pro and Visio Pro (for the lovely WDF pnp/power/power policy state machines) &lt;/li&gt;    &lt;li&gt;Apply the mail key registry change so Outlook works the way I want it to. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Well steps 1 through 4 went by flawlessly and I updated the registry to fix the mail key.&amp;#160; All happy with myself I made the change and pressed the key.&amp;#160; &lt;em&gt;Nothing happened&lt;/em&gt;.&amp;#160; The focus did not change nor did Outlook move to the default folder.&amp;#160; &lt;strong&gt;&lt;em&gt;Phooey&lt;/em&gt;&lt;/strong&gt;.&amp;#160; I double checked the changes in the registry and lo and behold I mistyped the value name and fixed it.&amp;#160; Pressed the mail key.&amp;#160; &lt;em&gt;Still nothing happened.&amp;#160; &lt;strong&gt;Rats&lt;/strong&gt;&lt;/em&gt;&lt;strong&gt;.&lt;/strong&gt;&lt;em&gt;&amp;#160; &lt;/em&gt;&lt;/p&gt;  &lt;p&gt;So now my only recourse was to debug it ;).&amp;#160; First searched for &amp;quot;RegisteredApp&amp;quot; in the source tree (via content indexing) to find the function which processed the WM_APPCOMMAND message.&amp;#160; Once found, I traced it into the internal shlwapi function which looked up the appropriate locations in the registry and traced through it as well.&amp;#160; Not the most enjoyable task either....first, I do not own the code so I am figuring out it intent while determining if it is behaving correctly...and second, it is optimized code so debugging with source was not an option.&amp;#160; &lt;em&gt;Thank god it was not IA64 assembly though.&amp;#160; &lt;strong&gt;Phew&lt;/strong&gt;.&amp;#160; &lt;/em&gt;The one positive through this part of the debugging was that it was 100% reproducible, so when I got lost, I could just hit 'g' and press the mail key again to restart.&lt;/p&gt;  &lt;p&gt;After looking at this for a half an hour or so, the logic was this&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Query for the default mail client in HKCU &lt;/li&gt;    &lt;li&gt;if (WIN64) { If that failed, 1) open the default mail client in the 32 bit HKLM software key and 2) query for the default mail client } &lt;/li&gt;    &lt;li&gt;If that failed, query for the default mail client in the normal HKLM software key (which would be the 64 bit HKLM on 64 bit, the 32 bit HKLM on 32 bit). &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Upon successfully querying for the default mail client, attempt to execute its open verb as registered in the key 64 bit &lt;font face="Courier New"&gt;HKLM\Software\Clients\Mail\&amp;lt;application&amp;gt;\shell\open\command. &lt;/font&gt;If this failed, attempt the same thing under the 32 bit version of the key.&amp;#160; &lt;/p&gt;  &lt;p&gt;The bug was that the result of the 2nd bullet (query on the 32 bit key on 64 bit machines) was being misinterpreted.&amp;#160; The code treated the return value as if a &lt;a href="http://msdn2.microsoft.com/en-us/library/ms724911.aspx" target="_blank"&gt;RegQueryValueEx&lt;/a&gt; call was made, but the call was to &lt;a href="http://msdn2.microsoft.com/en-us/library/ms724897(VS.85).aspx" target="_blank"&gt;RegOpenKeyEx&lt;/a&gt;.&amp;#160; Because the return value was not being evaluated correct, step 2) was never performed (querying for the client on the new key) which led to an error when formatting the string that was used to query for the verb.&amp;#160; &lt;/p&gt;  &lt;p&gt;OK, great.&amp;#160; Now at least I knew where the bug was, but I still wanted my mail key to work and I was definitely not going to run my own custom shlwapi.dll on my own machine.&amp;#160; It is used by too many components for me to have confidence in making that kind of change.&amp;#160; I needed a solution that was as minimal as possible and the least invasive.&amp;#160; In the end I ended up attaching windbg and using the assembler (the 'a' command) to remove the incorrect checks.&amp;#160; My initial removal was to nop the entire sequence...&lt;/p&gt;  &lt;pre&gt;0:004&amp;gt; u xxxxxxxxx`xxxxxx6c  (somewhere in the guts of shlwapi.dll)
$ the call whose result will be misinterpreted
xxxxxxxxx`xxxxxx6c ff153e08fcff    call    qword ptr [SHLWAPI!_imp_RegOpenKeyExW (000007fe`fee918b0)]

$ incorrect tests
xxxxxxxxx`xxxxxx72 85c0            test    eax,eax
xxxxxxxxx`xxxxxx74 8bf8            mov     edi,eax
xxxxxxxxx`xxxxxx76 7474            je      xxxxxxxxx`xxxxxxec
xxxxxxxxx`xxxxxx78 3bc3            cmp     eax,ebx
xxxxxxxxx`xxxxxx7a 742c            je      xxxxxxxxx`xxxxxxa8

$ call to query the value
xxxxxxxxx`xxxxxx7c 488b4c2438      mov     rcx,qword ptr [rsp+38h]
xxxxxxxxx`xxxxxx81 4c8d4c2430      lea     r9,[rsp+30h]
xxxxxxxxx`xxxxxx86 4c8d442440      lea     r8,[rsp+40h]
xxxxxxxxx`xxxxxx8b 33d2            xor     edx,edx
xxxxxxxxx`xxxxxx8d c7442430a0000000 mov     dword ptr [rsp+30h],0A0h
xxxxxxxxx`xxxxxx95 ff150d08fcff    call    qword ptr [SHLWAPI!_imp_RegQueryValueW (000007fe`fee918a8)]

$ now nop out the check, always do the query.  Stop @ xxxx7c since that is the start of the query call
0:004&amp;gt; a xxxxxxxxx`xxxxxx72 
xxxxxxxxx`xxxxxx72 nop
xxxxxxxxx`xxxxxx73 nop
xxxxxxxxx`xxxxxx74 nop
xxxxxxxxx`xxxxxx75 nop
xxxxxxxxx`xxxxxx76 nop
xxxxxxxxx`xxxxxx77 nop
xxxxxxxxx`xxxxxx78 nop
xxxxxxxxx`xxxxxx79 nop
xxxxxxxxx`xxxxxx7a nop
xxxxxxxxx`xxxxxx7b nop

$ and dump out the old code again to make sure the right thing was nop'ed
0:004&amp;gt; u xxxxxxxxx`xxxxxx6c 
xxxxxxxxx`xxxxxx6c ff153e08fcff    call    qword ptr [SHLWAPI!_imp_RegOpenKeyExW (000007fe`fee918b0)]
xxxxxxxxx`xxxxxx72 90              nop
xxxxxxxxx`xxxxxx73 90              nop
xxxxxxxxx`xxxxxx74 90              nop
xxxxxxxxx`xxxxxx75 90              nop
xxxxxxxxx`xxxxxx76 90              nop
xxxxxxxxx`xxxxxx77 90              nop
xxxxxxxxx`xxxxxx78 90              nop
xxxxxxxxx`xxxxxx79 90              nop
xxxxxxxxx`xxxxxx7a 90              nop
xxxxxxxxx`xxxxxx7b 90              nop
xxxxxxxxx`xxxxxx7c 488b4c2438      mov     rcx,qword ptr [rsp+38h]
xxxxxxxxx`xxxxxx81 4c8d4c2430      lea     r9,[rsp+30h]
xxxxxxxxx`xxxxxx86 4c8d442440      lea     r8,[rsp+40h]
xxxxxxxxx`xxxxxx8b 33d2            xor     edx,edx
xxxxxxxxx`xxxxxx8d c7442430a0000000 mov     dword ptr [rsp+30h],0A0h
xxxxxxxxx`xxxxxx95 ff150d08fcff    call    qword ptr [SHLWAPI!_imp_RegQueryValueW (000007fe`fee918a8)]&lt;/pre&gt;

&lt;p&gt;...but my final (and more refined) approach was the actual comparisons in the assembly.&amp;#160; After the in place edits, my mail key now works again!&amp;#160; The only issue is that I have to reapply every time explorer is started, I can live with that. I also filed a bug for the next release of Windows, so I will not have to make the edits in the future and neither will you ;).&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8162496" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>A must have book for any Windows developer</title><link>http://blogs.msdn.com/doronh/archive/2007/12/19/a-must-have-book-for-any-windows-developer.aspx</link><pubDate>Wed, 19 Dec 2007 21:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:6808549</guid><dc:creator>doronh</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/doronh/comments/6808549.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=6808549</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=6808549</wfw:comment><description>&lt;P&gt;I saw a book,&amp;nbsp;&amp;nbsp;&lt;A class="" href="http://www.amazon.com/Advanced-Debugging-Addison-Wesley-Microsoft-Technology/dp/0321374460/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1198017273&amp;amp;sr=8-1" mce_href="http://www.amazon.com/Advanced-Debugging-Addison-Wesley-Microsoft-Technology/dp/0321374460/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1198017273&amp;amp;sr=8-1"&gt;Advanced Windows Debugging&lt;/A&gt;, in the Microsoft company store and quickly read through it. It looked pretty awesome in the level of detail and breadth that it covered.&amp;nbsp; I ordered my own copy and I think it would be an invaluable resource for anyone who develops drivers or applications on Windows.&amp;nbsp; I learn something new everytime I read it.&lt;/P&gt;
&lt;P&gt;d&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=6808549" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Changes to !poreqlist</title><link>http://blogs.msdn.com/doronh/archive/2007/03/23/changes-to-poreqlist.aspx</link><pubDate>Fri, 23 Mar 2007 21:47:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1938730</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/1938730.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=1938730</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=1938730</wfw:comment><description>&lt;P&gt;I &lt;A class="" href="http://blogs.msdn.com/doronh/archive/2006/03/17/554179.aspx" target=_blank mce_href="http://blogs.msdn.com/doronh/archive/2006/03/17/554179.aspx"&gt;posted &lt;/A&gt;about !poaction and !poreqlist about a year ago. I tend to use these extensions whenever I am debugging a power related issue in the framework.&amp;nbsp; A few months ago, I ran !poreqlist and got the following output&lt;/P&gt;&lt;PRE&gt;0: kd&amp;gt; !poreqlist
All active Power Irps from PoRequestPowerIrp
PopReqestedPowerIrpList
FieldOffset = 00000004
&lt;/PRE&gt;
&lt;P&gt;Which is not what I expected to see!&amp;nbsp;It appeared to be broken :(.&amp;nbsp; (See the aforementioned previous posting on what the output should have looked like). The output refered to &lt;FONT face="courier new,courier"&gt;PopRequestedPowerIrpList&lt;/FONT&gt;, so I went into the kernel power manager code&amp;nbsp;to find the variable...but it was gone! Well, that would explain why the extension didn't work :). Just as a sanity check, I looked at the Server 2003 sources and did find this variable, so obviously a change was made for Vista (the related changes are unimportant for this posting). 
&lt;P&gt;What I really wanted to know is if I could still get the pending power IRP list in a Vista debug sesssion. After some digging around in the !poreqlist extension's source, I found what I was looking for. !poaction (which is implemented in the same file)&amp;nbsp;now contains the pending IRP list as well as its original output. &lt;FONT face="courier new,courier"&gt;PopIrpList &lt;/FONT&gt;replaced &lt;FONT face="Courier New"&gt;PopRequestedPowerIrpList. &lt;/FONT&gt;This was executed while the machine was in S0: &lt;PRE&gt;0: kd&amp;gt; !poaction
PopAction: 818fc7d8
  State..........: 0 - Idle
  Updates........: 0 
  Action.........: None
  Lightest State.: Unspecified
  Flags..........: 10000003 QueryApps|UIAllowed
  Irp minor......: ??
  System State...: Unspecified
  Hiber Context..: 00000000

Allocated power irps (PopIrpList - 81909a60)
  IRP: 8452b5e8 (wait/wake), PDO: 83f509c8
  IRP: 845dfa98 (wait/wake), PDO: 83f4f4c0
  IRP: 845cd820 (wait/wake), PDO: 8460b6a8

Irp worker threads (PopIrpThreadList - 819094e0)
  THREAD: 83b6bad0 (static)
  THREAD: 83b6bd78 (static)

Threads with non-zero thread execution state attributes:
&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1938730" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Debugger command (!list) that makes my life easier</title><link>http://blogs.msdn.com/doronh/archive/2006/08/10/693769.aspx</link><pubDate>Thu, 10 Aug 2006 18:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:693769</guid><dc:creator>doronh</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/doronh/comments/693769.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=693769</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=693769</wfw:comment><description>&lt;A href="http://blogs.msdn.com/doronh/archive/2006/08/09/693765.aspx"&gt;Yesterday&lt;/A&gt; I introduced the &lt;FONT face="courier new"&gt;dl&lt;/FONT&gt; command and demonstrated some of its limitations. Today I will talk about &lt;FONT face="courier new"&gt;!list&lt;/FONT&gt;. Let's take yesterday's data structure, MY_DATA. What if the LIST_ENTRY is at the end of the structure or there is more data in your structure that fits into two pointer sized fields so that dl cannot display them? This is where the extension &lt;FONT face="courier new"&gt;!list&lt;/FONT&gt; comes in very handy. 
&lt;P&gt;Getting all the parameters to this extension correct is a bit difficult and it took me quite a bit of experimentation to get it to work, so hopefully I will be able to make it easier to understand and you won't have to go through the same pain I did. First, let's rearrange the fields in MY_DATA so that the LIST_ENTRY is the last field, recompile, and rerun our test with the same breakpoint set on "&lt;FONT face="Courier new"&gt;return 0;&lt;/FONT&gt;" and run dl again to see the changes &lt;PRE&gt;    typedef struct _MY_DATA {
        &lt;STRIKE&gt;LIST_ENTRY ListEntry;&lt;/STRIKE&gt;
        ULONG Data;
        ULONG Data2;
        &lt;FONT color=cornflowerblue&gt;LIST_ENTRY ListEntry;&lt;/FONT&gt;
    } MY_DATA, *PMY_DATA;

    0:000&amp;gt; dl head
    0013fbf0  004d4098 004d4138 00000005 0013fc40
    004d4098  004d40c0 0013fbf0 abababab abababab
    004d40c0  004d40e8 004d4098 abababab abababab
    004d40e8  004d4110 004d40c0 abababab abababab
    004d4110  004d4138 004d40e8 abababab abababab
    004d4138  0013fbf0 004d4110 abababab abababab
&lt;/PRE&gt;As you can see for all rows except for the first, that the data after the LIST_ENTRY is unitialized and the usefulness of the output is much less. So, let's run &lt;FONT face="courier new"&gt;!list&lt;/FONT&gt; and see what we get &lt;PRE&gt;    0:000&amp;gt; !list "-t _LIST_ENTRY.Flink -x \"? @@(#CONTAINING_RECORD(@$extret, _MY_DATA, ListEntry));dt _MY_DATA @@(#CONTAINING_RECORD(@$extret, _MY_DATA, ListEntry))\" @@(head.Flink)"
    Evaluate expression: 5062800 = 004d4090
       +0x000 Data             : 1
       +0x004 Data2            : 0x101
       +0x008 ListEntry        : _LIST_ENTRY [ 0x4d40c0 - 0x13fbf0 ]

    [...]

    Evaluate expression: 5062960 = 004d4130
       +0x000 Data             : 5
       +0x004 Data2            : 0x105
       +0x008 ListEntry        : _LIST_ENTRY [ 0x13fbf0 - 0x4d4110 ]
&lt;/PRE&gt;So now we have all our structure, but there that has got to be one of the worst command lines I have seen in a long time! Let's take it apart and try to make some sense of it. 
&lt;UL&gt;
&lt;LI&gt;The entire command line is quoted which takes care of the beginning and ending "s 
&lt;LI&gt;&lt;FONT face="courier new"&gt;-t _LIST_ENTRY.Flink&lt;/FONT&gt; tells !list how to move from one entry to the next. !list will evaluate the expression to find the offset of the next list items pointer given the current list item pointer. My first impression was that it would be &lt;FONT face="courier new"&gt;-t _MY_DATA.ListEntry.Flink&lt;/FONT&gt;, but !list requires an offset relative to the current pointer while &lt;FONT face="courier new"&gt;_MY_DATA.ListEntry.Flink&lt;/FONT&gt; provides an absolute offset from the beginning of the structure. 
&lt;LI&gt;-x indicates what command you want to run for each entry in the list. You can optionally specify the -e flag for !list to echo the command, but for this case the echo was completely useless. The -x command also needs to be quoted which is why it is encased in escaped (\") quotes. The command being executed is actually 2 commands (separated by the semicolon). 
&lt;OL&gt;
&lt;LI&gt;&lt;FONT face="courier new"&gt;? @@(#CONTAINING_RECORD(@$extret, _MY_DATA, ListEntry))&lt;/FONT&gt; will dump the current _MY_DATA pointer &lt;EM&gt;&lt;FONT color=#ffa500&gt;value&lt;/FONT&gt;&lt;/EM&gt; for the given entry. &lt;FONT face="courier new"&gt;@$extret&lt;/FONT&gt; evaluates to&amp;nbsp;the current item pointer in the list (a PLIST_ENTRY in this case). This value is not necessarily the same as the start of the structure so I use &lt;FONT face="courier new"&gt;#CONTAINING_RECORD&lt;/FONT&gt; to adjust accordingly (just like it would in real live code). I evaluate the the pointer value because the next command, &lt;FONT face="courier new"&gt;dt _MY_DATA @@(#CONTAINING_RECORD(@$extret, _MY_DATA, ListEntry))&lt;/FONT&gt;, does not print it out and I like to see what each entry's value is. 
&lt;LI&gt;&lt;FONT face="courier new"&gt;dt _MY_DATA @@(#CONTAINING_RECORD(@$extret, _MY_DATA, ListEntry))&lt;/FONT&gt; will dump out the data structure for the given entry the same way it would work if you ran the dt command from the prompt &lt;/LI&gt;&lt;/OL&gt;
&lt;LI&gt;&lt;FONT face="courier new"&gt;@@(head.Flink)&lt;/FONT&gt; tells !list where the first entry in the list is. T&lt;I&gt;his is not the list head, it is the address of the &lt;B&gt;first&lt;/B&gt; entry.&lt;/I&gt; This is why I am evaluating getting the value of &lt;FONT face="courier new"&gt;head.Flink&lt;/FONT&gt; and not &lt;FONT face="courier new"&gt;&amp;amp;head&lt;/FONT&gt; &lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=693769" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Debugger command (dl) that makes my life easier</title><link>http://blogs.msdn.com/doronh/archive/2006/08/09/693765.aspx</link><pubDate>Thu, 10 Aug 2006 01:34:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:693765</guid><dc:creator>doronh</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/doronh/comments/693765.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=693765</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=693765</wfw:comment><description>The use of the LIST_ENTRY structure in WDM is quite pervasive.  It is used for nearly
all list keeping tasks.  I have used it extensively in the past and KMDF uses it
quite a bit as well.   There are two debugger commands that help in viewing the contents
of a list. I will talk about &lt;FONT FACE="courier new"&gt;dl&lt;/FONT&gt; today and &lt;FONT FACE="courier new"&gt;!list&lt;/FONT&gt; tomorrow.
&lt;P&gt;Here is an example usage of LIST_ENTRY (ignoring the fact that it leaks memory):

&lt;PRE&gt;
    typedef struct _MY_DATA {
        LIST_ENTRY ListEntry;
        ULONG Data;
        ULONG Data2;
    } MY_DATA, *PMY_DATA;

    int __cdecl main()
    {
        LIST_ENTRY head;
        ULONG i;

        InitializeListHead(&amp;head);

        for (i = 0; i &lt; 5; i++) {
            PMY_DATA pData = (PMY_DATA) LocalAlloc(LPTR, sizeof(MY_DATA));
            if (pData == NULL) {
                return 1;
            }

            pData-&gt;Data = i + 1;
            pData-&gt;Data2 = 0x100 + i + 1;

            InsertTailList(&amp;head, &amp;pData-&gt;ListEntry);
        }

        return 0;
    }
&lt;/PRE&gt;

Assuming we have set a breakpoint at "&lt;FONT FACE="Courier new"&gt;return 0;&lt;/FONT&gt;",
you can use the dl command to dump the list contained in the local variable 'head'.

&lt;PRE&gt;
    0:000&amp;gt; dl head
    0024f7d0  00364090 00364130 00000005 0024f820
    00364090  003640b8 0024f7d0 00000001 00000101
    003640b8  003640e0 00364090 00000002 00000102
    003640e0  00364108 003640b8 00000003 00000103
    00364108  00364130 003640e0 00000004 00000104
    00364130  0024f7d0 00364108 00000005 00000105
&lt;/PRE&gt;

Let's take the output apart and see what we are told.  The first column is the
address being dumped.  The other four columns are the 4 pointer sized values that
the first column points to.  Of these four columns, the LIST_ENTRY is contained in
the first (Flink) and second (Blink) columns.  The remaining two columns are pure data
and dependent on your data structure.  So, let's annotate the previous output:

&lt;PRE&gt;
    [addr]    [Flink]  [Blink]  [Data]   [Data]
    0024f7d0  00364090 00364130 00000005 0024f820
    00364090  003640b8 0024f7d0 00000001 00000101
    [...]
&lt;/PRE&gt;

The first row (0024f7d0  00364090 00364130 00000005 0024f820) is the list head,
so the the final 2 column values (00000005 0024f820) should
be ignored.   The remaining rows are our structure MY_DATA; let's look at its layout in memory:

&lt;PRE&gt;
    0:000&gt; dt _MY_DATA
       +0x000 ListEntry        : _LIST_ENTRY
       +0x008 Data             : Uint4B
       +0x00c Data2            : Uint4B
&lt;/PRE&gt;

It is no coincidence that I put Data and Data2 after the ListEntry field in the
structure.  By placing these values after the ListEntry, the &lt;font face="courier new"&gt;dl&lt;/FONT&gt; command
dumped my data structure for me without any additional work.  I chose a simple
pattern for the Data and Data2 fields to further illustrate this concept.  If we look at the first row
(00364090  003640b8 0024f7d0 00000001 00000101), the MY_DATA at 0x00364090 has a
Data value of 1 and a Data2 value of 0x101.  You can also use the
&lt;font face="courier new"&gt;dlb&lt;/FONT&gt; command to dump the list backwards if want.

&lt;P&gt;One word of caution though.  The output for a 64 bit list is a little different then the 32 bit
output.  Each entry takes up &lt;I&gt;two&lt;/I&gt; lines instead of one!  Also, the layout
trick that worked nicely for 32 bits does not work as nicely for 64.

&lt;PRE&gt;
    0:000&gt; dl head
    &lt;FONT COLOR="red"&gt;00000000`001ff930  00000000`00383730 00000000`00383870
    00000000`001ff940  00000000`00000000 00000000`ff8213ac&lt;/FONT&gt;
    &lt;FONT COLOR="green"&gt;00000000`00383730  00000000`00383780 00000000`001ff930
    00000000`00383740  00000101`00000001 abababab`abababab&lt;/FONT&gt;
    &lt;FONT COLOR="blue"&gt;00000000`00383780  00000000`003837d0 00000000`00383730
    00000000`00383790  00000102`00000002 abababab`abababab&lt;/FONT&gt;
    [...]
&lt;/PRE&gt;

I annotated the output to clarify the data.  For 64 bits I like to "fix" this issue
by specifying how many pointers to dump (two).  Unfortunately, to specify the number
of pointers to dump you need to specify the maximum number of entries.  I use a very large value
(100) so that I do not accidentally clip the output

&lt;PRE&gt;
    0:000&amp;gt; dl head
    [addr]             [Flink]           [Blink]
    &lt;FONT COLOR="red"&gt;00000000`001ff930  00000000`00383730 00000000`00383870&lt;/FONT&gt;
    [addr continued]   [Data]            [Data]
    &lt;FONT COLOR="red"&gt;00000000`001ff940  00000000`00000000 00000000`ff8213ac&lt;/FONT&gt;

    [addr]             [Flink]           [Blink]
    &lt;FONT COLOR="green"&gt;00000000`00383730  00000000`00383780 00000000`001ff930&lt;/FONT&gt;
    [addr continued]   [Data]            [Data]
    &lt;FONT COLOR="green"&gt;00000000`00383740  00000101`00000001 abababab`abababab&lt;/FONT&gt;
    [...]

    0:000&amp;gt; dl head 100 2
    &lt;FONT COLOR="red"&gt;00000000`001ff930  00000000`00383730 00000000`00383870&lt;/FONT&gt;
    &lt;FONT COLOR="green"&gt;00000000`00383730  00000000`00383780 00000000`001ff930&lt;/FONT&gt;
    &lt;FONT COLOR="blue"&gt;00000000`00383780  00000000`003837d0 00000000`00383730&lt;/FONT&gt;
    [...]
&lt;/PRE&gt;

One final note, the &lt;FONT FACE="courier new"&gt;dl&lt;/FONT&gt; command does not actually
rely on the LIST_ENTRY structure, it can be used for nearly any list type as long
as the pointer to the next item in the list can be retrieved dereferencing the
current entry's address.  Tomorrow's entry on &lt;FONT FACE="courier new"&gt;!list&lt;/FONT&gt;
will describe how to more robustly dump each entry in the list.&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=693765" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Viewing your KMDF log in a mini-dump (and other post mortem features)</title><link>http://blogs.msdn.com/doronh/archive/2006/08/02/687010.aspx</link><pubDate>Thu, 03 Aug 2006 02:03:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:687010</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/687010.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=687010</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=687010</wfw:comment><description>Your KMDF driver log can also be available in a mini-dump under certain
circumstances.  If you have a full kernel dump or a full memory dump, the log
will be always present (barring any memory corruption or problems writing out the
dump file).   KMDF will attempt to write your driver's log to the mini-dump if
one of the following are true:

&lt;OL&gt;
    &lt;li&gt;KMDF can determine if your driver is the cause of the bugcheck&lt;/li&gt;
    &lt;li&gt;You added a registry setting which told KMDF to always write your log&lt;/li&gt;
&lt;/OL&gt;

As of v1.5, KMDF can determine if your driver is the cause of a bugcheck if
one of the bug check parameters contains a pointer which is within the loaded
driver's memory range.  KMDF could attempt to walk the stack to figure out if
the client is on the stack, but KMDF plays it safe.   Walking the stack may cause
another fault, which could make it impossible to capture a dump (which is just
one possible thing that could go wrong).  When the following bug check codes
occur, KMDF will attempt to determine if your driver was the cause of the bug check:&lt;/p&gt;

&lt;center&gt;
&lt;TABLE border&gt;
    &lt;TR&gt;
    &lt;td&gt;Code&lt;/td&gt;
    &lt;td&gt;Value&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;DRIVER_IRQL_NOT_LESS_OR_EQUAL&lt;/td&gt;
    &lt;td&gt;0xD1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;IRQL_NOT_LESS_OR_EQUAL&lt;/td&gt;
    &lt;td&gt;0xA&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;KERNEL_APC_PENDING_DURING_EXIT&lt;/td&gt;
    &lt;td&gt;0x20&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;KERNEL_MODE_EXCEPTION_NOT_HANDLED&lt;/td&gt;
    &lt;td&gt;0x8E&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;KMODE_EXCEPTION_NOT_HANDLED&lt;/td&gt;
    &lt;td&gt;0x1E&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;PAGE_FAULT_IN_NONPAGED_AREA&lt;/td&gt;
    &lt;td&gt;0x50&lt;/td&gt;
    &lt;/tr&gt;
    &lt;TR&gt;
    &lt;td&gt;SYSTEM_THREAD_EXCEPTION_NOT_HANDLED&lt;/td&gt;
    &lt;td&gt;0x7E&lt;/td&gt;
    &lt;/tr&gt;
&lt;/TABLE&gt;
&lt;/CENTER&gt;

&lt;p&gt;At first glance, to get your log out of the mini-dump you would think that
you could use &lt;font face="courier new"&gt;!wdflogdump&lt;/FONT&gt; to view the log.  Unfortunately,
you can't use this command because of the way that memory is stored in the mini-dump.  Instead,
you need to run the &lt;font face="courier new"&gt;!wdfcrashdump&lt;/FONT&gt; command.  All
the other dump related commands (&lt;font face="courier new"&gt;!wdfsearchpath, !wdftmffile&lt;/font&gt;)
still work in the mini-dump environment.

&lt;p&gt;If you have a kernel debugger attached, you can also save the log explicitly.
The &lt;FONT face="courier new"&gt;!wdflogsave [DriverName [FileName]]&lt;/FONT&gt; command will save the log for you
in a WPP compatible format (which you can open in a trace viewing app like TraceView).
If you do not specify [FileName], the log will be written to [DriverName].etl.

&lt;p&gt;You can also force KMDF to always write your driver's log file to the mini-dump.
To enable this feature, you must add the following registry value under
&lt;font face="courier new"&gt;HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\&amp;lt;your driver&amp;gt;\Parameters\WDF&lt;/FONT&gt;.
A value of zero (the default) turns the feature off, a non-zero value enables the
feature.
&lt;pre&gt;
    &lt;b&gt;ForceLogsInMiniDump&lt;/B&gt; : REG_DWORD
&lt;/PRE&gt;

&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=687010" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Customizing the KMDF log for your driver</title><link>http://blogs.msdn.com/doronh/archive/2006/08/01/685756.aspx</link><pubDate>Wed, 02 Aug 2006 01:55:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:685756</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/685756.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=685756</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=685756</wfw:comment><description>&lt;A href="http://blogs.msdn.com/doronh/archive/2006/07/31/684531.aspx"&gt;Yesterday&lt;/A&gt;
I talked about the KMDF log.  The KMDF log is a great tool to debug why a DDI call has failed or diagnose the
cause of a bugcheck in your driver.   You can customize different attributes of
the log so that you can better debug your driver.  The customizations available to
you are:

&lt;UL&gt;
    &lt;LI&gt;The length of the log&lt;/LI&gt;
    &lt;LI&gt;The format of the output&lt;/LI&gt;
    &lt;LI&gt;Verbose output&lt;/LI&gt;
&lt;/UL&gt;

When a customization requires you to add or modify a registry value, the value will
always be under &lt;FONT FACE ="courier new"&gt;HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\&amp;lt;your driver&amp;gt;\Parameters\WDF&lt;/FONT&gt;.
WHDC has a great KMDF &lt;A HREF="http://www.microsoft.com/whdc/driver/tips/KMDF_IfrLog.mspx"&gt;tip&lt;/A&gt;
which describes all of these options as well.&lt;/P&gt;

&lt;H4&gt;Length of the log&lt;/H4&gt;
Every KMDF driver has a log associated with it (you cannot turn it off).  The
default size of the log is one page (as defined by PAGE_SIZE; 4K on x86 and x64 systems, 8K on IA64).  Since
the log is measured by the size of a memory page it is not possible to say exactly how
many entries fit in the log, but one page usually holds around 100 entries.  You
can increase the size of the log by specifying the number of pages it should be.
The limit is currently 10 pages.   You should be conservative in the number of
pages you specify since these pages will not be available for general use by applications,
other drivers, or the OS.

&lt;P&gt;You specify the number of pages with the following value:

&lt;PRE&gt;
    &lt;B&gt;LogPages&lt;/B&gt; : REG_DWORD
&lt;/PRE&gt;

&lt;H4&gt;Format of the log&lt;/H4&gt;
You can modify the format of the log, just like you can with a WPP log.  The
format specifiers are intentionally the same so that you can transition from one
to the other.  The DDK has a good listing of the specifiers
&lt;A HREF="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/DevTest_g/hh/DevTest_g/tracefmt_df9af952-7b65-4610-b863-f3b76784f844.xml.asp"&gt;here&lt;/A&gt;
(the article is titled "Trace Message Prefix").  You can
set the formatting in two ways.  First, you can set the environment variable
&lt;FONT face="courier new"&gt;TRACE_FORMAT_PREFIX&lt;/FONT&gt;.  If you use a constant format this is the best way
to go since you just set it once and then leave it alone.  Second, you can also use the
&lt;font FACE="courier new"&gt;!wdfsettraceprefix&lt;/FONT&gt; comand in wdfkd.dll.

&lt;P&gt;The default formatting changed in KMDF v1.5.   The big difference between the
two is that for v1.5 the calling function is in the entry, while pre v1.5
the source file and line number are in the entry.  The calling function is much more useful to
an external developer then the file and line number (which is only available internally)
which is why we made the change.  (If you use the v1.5 wdfkd.ll with an earlier
version of KMDF, you will get the v1.5 formatting.)

&lt;PRE&gt;
KMDF v1.5:          "%7!u!: %!FUNC! - "
KMDF v1.0 and v1.1: "%7!u!: %2!-20.20s! -- "
&lt;/PRE&gt;

&lt;H4&gt;Verbose output&lt;/H4&gt;
What you see in the log is not everything that KMDF can potentially log, only
the most relevant entries are written to the log.  Sometimes this is not enough
information though.  You can tell KMDF to log &lt;I&gt;everything&lt;/I&gt; by turning on
verbose logging, but this comes with a caveat.  You will get a lot more information,
but you may lose the entries you really need since the log might overflow with the
verbose entries.  I would recommend increasing the log size if you are going to enable
verbose logging.  When you enable the KMDF verifier on your driver,
verbose logging is also enabled by default.

&lt;P&gt;You specify verbose logging with the following registry value.
A value of 0x0 (the default) turns verbose logging off, while a non zero value
will enable verbose logging.

&lt;PRE&gt;
    &lt;B&gt;VerboseOn&lt;/B&gt; : REG_DWORD
&lt;/PRE&gt;

&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=685756" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>How can I view the KMDF log for my driver?</title><link>http://blogs.msdn.com/doronh/archive/2006/07/31/684531.aspx</link><pubDate>Tue, 01 Aug 2006 00:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:684531</guid><dc:creator>doronh</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/doronh/comments/684531.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=684531</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=684531</wfw:comment><description>&lt;P&gt;A lot of developers have a great experience with KMDF, but then they sometimes hit a wall. They add a chunk of code and the drivers start failing because something in the new code was not implemented correctly. The first question that comes to mind is &lt;FONT color=red &lt;B&gt;&lt;I&gt;"how do I figure out what went wrong?" &lt;/I&gt;&lt;/B&gt;&lt;/FONT&gt;
&lt;P&gt;The framework team realized that this would be a very common occurrence so we made it a policy to log (using WPP) every error returned by the framework. WPP is cool technology, but if you don't have an application listening to the logger, the log entries are lost. Furthermore, if there is a crash, it is hard to get at the log itself. To solve these 2 issues, KMDF keeps a history of each driver's log. The history is about 100 entries long (you can specify a longer history using the registry). 
&lt;H3&gt;Viewing the log&lt;/H3&gt;
&lt;P&gt;First you need to load the KMDF debugger extension, wdfkd.dll. The debugger packages that you download from WHDC contain a copy of this DLL, but they are usually out of date. The DLL is also shipped as a part of the KMDF distribution and the WDK. You should use distribution/WDK version of the DLL for now until things stabilize and both the debugger and WDK eventually ship with the same DLL. Here are the steps you should follow to view the log: 
&lt;OL&gt;
&lt;LI&gt;&lt;A href="#step1"&gt;Load the correct symbols.&lt;/A&gt; Set your symbol path for the WDF binaries and make sure that your driver's symbols are loaded. 
&lt;LI&gt;&lt;A href="#step1"&gt;Load the correct DLL.&lt;/A&gt; This means using a fully qualified path name when running the &lt;FONT face="courier new"&gt;!load&lt;/FONT&gt; command 
&lt;LI&gt;&lt;A href="#step1"&gt;Set the TMF search path.&lt;/A&gt; KMDF v1.5 changed the way you set the TMF search path, so you must issue a different command KMDF v1.0 and v1.1 
&lt;LI&gt;&lt;A href="#step4"&gt;Execute &lt;FONT face="courier new"&gt;!wdflogdump&lt;/FONT&gt;&lt;/A&gt; &lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Before we proceed, there are a few generic substitutions that you will have to make when running these commands. Each substitution phrase is in &amp;lt;&lt;I&gt;term&lt;/I&gt;&amp;gt;. It is up to you replace these phrases with the appropriate values on your installation. &lt;/P&gt;
&lt;CENTER&gt;
&lt;TABLE border=1&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;Phrase&lt;/TD&gt;
&lt;TD&gt;Meaning&lt;/TD&gt;
&lt;TD&gt;Example&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;&lt;/TD&gt;
&lt;TD&gt;Architecture of the target&lt;/TD&gt;
&lt;TD&gt;x86, i386, amd64, or ia64&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;lt;&lt;I&gt;build-type&lt;/I&gt;&amp;gt;&lt;/TD&gt;
&lt;TD&gt;Type of build, either debug or retail&lt;/TD&gt;
&lt;TD&gt;chk or fre&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;&lt;/TD&gt;
&lt;TD&gt;The root directory of your DDK/WDK install&lt;/TD&gt;
&lt;TD&gt;C:\WinDDK&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;lt;&lt;I&gt;DDK-build&lt;/I&gt;&amp;gt;&lt;/TD&gt;
&lt;TD&gt;The build number of your DDK/WDK&lt;/TD&gt;
&lt;TD&gt;3790.1830 (Server 2003 SP1), 2195 (XP), etc&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;&amp;lt;&lt;I&gt;driver&lt;/I&gt;&amp;gt;&lt;/TD&gt;
&lt;TD&gt;Your driver's name without the '.sys' extension&lt;/TD&gt;
&lt;TD&gt;foo if you driver's image name is foo.sys&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/CENTER&gt;&lt;A name=step1&gt;
&lt;H4&gt;1) Load the correct symbols&lt;/H4&gt;&lt;/A&gt;You need to add the DDK/WDK symbol path to your debugger. For V1.0 and V1.1 DDK, the path is &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;\wdf\kmdf10\symbols\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;&amp;lt;&lt;I&gt;build-type&lt;/I&gt;&amp;gt;\wdf. As an example, the path would be &lt;FONT face="courier new"&gt;C:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf&lt;/FONT&gt; on my machine when debugging an x86 fre version of KMDF. Currently the beta versions of the WDK are not shipping with the symbols for KMDF, so you must use the symbols for your beta Vista install or use the v1.1 bits. 
&lt;P&gt;For V1.0 and V1.1 you will also need to make sure your driver's symbols are loaded since the debugger extension needs to resolve a symbol in your driver. V1.5 removes this requirement and you just need to have KMDF symbols setup properly. &lt;A name=step2&gt;
&lt;H4&gt;2) Loading the correct wdfkd.dll&lt;/H4&gt;&lt;/A&gt;To load the correct version of wdfkd.dll you need to specify the fully qualified path to the DLL. For v1.0 and v1.1, it is &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;\wdf\kmdf10\bin\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;, where &amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt; in this case is the machine type which is running the debugger (vs the machine being debugged). Here is how I load the extension on my machine: &lt;PRE&gt;0:000&amp;gt; !load c:\WinDDK\wdf\KMDF10\bin\x86\wdfkd.dll
&lt;/PRE&gt;To load the DLL from the WDK, the fully qualified path is different, it is &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;&amp;lt;&lt;I&gt;DDK-build&lt;/I&gt;&amp;gt;\bin\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;. Here is how I load the extension on my machine: &lt;PRE&gt;1: kd&amp;gt; !load c:\WinDDK\5461\bin\x86\wdfkd.dll
&lt;/PRE&gt;
&lt;P&gt;&lt;I&gt;If you are having issues with which version is being loaded you have a couple of options. The first is to execute the &lt;FONT face="courier new"&gt;.chain&lt;/FONT&gt; command in the debugger. This will list all loaded extensions. You can look through the list and see if there is more then one version of wdfkd.dll loaded. Second, you can copy the DDK/WDK version of the DLL over the debugger's version of the DLL. If you choose this option, you should make a backup copy of the original DLL.&lt;/I&gt;&lt;/P&gt;&lt;A name=step3&gt;
&lt;H4&gt;3) Setting the TMF search path&lt;/H4&gt;
&lt;P&gt;&lt;/A&gt;To set the path for v1.0 , you use the &lt;FONT face="courier new"&gt;!wdfsearchpath&lt;/FONT&gt; command. The TMF path is &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;\wdf\kmdf10\symbols\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;\&amp;lt;&lt;I&gt;build-type&lt;/I&gt;&amp;gt;\wdf\tmf. &lt;/P&gt;
&lt;P&gt;For v1.1 and v1.5 the &lt;FONT face="courier new"&gt;!wdftmffile&lt;/FONT&gt; command should be used instead instead. &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;v1.1:&amp;nbsp; the TMF file is located at &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;\wdf\kmdf10\symbols\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;\&amp;lt;&lt;I&gt;build-type&lt;/I&gt;&amp;gt;\wdf\tmf\wdf010001.tmf.&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;v1:5:&amp;nbsp; the TMF file is located at &amp;lt;&lt;I&gt;DDK-root&lt;/I&gt;&amp;gt;&amp;lt;&lt;I&gt;DDK-build&lt;/I&gt;&amp;gt;\tools\tracing\&amp;lt;&lt;I&gt;arch&lt;/I&gt;&amp;gt;\wdf01005.tmf. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Here are examples of all 3 variations, notice that I am using the fully qualified path name when executing the command and that the command echoes back the path. &lt;/P&gt;&lt;PRE&gt;V1.0
1: kd&amp;gt; !c:\WinDDK\wdf\KMDF10\bin\x86\wdfkd.wdfsearchpath c:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf\tmf
wdftrace: searchpath is: c:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf\tmf

V1.1
1: kd&amp;gt; !c:\WinDDK\wdf\KMDF10\bin\x86\wdfkd.wdftmffile c:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf\tmf\wdf01001.tmf
Set TMF file name is : 'C:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf\tmf\wdf01001.tmf
'

V1.5
1: kd&amp;gt; !c:\WinDDK\5461\bin\x86\wdfkd.wdftmffile C:\WinDDK\5461\tools\tracing\i386\wdf01005.tmf
Set TMF file name is : 'C:\WinDDK\5461\tools\tracing\i386\wdf01005.tmf'
&lt;/PRE&gt;&lt;A name=step4&gt;
&lt;H4&gt;4) Execute !wdflogdump&lt;/H4&gt;&lt;/A&gt;This is the same for all versions. The syntax for this command is &lt;FONT face="Courier new"&gt;!wdflogdump &amp;lt;&lt;I&gt;driver&lt;/I&gt;&amp;gt;&lt;/FONT&gt;. Here is the output from the osrusbfx2 example using KMDF v1.1 (and again note the fully qualified path for the DDL): &lt;PRE&gt;1: kd&amp;gt; !c:\WinDDK\wdf\KMDF10\bin\x86\wdfkd.wdflogdump osrusbfx2

Trace searchpath is: c:\WinDDK\wdf\KMDF10\symbols\x86fre\wdf\tmf

Trace format prefix is: %7!u!: %!FUNC! -
Log at a400b000
Gather log: Please wait, this may take a moment (reading 4032 bytes).
% read so far ... 10, 20, 30, 40, 100
There are 47 log entries
--- start of log ---
1: FxPkgPnp::PnpEnterNewState - WDFDEVICE 0x5BFF06B8 !devobj 0xA400F128 entering PnP State WdfDevStatePnpInit from WdfDevStatePnpObjectCreated
2: FxPkgPnp::Dispatch - WDFDEVICE 0x5BFF06B8 !devobj 0xA400F128, IRP_MJ_PNP, 0x00000000(IRP_MN_START_DEVICE) IRP 0x87F7B5D0
[...]
&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=684531" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Debugger commands (stack frame navigation) that makes my life easier</title><link>http://blogs.msdn.com/doronh/archive/2006/07/21/673317.aspx</link><pubDate>Fri, 21 Jul 2006 18:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:673317</guid><dc:creator>doronh</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/doronh/comments/673317.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=673317</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=673317</wfw:comment><description>&lt;P&gt;One thing that I have always found clunky is stack frame navigation in windbg/kd.
Previously, I thought you had only a couple of options.  &lt;/P&gt;

&lt;P&gt;The first option, if you are using WinDBG, is that
you can bring up the call stack window.  I have found that this is not a great
thing to do b/c WinDBG will try to update the call stack window while the target
is running and not just when you are broken in (perhaps it does this only for
module loads, I don't know).  Of course, since this is WinDBG dependent, this does
not work in kd.  As the final straw, this requires moving my hands off the keyboard,
losing valuable time navigating with the mouse ;).&lt;/P&gt;

&lt;P&gt;The second option is to use the &lt;FONT FACE="courier new"&gt;kn&lt;/FONT&gt;
command.  This will dump the stack with frame numbers, the output looks like this:

&lt;PRE&gt;
1: kd&amp;gt; kn
 # ChildEBP RetAddr
&lt;B&gt;00&lt;/B&gt; 81e33c6c 81898d7c nt!RtlpBreakWithStatusInstruction
&lt;B&gt;01&lt;/B&gt; 81e33c74 81898d2e nt!KdCheckForDebugBreak+0x22
&lt;B&gt;02&lt;/B&gt; 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
&lt;B&gt;03&lt;/B&gt; 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
&lt;B&gt;04&lt;/B&gt; 81e33d54 00000000 nt!KiIdleLoop+0xa
&lt;/PRE&gt;

And then you can issue the &lt;FONT FACE="courier new"&gt;.frame N&lt;/FONT&gt; command,
where N is the frame number to navigate to that frame and start debugging

&lt;PRE&gt;
1: kd&amp;gt; .frame 3
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
1: kd&amp;gt; dv
[...]
&lt;/PRE&gt;

My problem is that I didn't know how to do frame relative jumps, so every time
I wanted to move to a new frame I ran &lt;FONT FACE="courier new"&gt;kn&lt;/FONT&gt; again
(since I forget the frame numbers), found the new frame and ran
&lt;FONT FACE="courier new"&gt;.frame N&lt;/FONT&gt; with the new frame number.  Well today I
saw 2 new ways how to navigate the frames.&lt;/P&gt;

&lt;P&gt;The first way will work with the previous debugger releases.  You use the pseudo register
&lt;FONT FACE="Courier new"&gt;$frame&lt;/FONT&gt;.  Pretty nice trick IMO.

&lt;PRE&gt;
1: kd&amp;gt; .frame @$frame-1
02 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
1: kd&amp;gt; .frame @$frame+1
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
&lt;/PRE&gt;

&lt;P&gt;The second way to navigate frames requires the debugger package that was just
released and is a little less cumbersome to use.  There are 2 new debugger commands,
&lt;FONT FACE="Courier new"&gt;.f+&lt;/FONT&gt; and &lt;FONT FACE="Courier new"&gt;.f-&lt;/FONT&gt;.
These are definitely easier to use in my book because I don't have to remember
the register deref syntax.&lt;/P&gt;

&lt;PRE&gt;
1: kd&amp;gt; .f-
02 81e33d20 8183ddd5 nt!KeUpdateRunTime+0x270
1: kd&amp;gt; .f+
03 81e33d50 8187dba2 nt!PopIdleDefaultHandler+0x239
&lt;/PRE&gt;

&lt;P&gt;With these new commands, I think I get now get by without having to lift my
hands off the keyboard ;).&lt;/P&gt;

&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=673317" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>New debugger package is now public</title><link>http://blogs.msdn.com/doronh/archive/2006/07/19/672196.aspx</link><pubDate>Thu, 20 Jul 2006 06:58:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:672196</guid><dc:creator>doronh</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/doronh/comments/672196.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=672196</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=672196</wfw:comment><description>You can download the package from &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;WHDC&lt;/A&gt;.&amp;nbsp; It is hard for me to keep track of when they go public, we get internal drops more often and so it is hard for me to know when fixes see the (external) light of day.&amp;nbsp; Enjoy.&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=672196" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Debugger commands (!error, .enable_long_status) that makes my life easier</title><link>http://blogs.msdn.com/doronh/archive/2006/07/07/659444.aspx</link><pubDate>Sat, 08 Jul 2006 00:29:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:659444</guid><dc:creator>doronh</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/doronh/comments/659444.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=659444</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=659444</wfw:comment><description>&lt;P&gt;One thing you learn very quickly when writing a driver is that &lt;FONT face="courier new"&gt;NTSTATUS&lt;/FONT&gt; is used almost &lt;B&gt;&lt;I&gt;everywhere&lt;/B&gt;&lt;/I&gt;. The consistency is nice, especially compared to user mode where errors can be an &lt;FONT face="courier new"&gt;HRESULT&lt;/FONT&gt;, &lt;FONT face="courier new"&gt;LONG&lt;/FONT&gt;, or &lt;FONT face="courier new"&gt;DWORD&lt;/FONT&gt; (yes they are all the same underlying type, but they have different meanings, particularly for success/failure checks). The problem with any error value that is returned is that you must figure out where it came from and what the value maps to in terms of description and error name.&lt;/P&gt;

&lt;p&gt;The first simple tool I use is the &lt;FONT face="courier new"&gt;.enable_long_status&lt;/FONT&gt; command.  By default, all long integers are displayed in decimal, but for some error encoding systems, you want hex instead.  In this example, status is an NTSTATUS which is set to STATUS_UNSUCCESSFUL.  This works for HRESULT as well since all we are doing is changing the format of the number.

&lt;pre&gt;
0:000&amp;gt; dt status
status = -1073741823
0:000&amp;gt; .enable_long_status 1
0:000&amp;gt; dt status
status = 0xC0000001
&lt;/pre&gt;

&lt;P&gt;I found &lt;FONT face="courier new"&gt;!error&lt;/FONT&gt; awhile ago and I just refered to it in a comment on another post, so I thought it was a good time to talk about it. &lt;FONT face="courier new"&gt;!error&lt;/FONT&gt; takes an error value and returns the description for it. As a bonus, it works for win32 error codes as well as NTSTATUS values. Here is the description from the docs:&lt;/P&gt;&lt;PRE&gt;Syntax
!error Value [Flags]

Parameters:
Value  Specifies one of the following error codes:
         Win32
         Winsock
         NTSTATUS
         NetAPI

Flags If Flags is set to 1, then the error code is read as an NTSTATUS code. 
&lt;/PRE&gt;And this is what the output looks like for various values: &lt;PRE&gt;Dump out the value as Win32
0:000&amp;gt;  !error 1 
Error code: (Win32) 0x1 (1) - Incorrect function.

Dump out the value as NTSTATUS
0:000&amp;gt; !error 1 1
Error code: (NTSTATUS) 0x1 - STATUS_WAIT_1

Dump out an NTSTATUS value that is not ambiguous with a Win32 value
0:000&amp;gt; !error c0000001
Error code: (NTSTATUS) 0xc0000001 (3221225473) - {Operation Failed}  The requested operation was unsuccessful.
&lt;/PRE&gt;There are others tools and commands that you can use to get error descriptions: 
&lt;UL&gt;
&lt;LI&gt;net helpmsg &lt;DECIMAL value error&gt;
&lt;LI&gt;WPP format specifiers, %!STATUS! for NTSTATUS. I am sure there are other specifiers for other types as well (I just don't know them offhand). 
&lt;LI&gt;&lt;FONT face="courier new"&gt;FormatMessage()&lt;/FONT&gt; in user mode 
&lt;LI&gt;Visual Studio will do some automatic interpretation for you. IIRC, in a watch window you can apped ",err" or ",hr" to the variable name to get better error info. 
&lt;LI&gt;...and I am sure there others... &lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=659444" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Why does my COM port disappear when I enable the kernel debugger?</title><link>http://blogs.msdn.com/doronh/archive/2006/06/07/621604.aspx</link><pubDate>Thu, 08 Jun 2006 08:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:621604</guid><dc:creator>doronh</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/doronh/comments/621604.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=621604</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=621604</wfw:comment><description>&lt;P&gt;A lot of folks are told to connect a kernel debugger (over a serial calbe) to their systems if
it is constantly blue screening or if there are suspected issues in the kernel
or a loaded driver.  Most of these folks do not have the skills to debug the
issue themselves, they are just setting up their machine so that once the problem
shows up, somebody else can debug it.  One thing that happens is that the
person whose machine is being debugged looks in device manager and sees one of
two things...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The COM that they are using to debug the machine is yellow !'ed out and
non functional.
&lt;li&gt;The COM port does not appear in device manager at all.
&lt;/OL&gt;

&lt;p&gt;...and then summarily freak out.  Reactions range from wondering if the kernel
debugger is working at all (how could it?  the port it using appears to be non functional)
to anger that the COM port that they wanted to use is now gone.&lt;/p&gt;

&lt;p&gt;So what exactly is happening?  First and foremost, in both situations the
kernel has assumed ownership of the COM port's resources and is using those resources
to directly manipulate the port.  The kernel is not opening the port by name and
using the serial driver (serial.sys) to control the hardware, it is direct
manipulation.  This has an important side affect...there must be real UART hardware
for the kernel to access; a USB to serial adapter will not work on the target side
of a kernel debug session because there are no real UART registers to touch!  When debugging
over a serial cable is enabled, the kernel export &lt;font face="courier new"&gt;KdComPortInUse&lt;/font&gt;
 contains the starting address of the UART resources being used by the kernel debugger.&lt;/P&gt;

&lt;p&gt;So why are there different visual results to enabling a kernel debugger?  Well,
the results depend on if it is an ACPI machine (and chances are, any machine
built in the past 5 years is ACPI enabled by default).  If ACPI is enabled, ACPI
will look at the address in &lt;font face="courier new"&gt;KdComPortInUse&lt;/font&gt; and see if a device
in the ACPI table starts with that address.  If a match is made, ACPI does not
even enumerate the COM at all.  This is why you don't see a !'ed out device.  Looking at
ACPI.sys's imports, we see that it does reference the export:&lt;/p&gt;

&lt;pre&gt;
C:\WINDOWS\system32\drivers&gt;link /dump /imports acpi.sys | findstr KdComPortInUse
                   38 KdComPortInUse
&lt;/PRE&gt;

&lt;p&gt;The !'ed out device occurs when ACPI is not enabled on the machine.  In this
case, the BIOS reported COM is enumerated, the serial driver is attached to the stack,
and an &lt;font face="courier new"&gt;IRP_MN_START_DEVICE&lt;/font&gt; is sent to the stack.
In the process of starting the device, serial looks at the assigned resources to
the device and if they match &lt;font face="courier new"&gt;KdComPortInUse&lt;/font&gt;,
it will fail the &lt;font face="courier new"&gt;IRP_MN_START_DEVICE&lt;/font&gt;, resulting
in a failed start which shows up as a !'ed device in device manager.  Since the
serial driver is a DDK/WDK sample, we can see what it does:&lt;/P&gt;

&lt;PRE&gt;
NTSTATUS
SerialInitController(
    IN PDEVICE_OBJECT PDevObj,
    IN PCONFIG_DATA PConfigData
    )
{
   [...]

#ifdef _WIN64
   BOOLEAN DebugPortInUse = FALSE;

   //
   // First check what type of AddressSpace this port is in. Then check
   // if the debugger is using this port. If it is set DebugPortInUse to TRUE.
   //
   if(PConfigData-&gt;AddressSpace == CM_RESOURCE_PORT_MEMORY) {
        PHYSICAL_ADDRESS  KdComPhysical;
        KdComPhysical = MmGetPhysicalAddress(*KdComPortInUse);
        if(KdComPhysical.LowPart == PConfigData-&gt;Controller.LowPart) DebugPortInUse = TRUE;
   } else {
        if ((*KdComPortInUse) == (ULongToPtr(PConfigData-&gt;Controller.LowPart))) DebugPortInUse = TRUE;
   }

   if (DebugPortInUse) {
      [...]
      return STATUS_INSUFFICIENT_RESOURCES;
   }
#else
   //
   // This compare is done using **untranslated** values since that is what
   // the kernel shoves in regardless of the architecture.
   //
   if ((*KdComPortInUse) == (ULongToPtr(PConfigData-&gt;Controller.LowPart))) {
      [...]
      return STATUS_INSUFFICIENT_RESOURCES;
   }
}
&lt;/PRE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=621604" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WDM/default.aspx">WDM</category><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item><item><title>Previous command completion in WinDBG</title><link>http://blogs.msdn.com/doronh/archive/2006/05/22/604219.aspx</link><pubDate>Tue, 23 May 2006 02:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:604219</guid><dc:creator>doronh</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/doronh/comments/604219.aspx</comments><wfw:commentRss>http://blogs.msdn.com/doronh/commentrss.aspx?PostID=604219</wfw:commentRss><wfw:comment>http://blogs.msdn.com/doronh/rsscomments.aspx?PostID=604219</wfw:comment><description>&lt;p&gt;One of the features I like about kd is that since you are using a console
window, you get a lot of the console functionality for free.  The 2 features that
I really like are tab (err, F8) completion and the listing of command history
(F7).  On the other hand, windbg has a lot going for it (ignoring the inflamatory
topic of docking windows :P ) like source browsing and easier stack frame
navigation, but the one thing I miss the most in windbg is command completion.
Sure you have command history like kd, but who likes to scroll through 10s of
command to get the command you executed 5 minutes ago?&lt;/P&gt;

&lt;P&gt;Well, windbg &lt;B&gt;does&lt;/B&gt; have command completion!  The problem is that it's
hidden.  The only reason I know about it is I read every line of the release
notes for the debugger drop one week.  As a lark, I tried searching debugger.chm
for the phrace "command completion" and got 114 hits.  Needless to say I didn't
have patience to search all 114 to see if one of them actually documented this
feature or not, so I leave it up to you to see if you can find a topic about
this functionality in the help.  &lt;b&gt;&lt;font color="red"&gt;Windbg's equivalent of kd's
&lt;FONT FACE="courier new"&gt;F8&lt;/FONT&gt; is
&lt;FONT FACE="courier new"&gt;SHIFT+UP ARROW&lt;/FONT&gt;.&lt;/b&gt;&lt;/font&gt;&lt;/P&gt;

&lt;P&gt;The functionality between kd's
(really cmd.exe's) and windbg is nearly the same.  They differ when there is
no match for what has been typed.  With kd, nothing occurs. On the other hand,
with windbg, the text in the command window is selected.  Furthermore, once you have
reached the end of the history, windbg will not wrap back to the beginning (where kd
will wrap).  I have found the differences only matter when you are not paying
attention to what you are typing :).

&lt;P&gt;Here's a demo of the command at work.  Please note that the output of
!wdfrequest and !wdfmemory is from a new version of wdfkd (which will be in the WDK).  Let's say I run these 3 commands:&lt;/P&gt;

&lt;PRE&gt;
kd&amp;gt; !WDFREQUEST 0x7df89888
   !IRP 0x82b6af20
   !WDFQUEUE 0x7e8fdb40
   State:  Pending, Allocated by WDF for incoming IRP
   System Buffer 0x817011a8, Length 0x24, !WDFMEMORY 0x7df89821
   IOCTL Output Buffer 0x817011a8, Length 0x10, !WDFMEMORY 0x7df89819

kd&amp;gt; !WDFMEMORY 0x7df89821
WDFMEMORY 0x7df89821:  Buffer 0x817011a8, Length 0x24 (36) bytes

kd&amp;gt; !WDFMEMORY 0x7df89819
WDFMEMORY 0x7df89819:  Buffer 0x817011a8, Length 0x10 (16) bytes

Now at this point at the prompt kd&amp;gt;, I type "!WDFR", so we have
kd&amp;gt; !WDFR

and if I know hold down the SHIFT key and then press the up arrow key once, 
the prompt will look like
kd&amp;gt; !WDFREQUEST 0x7df89888
&lt;/PRE&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=604219" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/doronh/archive/tags/WinDBG_2F00_KD+Fun/default.aspx">WinDBG/KD Fun</category></item></channel></rss>