<?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>Trouble Ahead- Trouble Behind : debugging</title><link>http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx</link><description>Tags: debugging</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>New WDF debugging videos on WHDC</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/09/22/9898002.aspx</link><pubDate>Tue, 22 Sep 2009 16:41:32 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9898002</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9898002.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9898002</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9898002</wfw:comment><description>&lt;p&gt;&lt;a href="http://www.microsoft.com/whdc/devtools/debugging/kmdf.mspx" target="_blank"&gt;Several for KMDF here&lt;/a&gt;, and &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/umdftraining.mspx" target="_blank"&gt;several more for UMDF here&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Thus endeth today’s PR blitzen.&amp;#160; Have fun!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9898002" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category></item><item><title>Exceptions rule!</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2009/04/18/exceptions-rule.aspx</link><pubDate>Sat, 18 Apr 2009 19:24:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9555103</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/9555103.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=9555103</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=9555103</wfw:comment><description>&lt;p&gt;I’ve decided to revert to storytelling mode today.&amp;#160; So sit right back and you’ll hear a tale, a tale of my fateful trip (or click something useful- you’re the one deciding, and I’m the one typing to satisfy whatever inner demon has driven me to do this today)…&lt;/p&gt;  &lt;p&gt;It began when someone found a bug in the static version of KMDF- the one almost nobody gets to use and which we have been trying to discontinue any support.&amp;#160; But people were still using it, and we had no clear migration path, and there was a bug.&amp;#160; So we decided to begin testing it.&amp;#160; Poor &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/06/28/potential.aspx"&gt;Neslihan&lt;/a&gt; got that task (well at least it wasn’t me, this time).&amp;#160; Soon we had added a static KMDF driver to our list of test drivers used in our daily automated testing.&lt;/p&gt;  &lt;p&gt;Then, of course, we got the bugcheck.&amp;#160; As often happens, I played “Johnny-on-the-spot” and (virtually speaking) leapt onto the remote debug session accompanying the report.&amp;#160; Buffer overflow?&amp;#160; In FxDriverEntry?&amp;#160; But only on Itanium (I checked the other architectures that ran the same test, of course- no problems)?&amp;#160; What in blazes is this about?&lt;/p&gt;  &lt;p&gt;Well, the method is well documented, and not all that hard to understand- a “cookie&amp;quot; gets initialized, it gets stored to the local stack frame in such a way that code overflowing buffers in the stack frame will overwrite the stored copy.&amp;#160; On exit, code gets called that checks that value to see if that happened.&amp;#160; It’s a little more complicated than that, and I’m not going to be precise, because part of that complication is related to securing the method against the sort of people who like to exploit buffer overflows [so I’m not going to make the method clear for them- they can do their own research without my assistance].&amp;#160; The bugcheck analysis will even tell you the two values- expected and actual, making it easy for people who really think overflows are a bad idea to make a quick guess as to where the overflow came from.&lt;/p&gt;  &lt;p&gt;But the circumstances seemed suspicious, so I went and read the source code- H’mm- there’s a default value the cookie is initialized to…&amp;#160; Interesting- that’s the value we have- but it doesn’t match the expected value.&lt;/p&gt;  &lt;p&gt;At which time, something I’ve known for years hit me like the proverbial sledgehammer- our entry code calls GsDriverEntry (which supports the stack probes inserted by the GS compiler switch, hence its name) when it finishes.&amp;#160; GsDriverEntry &lt;em&gt;initializes&lt;/em&gt; the cookie, which means that that was why the values didn’t match.&amp;#160; Like the sword of Damocles, this had been hanging over our heads for years- the first time the compiler decided to do stack probes in our entry code, everything would break.&amp;#160; Ouch…&lt;/p&gt;  &lt;p&gt;I’ll leave a bunch of story out here- things got “interesting” at that point, but the problem eventually got solved, both for us and for other people facing similar issues, as well.&amp;#160; Short answer is that everyone now initializes the cookie right at the start, just as should happen…&lt;/p&gt;  &lt;p&gt;But a while back I had occasion to tweak the build process for the WdfVerifier WDK applet, and afterwards I ran it briefly to make sure I didn’t break anything in the process.&amp;#160; Oh, joy of joys- NONE of the 1.9 client drivers are being properly identified.&amp;#160; They are all identified as “Inbox”, which is what I do when &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/11/11/determining-a-kmdf-driver-s-client-version.aspx"&gt;the client identification method I described last year&lt;/a&gt; fails on me.&lt;/p&gt;  &lt;p&gt;Already beginning to panic, I think- did someone change FxDriverEntry, and I didn’t even notice it?&amp;#160; So I go to our source control system, and look at the change history.&amp;#160; The most recent change is the fix for the problem with the stack probes (yes it occurred on static, but what scared me then was it could have happened to any version, because were weren't doing things properly).&amp;#160; But that just calls library routines to initialize said cookie… Oh, blazes, those routines must be calling an import I wasn’t accounting for!!!&amp;#160; Why???&amp;#160; Because I NULL the IAT to force access violations, and I handle the exception by giving up on getting the true version, and fall back to calling it “Inbox”- which is, after all, exactly what I am seeing.&amp;#160; Oh, well- so much for my having thoroughly considered all the test and product consequences of that change when it was made…&lt;/p&gt;  &lt;p&gt;Well, easy enough to find out what that import might be.&amp;#160; One nice trick &lt;a href="http://blogs.msdn.com/iliast"&gt;Ilias&lt;/a&gt; showed me is that you can open any binary in WinDbg as a crash dump, and happily resolve symbols and disassemble code.&amp;#160; So I pick a random driver on my dev box, and do so.&lt;/p&gt;  &lt;p&gt;What, no imports?&amp;#160; But, but--- hmm- it uses a fixed address (load of a 64-bit immediate value into RAX, since my dev box is an X64, thank you- you x86 dinosaurs can keep your wimpy processors).&amp;#160; What’s with this?&lt;/p&gt;  &lt;p&gt;The answer lies in wdm.h, of course- KeQueryTickCount turns out to always be a macro- on x86 and IA64, it accesses KeTickCount [which is an import, and if you followed my earlier tale, it’s clear adding an import to my existing hack-o-matic mechanism is a trivial task]- but on X64, it accesses an essentially hardcoded address in a “SharedUserData” area.&amp;#160; This snippet is from wdm.h, so you can see for yourself…&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#define&lt;/span&gt; KI_USER_SHARED_DATA 0xFFFFF78000000000UI64

&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedUserData ((KUSER_SHARED_DATA * &lt;span class="kwrd"&gt;const&lt;/span&gt;)KI_USER_SHARED_DATA)

&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedInterruptTime (KI_USER_SHARED_DATA + 0x8)
&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedSystemTime (KI_USER_SHARED_DATA + 0x14)
&lt;span class="preproc"&gt;#define&lt;/span&gt; SharedTickCount (KI_USER_SHARED_DATA + 0x320)

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQueryInterruptTime() *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedInterruptTime))

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQuerySystemTime(CurrentCount)                                     \
    *((PULONG64)(CurrentCount)) = *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedSystemTime))

&lt;span class="preproc"&gt;#define&lt;/span&gt; KeQueryTickCount(CurrentCount)                                      \
    *((PULONG64)(CurrentCount)) = *((&lt;span class="kwrd"&gt;volatile&lt;/span&gt; ULONG64 *)(SharedTickCount))&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;My. my. my- this is a problem- no import I can just tweak to point into my code.&amp;#160; For a plus, at least the value can’t change (if it did, existing drivers would, after all, cease to work)- well, at least not easily, so I’ll save any remaining paranoia about that for another time.&amp;#160; But I’m going to access violate trying to access that address in user mode (not to mention the reams of experimental evidence I had just accumulated by noticing the problem in the first place)…&lt;/p&gt;

&lt;p&gt;So in reading about exception handling, a phrase happens to catch my eye- putting it in my words, it says that when continuing an exception, you can alter the context record supplied to you with the exception (and I know this process well, but that’s perhaps a story for a different time).&amp;#160; Whoa- that must mean I can change the contents of the registers programmatically, and then tell it to repeat the failed instruction!&amp;#160; Now, I can’t find that illustrated in any of the samples the material I’m reading points me to [nor could I find it an an internet search, although the latter was by no means exhaustive].&amp;#160; But that HAS to be what it means, right?&lt;/p&gt;

&lt;p&gt;So I start coding- first the half dozen or so lines needed to handle the KeTickCount import.&amp;#160; Then an exception filter [only for AMD64, of course].&amp;#160; The logic is my usual bit of precise work: If it is an access violation, and if it is a read, and it is a read of that exact address, and one of the integer registers in the context record has that same address, then change that register’s entry in the context record to the address of the proxy I’ve decided to keep in WdfVerifier, and tell the OS to repeat the failed instruction.&amp;#160; I began with RAX, because after all, that’s what I had seen in my investigation, and it seemed the most likely place for a while, but I added the whole set since under the circumstances, it seemed unlikely to do any harm.&amp;#160; Anything that didn’t match that exact pattern, and I gave up- just execute the handler, which does nothing.&amp;#160; The attempt to run the driver entry code to extract the client version will fail, but WdfVerifier keeps running, and the machine itself is still quite safe from my hackery.&lt;/p&gt;

&lt;p&gt;Worked the first time, it did (not counting my usual compiles to get rid of typos).&amp;#160; Problem solved.&amp;#160; Total work time from start to finish- something like 5 or 6 hours- good enough- after all, I did have to do some research…&amp;#160; Of course, there’s always somebody who can do it better, faster, and quicker- and they usually jump out of the woodwork if I start talking about things in that fashion, but it’s my story, so I’ll brag now and regret it later…&lt;/p&gt;

&lt;p&gt;Exceptions do indeed rule!&amp;#160; I love it when a plan comes together…&lt;/p&gt;

&lt;p&gt;A glimpse now at handling the new import…&lt;/p&gt;

&lt;pre class="csharpcode"&gt;
    &lt;span class="rem"&gt;//  The descriptors are an array of entries per module, each terminated with an all-0 entry.&lt;/span&gt;
    &lt;span class="rem"&gt;//  Each entry has an RVA for the module image name, and a second for a 0-terminated list of RVAs to the structures used for&lt;/span&gt;
    &lt;span class="rem"&gt;//  resolving names of exported entries from the module (in loading these get resolved to real addresses and are plugged into&lt;/span&gt;
    &lt;span class="rem"&gt;//  the loaded image's import address table in the same order).  So we now know how to write an image loader if we need to...&lt;/span&gt;

    &lt;span class="rem"&gt;//  First, find the descriptor for the KMDF loader, and quit if it isn't there.&lt;/span&gt;
    DWORD   StringCopy = (DWORD) -1, WdfBind = (DWORD) -1, InitEvent = (DWORD) -1, TickCount = (DWORD) -1; 

    &lt;span class="rem"&gt;//  Then look for the Bind and Unbind entry points.  Case counts!&lt;/span&gt;

    &lt;span class="kwrd"&gt;enum&lt;/span&gt; {OutdatedTechnology, HasBind, HasUnbind, OneCoolDriver};
    
    BYTE        TargetIdentification = OutdatedTechnology;

....

            &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (IsKernel)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;RtlCopyUnicodeString&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    StringCopy = ImportsIndex;
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;KeInitializeEvent&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    InitEvent = ImportsIndex;
                &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (0 == strcmp(&lt;span class="str"&gt;&amp;quot;KeTickCount&amp;quot;&lt;/span&gt;, (PSTR) NameDescriptor.Name))
                    TickCount = ImportsIndex;
                
                ImportsIndex++;
            }
.....


        DWORD       IATSize, RelocationsSize;
        LONGLONG    OurFakeTickCount = 0x8badf00ddeadbeefI64;   &lt;span class="rem"&gt;//  ersatz Tick count &lt;/span&gt;        
        PVOID*  ImportAddresses = (PVOID*) 
            ImageDirectoryEntryToDataEx(DriverImage, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &amp;amp;IATSize, &amp;amp;Unused);
        
        PIMAGE_BASE_RELOCATION  Relocations = (PIMAGE_BASE_RELOCATION)
            ImageDirectoryEntryToDataEx(DriverImage, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &amp;amp;RelocationsSize, &amp;amp;Unused);

        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (NULL == ImportAddresses)
        {
            FreeLibrary((HMODULE) DriverImage);
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        &lt;span class="rem"&gt;//  Plug them in here, and we are good to go!&lt;/span&gt;

        DWORD   OldProtect;

        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (!VirtualProtect(ImportAddresses, IATSize, PAGE_READWRITE, &amp;amp;OldProtect))
        {
            FreeLibrary((HMODULE) DriverImage);
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }

        memset(ImportAddresses, 0, IATSize);

        ImportAddresses[StringCopy] = FakeOutStringCopy;
        ImportAddresses[WdfBind] = CollectVersion;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (InitEvent != (DWORD) -1)
            ImportAddresses[InitEvent] = FakeEventInit;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (TickCount != (DWORD) -1)
            ImportAddresses[TickCount] = &amp;amp;OurFakeTickCount;

        VirtualProtect(ImportAddresses, IATSize, OldProtect, &amp;amp;OldProtect);&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;So for some other glimpses, this is one part of the other hackery (complete with my elementary-level annotations):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; AllKMDFDrivers
{
    MachineKey&amp;amp;             Owner;
    KMDFDriverList&amp;amp;         InstalledKMDFDrivers;
    LoadedDrivers&amp;amp;          CurrentlyLoadedDrivers;
    LoaderDiagnosticsFlag   LoaderFlag;
    String                  RuntimeVersion;
    DWORD                   Major, Minor, Build;

    &lt;span class="kwrd"&gt;bool&lt;/span&gt;            ServiceUsesKMDFLoader(__in PCWSTR ServiceName, __in RegistryKey&amp;amp; Service, __out MyBindInfoAlias&amp;amp; Binding);
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;     FakeOutStringCopy(__in PVOID, __in PVOID);  &lt;span class="rem"&gt;//  Fake RtlCopyUnicodeString entry&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt;     FakeEventInit(__in PVOID, __in ULONG, __in ULONG);  &lt;span class="rem"&gt;//  Fake KeInitializeEvent entry&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; ULONG    CollectVersion(__out MyBindInfoAlias&amp;amp; BindingOut, __in PVOID, __in MyBindInfoAlias&amp;amp; BindingIn, __in PVOID);
&lt;span class="preproc"&gt;#if&lt;/span&gt; defined(_AMD64_)
    &lt;span class="kwrd"&gt;static&lt;/span&gt; LONG     Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount);
&lt;span class="preproc"&gt;#endif&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;While the rest of it looks like this (and again, this is partial)- yes, feel free to hate my stylistic indifference to the herd- perhaps I’ll get fired for this, and all can breathe a vast sigh of relief…&lt;/p&gt;

&lt;p&gt;First, the code that calls the filter&lt;/p&gt;

&lt;pre class="csharpcode"&gt;        MangledDriverEntry  CrashAndBurn = (MangledDriverEntry) ((PBYTE) DriverImage + EntryRva);

        __try
        {
            CrashAndBurn(Binding, &amp;amp;Binding);
        }
&lt;span class="preproc"&gt;#if&lt;/span&gt; !defined(_AMD64_)
        __except(EXCEPTION_EXECUTE_HANDLER)
&lt;span class="preproc"&gt;#else&lt;/span&gt;     
        __except(Filterx64Exception(GetExceptionInformation(), OurFakeTickCount))
&lt;span class="preproc"&gt;#endif&lt;/span&gt;
        {
        }&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;and now our filter:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#if&lt;/span&gt; defined(_AMD64_)
&lt;span class="rem"&gt;/**********************************************************************************************************************************&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;LONG    AllKMDFDrivers::Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount)&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;Ahh, the joys of low-level intervention by the truly incorrigible!  On AMD64, we will get an exception when the code tries to get&lt;/span&gt;
&lt;span class="rem"&gt;the tick count.  This value resides at a known address (which cannot change because if it did, all existing drivers would then fail&lt;/span&gt;
&lt;span class="rem"&gt;to work- although I suppose someone could resort to what I am about to do- bring it on, I'll see if I can keep up with the absurd&lt;/span&gt;
&lt;span class="rem"&gt;arms race).&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;So, first, verify from the exception record that we are getting an access violation of some sort reading that known address.  Then&lt;/span&gt;
&lt;span class="rem"&gt;see if one of the integer registers has that address (start with RAX, since that's where it currently is, and I bet it doesn't&lt;/span&gt;
&lt;span class="rem"&gt;change much).  If it does, change it to point to the value given to this function (which resides in WdfVerifier, since I made it&lt;/span&gt;
&lt;span class="rem"&gt;a reference, and will let the compiler play enforcer), and then continue execution.&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;In all other cases, execute the handler, which will do nothing (meaning the version will continue to be unknown).&lt;/span&gt;
&lt;span class="rem"&gt;&lt;/span&gt;
&lt;span class="rem"&gt;**********************************************************************************************************************************/&lt;/span&gt;

LONG    AllKMDFDrivers::Filterx64Exception(__in EXCEPTION_POINTERS* ExceptionInfo, __in LONGLONG&amp;amp; FakeTickCount)
{

    &lt;span class="rem"&gt;//  cf definition of SharedTickCount in wdm.h&lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; DWORD64    KnownTickCountAddress = 0xFFFFF78000000320UI64;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (NULL == ExceptionInfo || NULL == ExceptionInfo-&amp;gt;ExceptionRecord || NULL == ExceptionInfo-&amp;gt;ContextRecord)
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;switch&lt;/span&gt;  (ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionCode)
    {
    &lt;span class="kwrd"&gt;case&lt;/span&gt;    EXCEPTION_ACCESS_VIOLATION:
    &lt;span class="kwrd"&gt;case&lt;/span&gt;    EXCEPTION_IN_PAGE_ERROR:    &lt;span class="rem"&gt;//  Unlikely, but what the heck...&lt;/span&gt;
        &lt;span class="kwrd"&gt;if&lt;/span&gt;  (2 &amp;gt; ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;NumberParameters)
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;
        &lt;span class="kwrd"&gt;break&lt;/span&gt;;

    &lt;span class="kwrd"&gt;default&lt;/span&gt;:
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;
    }

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (EXCEPTION_NONCONTINUABLE == ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionFlags)
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (EXCEPTION_READ_FAULT != ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionInformation[0] ||
        KnownTickCountAddress != ExceptionInfo-&amp;gt;ExceptionRecord-&amp;gt;ExceptionInformation[1])
        &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_EXECUTE_HANDLER;

    &lt;span class="kwrd"&gt;if&lt;/span&gt;  (KnownTickCountAddress == ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rax)
    {
        ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rax = (DWORD64) &amp;amp;FakeTickCount;
            &lt;span class="kwrd"&gt;return&lt;/span&gt;  EXCEPTION_CONTINUE_EXECUTION;
    }
    &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt;  (KnownTickCountAddress == ExceptionInfo-&amp;gt;ContextRecord-&amp;gt;Rbx)
 &lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The rest I leave as an exercise to the reader, having already put all 0.378 of you through the treadmill today…&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9555103" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/C_2B002B00_/default.aspx">C++</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/Life+at+Microsoft/default.aspx">Life at Microsoft</category></item><item><title>DDC starts in less than an hour</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2008/09/29/ddc-starts-in-less-than-an-hour.aspx</link><pubDate>Mon, 29 Sep 2008 16:21:36 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8968867</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/8968867.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=8968867</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=8968867</wfw:comment><description>&lt;p&gt;Plenty of good stuff for today- begin with Eliyas and Peter going over what's new in WDF for Windows 7 (or as we prefer to think of it WDF 1.9, since much of it also works all the back to Windows 2000 [KMDF] or Windows XP [UMDF]).&amp;#160; It continues later with our first presentation of talks on the &amp;quot;shared secrets&amp;quot; of the Windows Driver Frameworks.&amp;#160; The first talk discusses the implementation of the frameworks themselves, while the second presentation (my first of this conference, and my first in about 16 years) discusses how the frameworks are tested.&amp;#160; The latter talk will also be one of the final talks of the day.&lt;/p&gt;  &lt;p&gt;Tomorrow will include &lt;a target="_blank" href="http://blogs.msdn.com/bobkjelgaard/archive/2008/09/11/potpourri.aspx"&gt;Neslihan's talk about getting a logo for your WDF driver&lt;/a&gt; (yes we are adding logo requirements specifically for WDF drivers- primarily for KMDF at the moment).&amp;#160; It will include some excellent talks by Praveen Rao about work we have done on WDF drivers in the storage space, and again the final talk (at least in that room) is &lt;a target="_blank" href="http://blogs.msdn.com/iliast"&gt;Ilias&lt;/a&gt; and I discussing the WDF coinstallers.&lt;/p&gt;  &lt;p&gt;Wednesday we'll repeat all the talks I am in- the shared secrets talks will be back to back in the morning, but I won't catch part 1 that day because I'll be in another room with &lt;a target="_blank" href="http://blogs.msdn.com/iliast"&gt;Ilias&lt;/a&gt; repeating the presentation on the coinstallers.&lt;/p&gt;  &lt;p&gt;There's so much more, too- SDV, DSF, the innards of driver verifier, annotations for PFD and SDV, new test techniques from my colleagues James Moe and Dieter Achstettler, excellent talks on device installation, many driver technologies (several on printing, I can't help but notice).&amp;#160; I could go on and on, except I've got some work to get to this morning [and I'll be leaving soon so I can register and begin my bit of supporting the conference].&lt;/p&gt;  &lt;p&gt;Ask the experts session tomorrow night, bowling tonight, space set aside for us to talk with developers before and after talks, labs, panel discussions, Q &amp;amp; A with our most senior engineering staff, and a few surprises I'm not at liberty to mention even now.&lt;/p&gt;  &lt;p&gt;My plan for now is to try to attend the whole thing- how well that works depends upon how things go in the lab [we've got some critical work going on, but let's see how the junior staff handles things for a bit], and whether I'm providing any benefit by being there [if I can be more effective working on test tasks in my office, I'll return to it].&amp;#160; Of course, assuming my laptop works there, I may just blog a bit more than usual.&amp;#160; Not having a cell phone, it might be a bit hard for people to contact me if they need me back at the office [although they will know where I am, anyway].&lt;/p&gt;  &lt;p&gt;So, I hope to see a few of my readers there (both those within Microsoft, and especially those from the outside).&amp;#160; Hope all enjoy there time.&lt;/p&gt;  &lt;p&gt;&lt;em&gt;Now playing:&amp;#160; The acid rock classic jam &amp;quot;Dark Star&amp;quot; from Live / Dead (of course by the Grateful Dead)&lt;/em&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8968867" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/PFD/default.aspx">PFD</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/DSF/default.aspx">DSF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/Driver+Verifier/default.aspx">Driver Verifier</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/Life+at+Microsoft/default.aspx">Life at Microsoft</category></item><item><title>Now for a different UMDF Coinstaller story...</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2008/04/11/now-for-a-different-umdf-coinstaller-story.aspx</link><pubDate>Sat, 12 Apr 2008 01:40:08 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8382540</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/8382540.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=8382540</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=8382540</wfw:comment><description>&lt;p&gt;This one can never affect you, so your blood pressure can start easing now.&amp;#160; It's just been a while since I tried to put on my &amp;quot;war stories&amp;quot; hat and tried tellin' one of them tales...&lt;/p&gt;  &lt;h1&gt;In the Beginning was...&lt;/h1&gt;  &lt;p&gt;the need to make sure drivers we build for test are signed so we can automate their usage and avoid all the nasty workarounds unsigned driver installation entails- particularly since we test on so many operating system platforms.&amp;#160; In the early versions of KMDF, we did this as part of our normal build process, getting them signed just like all the rest of the OS is.&amp;#160; Even when we went to produce releases (this happens in build lines not under our direct control) they built all the samples and test code as well, and life was good.&amp;#160; We always had a coinstaller with the right update packages in it, and everything was signed.&lt;/p&gt;  &lt;p&gt;You still see vestiges of those halcyon days in the KMDF samples, where entries for the catalog &lt;em&gt;kmdfsamples,cat&lt;/em&gt; can be found even now [and this will be the case for as long as we are responsible for them].&amp;#160; All of our test drivers are also catalogued in there, so we can mix and match with impunity and it all works as long as it's from the same build.&lt;/p&gt;  &lt;h1&gt;The price of success&lt;/h1&gt;  &lt;p&gt;But we also became a part of the OS beginning with Windows Vista.&amp;#160; Now for a host of reasons, the build lines that build the OS produce coinstallers for KMDF and UMDF that contain &lt;u&gt;no&lt;/u&gt; update packages.&amp;#160; We did continue to build coinstallers with update packages on our private build machines, though.&amp;#160; We utilized various nefarious techniques to undo the system's file protection and place KMDF on a Vista machine when testing so we could test our latest versions, so things still weren't too bad.&amp;#160; But sometimes we wanted to use coinstallers and test binaries from differing builds- signing was becoming a problem.&amp;#160; More importantly, when we approached WDK release times, our external builders now only produced the coinstallers.&amp;#160; So we no longer had a single nice signed package automagically produced for us.&lt;/p&gt;  &lt;p&gt;We worked around this as best we could- typically one of the SDETs assembled a &amp;quot;build&amp;quot; out of disparate pieces and then re-ran the signing steps with a bcz in the proper directory.&amp;#160; Like all manual processes, errors happened, but we muddled along.&lt;/p&gt;  &lt;p&gt;Finally, late last year things got to be too much for Shefali and I- we had to run really old test content and found the signatures were no longer valid.&amp;#160; I should explain that a bit, if I can.&amp;#160; Developers working on Windows have certificates created for them identifying components they build that chain to a special &lt;em&gt;test root certificate&lt;/em&gt; (a term you can look up, for instance- &lt;a href="http://msdn2.microsoft.com/en-us/library/aa379872.aspx" target="_blank"&gt;this MSDN article touches upon them&lt;/a&gt;) that is recognized by most interim builds produced of Windows.&amp;#160; This means all of our content is &amp;quot;signed&amp;quot; (and it also means that if any of those signed binaries show up where they should not, they identify who produced it, giving one easy place to start searching for a leak).&amp;#160; When we approach releases a switch is made to more official forms of signing- our test drivers are also part of those builds, although they never ship to anyone, so we're still good to install on those- but we can't use them anywhere else because the coinstallers are still what we call &amp;quot;thin&amp;quot; [no update packages].&amp;#160; Of course, since nobody should need them for very long, those certificates also have a very short shelf life, which is what I was referring to at the start of this rambling paragraph of mine.&lt;/p&gt;  &lt;p&gt;We also had a hard time making clear to the software test engineers who were trying to run our rapidly changing test mixes what parameters to use (or even to figure out for ourselves which combinations of parameters really did what).&amp;#160; This led to delays, confusion, dissatisfaction [one of those poor STEs must have been sure he was on the verge of being dismissed- and that bothered me because I knew it wasn't all his fault], and other generally bad and stressful things.&lt;/p&gt;  &lt;h1&gt;If you want it done right, DIY&lt;/h1&gt;  &lt;p&gt;So, if self-signing driver packages and using test-signing approaches is good enough for our customers, it ought to be good enough for us.&amp;#160; I redesigned our entire automation process around this approach (with much encouragement and prodding from Shefali).&amp;#160; I solved both problems at the same time, but since I like to wander when telling tales, and I'm the one with the keyboard, I shall tangent...&lt;/p&gt;  &lt;h2&gt;Too many cooks&lt;/h2&gt;  &lt;p&gt;Normally a good test automation design in WTT (known to you as DTM) is fairly self-contained.&amp;#160; It gets its stuff, does its work, and cleans up after itself.&amp;#160; You see this in the three phases- setup, regular, and cleanup.&amp;#160; Virtually all of our test jobs worked this way, meaning any one could run independently of the others.&lt;/p&gt;  &lt;p&gt;We have literally hundreds of jobs that work this way- the bulk of them testing the KMDF DDI.&amp;#160; They took parameters with little bits and pieces of path names [because most of the time everything came from a specific machine, or if the machine changed, parts of the path were known, etc] and assembled them together to locate things, install them, run them, and clean up.&lt;/p&gt;  &lt;p&gt;But the names weren't consistent, the portions mapped weren't consistent and while it was sometimes possible to get a correct path by using .. in path entries and even blank entries for some parameters, determining those values was a logic puzzle in and of itself.&amp;#160; Worse, you couldn't be sure after a run that all of those jobs had really run the same thing.&amp;#160; Since &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2007/11/07/someone-must-want-this-job.aspx" target="_blank"&gt;I now found myself the only cook left in the KMDF QA kitchen&lt;/a&gt;, I took advantage of the situation to impose order on the chaos.&lt;/p&gt;  &lt;h1&gt;&lt;/h1&gt;  &lt;h1&gt;Slicing the knot&lt;/h1&gt;  &lt;p&gt;&lt;a href="http://www.geocities.com/~jlhagan/fineart/gallery3.htm" target="_blank"&gt;The story of Alexander the Great and the Gordian Knot&lt;/a&gt; has been with me all these last few weeks for some reason, and this may have been another of my &amp;quot;Brute Force&amp;quot; solutions.&amp;#160; I broke our test pass into three stages:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Staging- in this phase, all of the tools and content used is copied from disparate and myriad sources to the test machine in a known location.&amp;#160; Common tools like DSF are installed.&amp;#160; The key to the underlying narrative here is that this job also creates a test certificate on the machine, creates a catalog containing the entire contents that had been copied earlier, and signs that catalog with the new certificate.&amp;#160; It then sets the machine up so it works with test-signed binaries effectively.&amp;#160; So there's still a kmdfsamples.cat- but now it gets built fresh and piping hot right at your table [that thought makes me want to visit &lt;a href="http://www.benihana.com/" target="_blank"&gt;Benihana&lt;/a&gt;].&lt;/li&gt;    &lt;li&gt;Setting the framework on the machine.&amp;#160; In this phase, if we need to overwrite the normal version of KMDF already there we do- either brute force (by overriding the system protection on it) or elegantly (by using a &amp;quot;fat&amp;quot; coinstaller containing the appropriate update package).&amp;#160; As &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2007/12/13/kmdf-1-7-and-the-server-2008-vista-sp1-rc1-wdk.aspx" target="_blank"&gt;mentioned somewhere in here&lt;/a&gt;, you have to reboot the machine if the coinstaller is used (in fact, you have to do it either way).&amp;#160; Sometimes we don't even need this phase [XP, for instance].&amp;#160; Whenever possible we try to utilize real coinstallers in random configurations to more closely duplicate the end user experience, after all.&lt;/li&gt;    &lt;li&gt;The tests themselves.&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I had a single ground rule- &lt;strong&gt;&lt;em&gt;only the staging job would have any parameters&lt;/em&gt;&lt;/strong&gt;.&amp;#160; All the subsequent jobs would use what was staged.&amp;#160; There was a corollary based on previous experience:&amp;#160; &lt;em&gt;&lt;strong&gt;those parameters would be substantially complete path names&lt;/strong&gt;.&amp;#160; &lt;/em&gt;They might take longer to type, but it was easier to switch and accommodate quirks in how paths were assembled as you tried to get things from elsewhere if you just always took entire paths.&lt;/p&gt;  &lt;p&gt;I finished most of that work in one weekend (in November, if I remember correctly).&amp;#160; The most mind-numbing part of it was modifying the existing tests- I'd go through task by task with the new &amp;quot;known&amp;quot; staged path in the clipboard, and selected each directory name I found and pasted it in.&amp;#160; There were some deviations that I wound up adjusting in the initial setup job because they were done too many places.&amp;#160; There were places where parameters were passed down into library jobs that I left untouched (I actually set any such parameters to totally invalid values to make sure nothing escaped my wrath).&lt;/p&gt;  &lt;p&gt;After all that surgery I now had the ability to mix and match with much greater flexibility, and simple instructions with four basic parameters that covered all the known variations we had seen.&amp;#160; I then created a Wiki on the internal Microsoft network where I listed the instructions for all of the normal passes we did so we could clearly communicate what settings were to be used each day- at first, the STE could literally cut and paste from my instructions.&amp;#160; Once they were familiar with the new setup, they could do more of the work themselves.&amp;#160; You wouldn't recognize that same STE today.&lt;/p&gt;  &lt;p&gt;It worked pretty well, even if underneath there are a lot of rough edges (if you like clean setups, this isn't one- the sheer scale of the task is too big to justify yet).&amp;#160; It also made testing test changes easier- I build everything on my machine, and can schedule a job to pick up the content from there.&amp;#160; If I'm doing even more aggressive mixing and matching than usual, I actually assemble the binaries on the test machine and let the setup job copy them from there into the new official staged location [one part of the hard drive to another, but it's all with a tool we use continually and rarly needs to be done].&amp;#160; To be fully fair, I should add that I didn't get all the tests at this time, just the ones that we absolutely had to keep running.&amp;#160; For instance, our stress mix fell out.&amp;#160; But Shefali later chipped in on her own and got them working.&lt;/p&gt;  &lt;p&gt;Life was good- and there was now time to work on problems in the test code instead of trying to figure out how to continually tweak creaky automation into doing something slightly different every few days.&amp;#160; Shefali seemed pleased, and what the heck, making the boss happy is generally a good idea in the business world...&lt;/p&gt;  &lt;h1&gt;Trouble in Paradise&lt;/h1&gt;  &lt;p&gt;Until I deployed a new test.&amp;#160; Or rather a new variation on an old test.&amp;#160; I have a rather elaborate setup I use to verify operation of the IoTarget and IRP processing function in KMDF [although I don't go totally into queues- just the very basic configurations], and to support some new features in WDF 1.7 you'll be hearing about soon, I added UMDF drivers into that test.&amp;#160; I had to add another parameter to make sure I had all the flexibility I needed in finding a UMDF update coinstaller, but that's not a problem.&amp;#160; I put it all together, tested it quite a bit, rejoicing somewhat in how easy this new process made it for me to do a test that was now creating 88 different devices on top of a virtual test bus, installing the proper drivers with no popups in sight, and then putting those devices through their paces- and it looked good.&amp;#160; So I called it complete. got it reviewed, and checked it all in.&amp;#160; [For the 2 or 3 regular readers [overestimating my impact again?] &lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2008/02/08/why-you-ll-never-see-a-sample-from-me.aspx" target="_blank"&gt;this is the test with the targets and &amp;quot;hunters&amp;quot; where I showed some code here&lt;/a&gt;].&lt;/p&gt;  &lt;p&gt;But early this week, it failed.&amp;#160; Makecat wouldn't process the UMDF coinstaller from our own build machines (to debug it, I forced WTT to halt when this failed- we were losing logs due to some problems not worth going into here- the following is an email snippet):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif""&gt;I set the task to freeze if it fails.&amp;#160; This is weird- this is the tail of the self-sign log:       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif""&gt;       &lt;p&gt;&amp;#160;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif""&gt;processing: &amp;lt;hash&amp;gt;C:\kmdftest\WUDFSvc.dll.mui       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif""&gt;processing: &amp;lt;hash&amp;gt;C:\kmdftest\&lt;/span&gt;&lt;span style="font-size: 11pt; color: red; font-family: " calibri","sans-serif""&gt;WUDFUpdate_01007.dll&lt;/span&gt;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif""&gt;       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: red; font-family: " calibri","sans-serif""&gt;NOT processed: calculating the indirect data (C:\kmdftest\WUDFUpdate_01009.dll)       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: red; font-family: " calibri","sans-serif""&gt;Failed: CryptCATCDFEnumMembersByCDFTagEx.&amp;#160; Last Error: 0x80004005       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: red; font-family: " calibri","sans-serif""&gt;       &lt;p&gt;&amp;#160;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt;    &lt;p class="MsoNormal" style="margin: 0in 0in 0pt"&gt;&lt;span style="font-size: 11pt; color: red; font-family: " calibri","sans-serif""&gt;Errors found in parsing the CDF file       &lt;p&gt;&lt;/p&gt;     &lt;/span&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A comedy of errors ensued for a while after that, as I tried to find out why the 1.7 RC1 coinstaller was there when the job parameters I was told used pointed to locations that couldn't have contained it [if I'd dug into the job reports, I'd have seen that when the set they gave didn't work, they pointed to a server containing that and tried it again].&amp;#160; Once that was settled, I began focusing on why makecat was giving me the ever-so-helpful E_FAIL parsing a file that seemed perfectly good.&lt;/p&gt;  &lt;p&gt;Well, it was the file itself for some reason- take it out of the CDF, makecat worked.&amp;#160; Have it as the only one in the CDF, same error.&amp;#160; Since we&amp;#160; recently had some changes made, I was wondering how they could affect hashing the file- so I went back and tried earlier versions.&amp;#160; This led to another comedy of errors when I inadvertently mistyped a path and the process worked [because it couldn't find the coinstaller, and without going too deep into why, I couldn't treat it as an error at this point in our setup job].&lt;/p&gt;  &lt;p&gt;Well, the world was looking strange- I know I ran this dozens of times while I was developing this, didn't I?&amp;#160; We'd run it the previous week, and there'd been no problems.&amp;#160; It got stranger when I ran the same thing on a Windows 7 machine, and it worked flawlessly.&amp;#160; Why should the OS have made a difference?&amp;#160; It was the same set of binaries, tools and all...&amp;#160; Now if I weren't stressed and well-befuddled by then, I might not have continued to be so stressed and befuddled at that point, but of course I was and I did...&lt;/p&gt;  &lt;p&gt;But this is serious after all- in this design, all the test pass eggs are in one basket called the staging or &amp;quot;Unified Setup Job&amp;quot; and with it broken, NOTHING works!&lt;/p&gt;  &lt;h1&gt;&lt;/h1&gt;  &lt;h1&gt;Fools Rush In&lt;/h1&gt;  &lt;p&gt;And this old fool is no exception.&amp;#160; &lt;/p&gt;  &lt;p&gt;Ilias sends me an email about the problem late in the day with &lt;a href="http://www.xkcd.com/378/" target="_blank"&gt;this link&lt;/a&gt; and the comment &amp;quot;real programmers use butterflies&amp;quot;.&amp;#160; I had decided what I was going to do, so at about 5 AM the next morning (I started sometime between 1 and 2 AM) in reply I said, &amp;quot;&lt;span style="font-size: 11pt; color: #1f497d; font-family: " calibri","sans-serif"; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA; mso-bidi-font-family: Arial"&gt;A &lt;u&gt;&lt;font color="#0000ff"&gt;&lt;a href="http://en.wikipedia.org/wiki/Image:Sledgehammers-1.jpg" target="_blank"&gt;sledgehammer&lt;/a&gt;&lt;/font&gt;&lt;/u&gt; is more my style&amp;quot;- &lt;font color="#400040"&gt;ahh, well- afterthought says &amp;quot;Real SDETs use sledgehammers&amp;quot; might have been a better retort...&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;Onward- &amp;quot;Take the bull by the horns!&amp;quot;, Papa sez to himself, and loads the debugger package on the machine.&amp;#160; Point it to makecat, give it the command line to process the CDF, and go.&amp;#160; Make sure we've got all the symbols [miracle of all, they were there the first time!], and set a breakpoint on the routine name which was most helpfully displayed in that error message above, and go.&amp;#160; Then step into the code [now while I did have symbols, I don't normally need to work with that part of the Windows source, and this is Windows 2003, anyway- so I'm doing it the old-fashioned way, reading the assembler and using the old noggin to cipher out what's up...&amp;#160; I wasn't totally cheating- but because I had symbols I could see internal names and also the names and types of local variables, so I wasn't flying entirely blind].&lt;/p&gt;  &lt;p&gt;Now before I did this, I went through a phase where I thought there was a defect I could note externally that would tell me what had happened- and in the process, I dumped the headers of the coinstaller with the linker (link /dump /headers &amp;lt;file name&amp;gt;).&amp;#160; It seems to me that my long-term memory is beginning to suffer the ravages of age, but short-term is still pretty good, so I still remember things like this:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; 10 number of directories     &lt;br /&gt; 11440 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 8D] RVA [size] of Export Directory      &lt;br /&gt; 10974 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 50] RVA [size] of Import Directory      &lt;br /&gt; 15000 [&amp;#160; 12A53C] RVA [size] of Resource Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Exception Directory      &lt;br /&gt;&amp;#160;&lt;font color="#ff0000"&gt;13400 [&amp;#160;&amp;#160;&amp;#160;&amp;#160; FB8] RVA [size] of Certificates Directory&lt;/font&gt;      &lt;br /&gt;140000 [&amp;#160;&amp;#160;&amp;#160;&amp;#160; AE0] RVA [size] of Base Relocation Directory      &lt;br /&gt;&amp;#160; 1210 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1C] RVA [size] of Debug Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Architecture Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Global Pointer Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Thread Storage Directory      &lt;br /&gt;&amp;#160; 5530 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 40] RVA [size] of Load Configuration Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Bound Import Directory      &lt;br /&gt;&amp;#160; 1000 [&amp;#160;&amp;#160;&amp;#160;&amp;#160; 1D0] RVA [size] of Import Address Table Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Delay Import Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of COM Descriptor Directory      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0 [&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 0] RVA [size] of Reserved Directory&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;what was odd, was that even though this says a certificate was there, I couldn't see one in Explorer.&amp;#160; Odd, but it didn't raise any red flags to this old bull, so on he went.&lt;/p&gt;  &lt;p&gt;Well, after much digging and a bit of backtracking, I found the place makecat decided to make that error.&amp;#160; So I followed the preceding call deeper and deeper and got into code that was preparing to hash the binary and was looking for parts of the PE image to exclude.&amp;#160; Now it happens I've done lots of hacking to binaries- stripping resources out, putting them back in, altering tables and all sort of general mayhem, so following this code is a snap, even in assembler [with those handy locals about, anyway].&amp;#160; I find a path where it is clearly failing, and looking back up through the registers shown as I single-stepped the code, the values FB8 and 13400 caught my eye.&amp;#160; Hurrah for what memory remains!&amp;#160; A quick check confirmed they were the header values.&amp;#160; Bashing them against the values in dv, I had my cause...&lt;/p&gt;  &lt;p&gt;It had refused to hash the binary because the certificate was not at the end of the file's memory image- specifically, the resources followed it.&amp;#160; It turns out this also caused the certificate to be invisible to explorer and made signtool verify most unhappy [but signtool also happily replaced the certificate in situ every time I tried, alas].&lt;/p&gt;  &lt;p&gt;I then sent a rather rambling and somewhat incoherent email to &lt;a href="http://blogs.msdn.com/iliast" target="_blank"&gt;Ilias&lt;/a&gt; telling him we'd been building an unsignable UMDF coinstaller [too much stress and too little sleep- forgot that it had worked in Windows 7] since time immemorial.&amp;#160; Probably boosted his blood pressure since I wasn't all that clear I meant only on our private build line [obviously WHQL signs the official versions from time to time, after all].&amp;#160; I also wasn't making any clear distinction between signing the binary by embedding a certificate and signing it by having it properly hashed in a catalog signed with an embedded certificate [that duplication of terms has always been a source of confusion] . After a face to face and some more coherent and detailed explanations from me we had it down- that only the UMDF coinstaller from our private line was unsignable, and then only on Windows 2003 and earlier [I'm afraid you'll have to repeat some of what I did to see why]...&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/bobkjelgaard/archive/2007/12/13/kmdf-1-7-and-the-server-2008-vista-sp1-rc1-wdk.aspx" target="_blank"&gt;As I describe here&lt;/a&gt;, I can disassemble the coinstallers quite readily and in converse I know how they're put together- the problem is clearly that we signed it before we added the update package as a resource [now the package that does this could just be made smarter...]. We found out how that's happening, but fixing it is proving a challenge.&lt;/p&gt;  &lt;p&gt;Well, the main build lines have well-funded and trained staff to handle all those scripts that handle all those things we do after build- on a private line like ours, you have something a bit more seat of the pants, and Ilias is not the originator of most of those scripts.&amp;#160; If you've been around software long enough, you probably get the picture- logging not quite up to snuff, commentary a bit lacking, and so on.&amp;#160; He's still working on it [actually, he's going on vacation, so my old buddy Kumar probably gets to hold this hot potato].&lt;/p&gt;  &lt;p&gt;So you unhappy souls we've held up with the Server WDK [and I mean this with all sympathy and respect- you've got good reason to feel that way] aren't the only ones with coinstaller issues- but at least this one is never going to affect you.&lt;/p&gt;  &lt;p&gt;I also got to tell him somewhere in the middle of all that about my fascination with the Gordian Knot, him being Greek and all [alas, I kept wondering if Greeks regarded Alexander as Greek, since Alexander was Macedonian- but I kept saying Mycenaean and totally fudging the issue- that aging memory again].&amp;#160; This time I figured my brute force approach to the knot was debugging it myself instead of doing the usual thing and trying to find someone who could just tell me or wanted to find out why something didn't work on such an old operating system [lets face it, the main focus is on Windows 7 around here].&amp;#160; He admitted to being one of those closet WdfVerifier users I occasionally speculate exist, and so it went [our conversations are usually quite a bit of fun, even when the situation isn't all that much fun- similar sense of humor, perhaps].&lt;/p&gt;  &lt;p&gt;Those who hate my endless music lists can rejoice- this was much too long to bother trying to accumulate one.&amp;#160; But I at least got to hear all that good stuff (ahh, Garcia's &amp;quot;Bird Song&amp;quot;- &amp;quot;tell me all that you know- I'll show you snow and rain&amp;quot;)&lt;/p&gt;  &lt;p&gt;L8r!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8382540" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/lifestyle/default.aspx">lifestyle</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category></item><item><title>So Nice I Tried it Twice</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2008/01/31/so-nice-i-tried-it-twice.aspx</link><pubDate>Fri, 01 Feb 2008 03:58:12 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7362808</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/7362808.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=7362808</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=7362808</wfw:comment><description>&lt;p&gt;Yeah, the disco daze wuz good uns...&amp;#160; As long as I'm on the &amp;quot;Papa B Dumb&amp;quot; kick, I'll add a most embarrassing errata for WdfVerifier- this will be there in the official 6001 WDK, much to my eternal shame...&lt;/p&gt;  &lt;p&gt;With all the things to test on WdfVerifier, you'd think Papa would make sure that UMDF debugger launching would work with the default debugger locations from installing &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" target="_blank"&gt;Debugging Tools For Windows&lt;/a&gt;.&amp;#160; Papa sure would have said so, right up until he did his late-in-the game manual tests for said WDK.&lt;/p&gt;  &lt;p&gt;Papa forgot that if a path has spaces in it, you need to use double quotes around it to form a working command line.&amp;#160; Well, actually not even Papa would forget that- as soon as the debugger launched and then complained it couldn't find &amp;quot;Files\Debugging Tools For Windows 64-bit -&amp;lt;debugger switches papa done fergot&amp;gt;&amp;quot; he knew what he'd done, and he knew it wasn't good, and he also knew it was too late to do anything about it but realize he was a dunderhead and that work item he filed for getting some regular automated testing was a lot more necessary than hoped.&lt;/p&gt;  &lt;p&gt;Not what anyone should expect from QA.&amp;#160; Live I shall, learn- well, we'll find out about that one if I'm lucky enough to get another shot at that sort of thing.&lt;/p&gt;  &lt;p&gt;There is a workaround, but it's ugly- install your package (or copy it after installation) to a path with no spaces in it.&lt;/p&gt;  &lt;p&gt;It was easy enough to fix, of course- but it won't get out there for a while, now.&lt;/p&gt;  &lt;p&gt;On the bright side, at least, I'm not sure anybody actually uses this feature [nobody mentioned this flaw, after all], nor this tool.&amp;#160; So p'rhaps 'tis much ado about nothing...&lt;/p&gt;  &lt;p&gt;With that thought, I'll go see if there's anything useful I could be doing.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7362808" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category></item><item><title>Papa's "Wall of Dumb"</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2008/01/31/papa-s-wall-of-dumb.aspx</link><pubDate>Fri, 01 Feb 2008 02:06:42 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:7360864</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/7360864.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=7360864</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=7360864</wfw:comment><description>&lt;p&gt;If memory serves correctly, always an iffy thing with us old fogies, Chloe Sullivan (on &amp;quot;Smallville&amp;quot;) maintained a &amp;quot;Wall of Weird&amp;quot; covering all the strange events in her benighted hometown.&lt;/p&gt;  &lt;p&gt;So Papa's decided to inaugurate his &amp;quot;Wall of Dumb&amp;quot; today- but don't worry about showing up on it- this wall is for Papa's dumb ideas.&amp;#160; If I get ambitious enough to think about and and describe all of &lt;strong&gt;those&lt;/strong&gt; I've had, 'twould be a grand wall indeed!&lt;/p&gt;  &lt;p&gt;Today's entry (the fuel for this disgruntled posting) is a DDI test for a new KMDF 1.9 feature.&amp;#160; Can't tell you about the feature, of course, but as a result of one of the relevant DDI, the driver writer can allocate large numbers of objects if he or she so desires.&amp;#160; The original plan had a cap on the amount you could request, so of course I had a test that hit just above that mark.&amp;#160; But then the cap was removed, the idea being to allow as much as there was memory for.&lt;/p&gt;  &lt;p&gt;So Papa said- &amp;quot;hey fine, the number I want is a ULONG, so I'll ask for 4 billion or so [(ULONG) -1]- that ought to fail eventually [sure will on any machine I own], and I can verify it all cleans up nicely afterwards, and so forth&amp;quot;.&amp;#160; Possibly a dumb idea as it turned out, but we'll get back to that.&lt;/p&gt;  &lt;p&gt;Later Papa was looking at the possibility that if there was a bug in the driver or framework, he might hang forever, so he put an explicit 20 second timeout on each test.&amp;#160; The timeout was reported, and the test had very specific history tracking and such that it would be easy to look at the logs and see just about where it hung.&amp;#160; The idea here being that an automated run would detect and report the failure, the logs would give a good idea where to look, and if needed, good clues for either code review of suspect areas or good breakpoints for repro could be easily determined.&amp;#160; Thinking ahead, Papa thought he was.&lt;/p&gt;  &lt;p&gt;Perhaps you see where this is headed...&lt;/p&gt;  &lt;p&gt;Papa ran his test, debugged it, found bugs in the feature, and eventually got it into the regular automation runs for KMDF.&amp;#160; All was well, the test had no false positives or negatives, and no feature regressions turned up [in part because by then it was the winter holidays and all the folks that could have been breaking stuff were on vacation].&lt;/p&gt;  &lt;p&gt;Meanwhile, in other parts of Testland, trouble was a brewin'- older test drivers developed by more junior folks and at a time when we were still becoming familiar with the technologies that would just as soon bugcheck as look at ya.&amp;#160; So after picking out the worst of that lint, Papa enabled driver verifier on the framework runtime, loader and the most likely of the corrupting drivers.&lt;/p&gt;  &lt;p&gt;In some ways this was a very good thing.&amp;#160; New bugs were found, even some framework bugs we should have been catching sooner.&amp;#160; Many more horrible test bugs also surfaced- nice icky big ones that steal your lunch when you're not looking and slap you in the back of your head with their tails as the scuttle out of sight...&amp;#160; Papa had more fun than an SDET should trying to squash all them 'orrible critters.&lt;/p&gt;  &lt;p&gt;But Papa's prize test, the one where he pushed some gnarly hacks for quicker tracking and coding, and where he did things like tear down one software device stack while spawning another [to increase throughput at runtime, of course]- it began crashing, timing out on one test, and sometimes even bugchecking.&amp;#160; Papa was mortified.&lt;/p&gt;  &lt;p&gt;But Papa was very busy with all his other problems [including some installation issues people have presented through this blog- keep 'em coming], so he just had to wait for some time to investigate, wondering in the meantime what could be wrong with his bus driver [had to be the bus driver- couldn't possibly be an issue with the newest code- that blind spot has always troubled that old dude].&lt;/p&gt;  &lt;p&gt;So today he finally got his chance.&amp;#160; The test quickly hit the overlong case, so Papa broke into the debugger, set up his symbols, loaded the extension, and thinking &amp;quot;well, let's see how far this got- maybe I'll just see what handles and such are in my driver&amp;quot;:&lt;/p&gt;  &lt;p&gt;!wddfdriverinfo &amp;lt;DriverNameSuppressedToPreventPapaBeingDismissedForLeakingConfidenshulInfermashuns&amp;gt; ff&lt;/p&gt;  &lt;p&gt;That command is still running, and it's been over an hour, and it will probably be a lot longer- the same object type, over and over.&lt;/p&gt;  &lt;p&gt;So let's see, standard settings include special pool, so instead of each object taking a few bytes, it consumes a page of pool.&amp;#160; Pages are fewer in number than bytes, and there is extra overhead for all that neat tracking driver verifier does.&amp;#160; So that 20 seconds that was enough with it off to run out of memory wasn't near enough with special pool on.&lt;/p&gt;  &lt;p&gt;Papa is an idiot.&amp;#160; Really should have seen that one coming...&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=7360864" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/test+development/default.aspx">test development</category></item><item><title>WdfVerifier tricks- Controlling DbgPrint on Vista and later OS</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2007/10/16/wdfverifier-tricks-controlling-dbgprint-on-vista-and-later-os.aspx</link><pubDate>Wed, 17 Oct 2007 01:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5476494</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/5476494.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=5476494</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=5476494</wfw:comment><description>&lt;P&gt;This is one you can use even if you never use WDF at all (of course, you may find WdfVerifier to be a bit annoying for such a use, but if you've got a memory like mine...).&amp;nbsp; I wound up doing this a couple of days back, and thought it would make good fodder for the "gotta add more blog content" jones.&lt;/P&gt;
&lt;P&gt;As &lt;A href="http://blogs.msdn.com/bobkjelgaard/archive/2007/09/14/a-brief-history-of-wdfverifier.aspx" mce_href="http://blogs.msdn.com/bobkjelgaard/archive/2007/09/14/a-brief-history-of-wdfverifier.aspx"&gt;I mentioned earlier&lt;/A&gt;, the KMDF loader (since it has to work all the way back to Win2K) uses DbgPrint for its diagnostic messages.&amp;nbsp; Having no memory, I thought it would be nice if WdfVerifier took care of turning it on and off for me so I wouldn't have to look up &lt;A href="http://blogs.msdn.com/doronh/archive/2006/11/14/where-did-my-debug-output-go-in-vista.aspx" target=_blank mce_href="http://blogs.msdn.com/doronh/archive/2006/11/14/where-did-my-debug-output-go-in-vista.aspx"&gt;the post in Doron's blog that I used as a crutch whenever I had to do this&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;As a result, the latest version (6001 RC0 WDK, available on an MS Connect near you) of WdfVerifier will turn DbgPrint on and off- but it is actually more precise than the method listed almost anywhere else- it enables only the specific mask bit the DbgPrint implementation actually uses!&amp;nbsp; Of course, almost nobody bothering to use DbgPrintEx uses the default setting, but hey, if they ever do- I've already got you covered!&amp;nbsp; With my usual attempt to be thoughtful, you can configure the way this support works to suit you, which is crucial to this discussion.&lt;/P&gt;
&lt;P&gt;I'm going to assume for this post that you could care less about the KMDF loader, or KMDF in general- but you use DbgPrint, and find having to look up that key name or remembering the debugger method more than a bit annoying.&amp;nbsp; WdfVerifier just might make even&amp;nbsp;one WDF-less development task a tad less annoying.&lt;/P&gt;
&lt;P&gt;To begin, you point WdfVerifier at your Vista or Server 2008 box (or copy it there and run it directly- whichever method matches your working style).&amp;nbsp; You then:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Go to the &lt;EM&gt;Tool Preferences&lt;/EM&gt; tab, and go down to the group box entitled &lt;EM&gt;On Committing changes to:&lt;/EM&gt;, and drop down the list next to &lt;EM&gt;KMDF verifier settings:&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;Select the item named &lt;EM&gt;Simply Exit With No Prompts&lt;/EM&gt;, which of course I now think should have been labeled something else, since "Apply" won't actually exit anything...&lt;/LI&gt;
&lt;LI&gt;Now go to the group box labeled &lt;EM&gt;Vista DbgPrint Enabling&lt;/EM&gt;.&lt;/LI&gt;
&lt;LI&gt;If you want to turn DbgPrint ON, select &lt;EM&gt;Turn DbgPrint output on if needed for loader diagnostics, but do not turn it off.&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;If you want to turn it OFF, select &lt;EM&gt;Turn DbgPrint output on and off as I turn KMDF Loader diagnostics on and off.&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;Now go to the &lt;EM&gt;Kernel Mode Driver Settings&lt;/EM&gt; tab.&lt;/LI&gt;
&lt;LI&gt;Click the Checkbox &lt;EM&gt;Enable KMDF Loader Diagnostic Messages to Kernel Debugger&lt;/EM&gt;, then press &lt;EM&gt;Apply.&lt;/EM&gt;&lt;/LI&gt;
&lt;LI&gt;Repeat the last step.&lt;/LI&gt;
&lt;LI&gt;If the checkbox is ON (meaning it was on when you started, which would be rather weird if you don't care about KMDF), do it a third time.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;So that checkbox is always OFF when you exit.&amp;nbsp; What that means is DbgPrint ON or OFF, you won't have any KMDF loader messages interfering with your trace.&lt;/P&gt;
&lt;P&gt;How all that worked ought to be self-explanatory, of course.&amp;nbsp; But you know, it might be more convenient than firing up RegEdit, remembering key names and keywords, etc.&amp;nbsp; Just a few clicks and very little typing.&amp;nbsp; It reads harder than it does, if you catches my drift...&lt;/P&gt;
&lt;P&gt;That's how I like my tools- but after all, it's both optional and free- if you don't like it, no need to use it...&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1&gt;The adept among you no doubt noticed I didn't use a spell checker, and my first group box typo'd "committing".&amp;nbsp; I used to have no problem with that rule, but after stubbing my mind against "editing" so many times, I now can mess up all my doubled consonants...&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT size=1&gt;Ah well, that and the second bullet are what next versions are for- assuming anyone actually uses it and we don't decide to use that valuable WDK space for something &lt;EM&gt;&lt;STRONG&gt;useful&lt;/STRONG&gt;&lt;/EM&gt;...&lt;/FONT&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5476494" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category></item><item><title>WdfVerifier Basics- Assistance in debugging UMDF drivers</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2007/10/08/wdfverifier-basics-assistance-in-debugging-umdf-drivers.aspx</link><pubDate>Mon, 08 Oct 2007 23:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5370935</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/5370935.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=5370935</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=5370935</wfw:comment><description>&lt;P&gt;One of the most interesting set of requests for the WdfVerifier tool in its latest incarnation involved simplifying the attachment of debuggers to UMDF drivers.&amp;nbsp; I believe that WdfVerifier can now be used to great advantage here.&amp;nbsp; Without it, you must find the PID (Process ID) of the host process in which your driver is running, and then launch a debugger and direct it either through the command line or (in the case of WinDbg or the visual studio debugger) its UI to attach to that PID.&lt;/P&gt;
&lt;P&gt;The earliest version of WdfVerifier which appeared in the WDK at least listed the PIDs, but you were still on your own to attach the debugger.&amp;nbsp; But we wanted to do better by our developer users, and I believe we now have.&lt;/P&gt;
&lt;P&gt;This is a list of things&amp;nbsp;WdfVerifier will assist the UMDF driver developer with:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;If you use the Debugging Tools For Windows package, it can usually find all of the debuggers for you and can pick whichever is your favorite for launching a debugging session either when needed, or at the click of a button.&lt;/LI&gt;
&lt;LI&gt;If it can't find the debuggers, it is easily pointed to them.&lt;/LI&gt;
&lt;LI&gt;You can use it to force your driver to be restarted if you want to attach a debugger at process start or driver load (although driver load is the logical choice 90+% of the time).&lt;/LI&gt;
&lt;LI&gt;You can use a different debugger as long as it can handle getting a PID in the command line.&lt;/LI&gt;
&lt;LI&gt;You can attach a debugger to any running UMDF driver at the click of a button.&lt;/LI&gt;
&lt;LI&gt;The debugger command line which is built in is sufficient for most uses, but you can easily change it if you wish to.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;There are also extended controls for UMDF in this version, including control of framework tracing, failure retries, and kernel debugger interactions (for those that simply must live the hard way).&lt;/P&gt;
&lt;H2&gt;&lt;FONT face=Verdana&gt;Debugger Auto-launch- or automatic "Set and forget" debugger attachment.&lt;/FONT&gt;&lt;/H2&gt;
&lt;P&gt;This is how we've referred to one of these features.&amp;nbsp; If you&amp;nbsp;have asked the host process to wait for debugger attachment (all you need to do is enter a non-zero number in the edit control between "wait" and "seconds" about halfway down the tab), and your debugger preference is confirmed (meaning WdfVerifier was able to find the executable file for the debugger), then the "Automatically launch user-mode debugger when requested" checkbox is available.&amp;nbsp; &lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If that checkbox is on, then WdfVerifier watches for new UMDF host processes to start running.&amp;nbsp; When one does, it automatically starts the preferred debugger,&amp;nbsp;with the proper command line to attach it to the process.&amp;nbsp; Since this is an asynchronous process, I recommend you set the wait to at least 3-5 seconds- but that is still much faster than what you can normally do if you're trying to look it all up yourself.&amp;nbsp; Most of the time when I try it, it seems virtually instantaneous (a setting of "1" works for me, but why push your luck?).&lt;/P&gt;
&lt;P&gt;I've found this useful in conjunction with a second feature: if you change trace settings for UMDF, they do not apply until all host processes exit and are restarted.&amp;nbsp; So WdfVerifier will ask&amp;nbsp; if you want this done when those settings change.&amp;nbsp; So, for safe and sure attachment of a debugger to your driver, just set up the auto-launch feature, then&amp;nbsp;change a trace setting&amp;nbsp;(my favorite is toggling the "Send log&amp;nbsp;output to the kernel debugger" setting, since I don't&amp;nbsp;often need one in debugging UMDF drivers) and press "Apply now".&amp;nbsp; In a few short seconds, I have a debugger session up with my driver ready to debug.&lt;/P&gt;
&lt;H2&gt;Why not just attach to a running driver at any time?&lt;/H2&gt;
&lt;P&gt;You can do this by selecting the PID from the list on the UMDF tab, and pressing a button.&amp;nbsp; So that was also made easy- however, if you did NOT have UMDF set up for user mode debugging at the time that particular process started, then the kernel-side reflector will think the process is hung if you have it broken in the debugger.&amp;nbsp; If this happens when it tries to handle a PnP or power event, the process you are trying to debug will be shut down.&amp;nbsp; Since that's probably not what you want, I&amp;nbsp; usually recommend the auto-launch method.&lt;/P&gt;
&lt;H2&gt;&lt;FONT face=Verdana&gt;Feedback?&lt;/FONT&gt;&lt;/H2&gt;
&lt;P&gt;Let us know what you think of these features, or if there is anything else that might make life better as a UMDF developer.&amp;nbsp; If we can make UMDF development easier to do as well as having it produce a product that is safer for end users, I think everybody wins- which isn't such a bad outcome!&lt;/P&gt;
&lt;P&gt;Additionally, I'm not certain any further description of this tool is needed.&amp;nbsp; If there's something else you want to know about, send some feedback on that, as well.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5370935" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/UMDF/default.aspx">UMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/WdfVerifier/default.aspx">WdfVerifier</category></item><item><title>Root Causing a Not Reproducible KMDF Installation Issue- part 3: Pay Dirt!</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2007/08/16/root-causing-a-not-reproducible-kmdf-installation-issue-part-3-pay-dirt.aspx</link><pubDate>Thu, 16 Aug 2007 19:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4417251</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/4417251.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=4417251</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=4417251</wfw:comment><description>&lt;P&gt;I'll begin by recapping where we've been.&amp;nbsp; In &lt;A href="http://blogs.msdn.com/bobkjelgaard/archive/2007/08/02/what-would-you-do-for-a-customer.aspx" target=_blank mce_href="http://blogs.msdn.com/bobkjelgaard/archive/2007/08/02/what-would-you-do-for-a-customer.aspx"&gt;part 1&lt;/A&gt;, an interesting installation issue was reported- interesting in that it was 100% reproducible on customer machines scattered about Europe, but not all such machines, and neither we nor the IHV who reported it to us could reproduce it.&amp;nbsp; After we got enough information to understand the symptoms,&amp;nbsp;a workaround was provided to the IHV so their customers could use their&amp;nbsp;devices, while we worked to&amp;nbsp;identify the underlying cause.&amp;nbsp; In &lt;A href="http://blogs.msdn.com/bobkjelgaard/archive/2007/08/10/root-causing-a-not-reproducible-kmdf-installation-issue-part-2-not-stupid-merely-human.aspx" target=_blank mce_href="http://blogs.msdn.com/bobkjelgaard/archive/2007/08/10/root-causing-a-not-reproducible-kmdf-installation-issue-part-2-not-stupid-merely-human.aspx"&gt;part 2&lt;/A&gt;, an attempt that should have been successful to capture the access violation behind it all failed, and I am left wondering &lt;EM&gt;Where Did I&amp;nbsp;Go Wrong?&lt;/EM&gt;&lt;/P&gt;
&lt;H2&gt;Rechecking assumptions&lt;/H2&gt;
&lt;P&gt;For a while, I reviewed previously known issues with the developers and/or PMs for the various installer technologies.&amp;nbsp; Many were registry based- I spend hours one day running the entire installation under a debugger checking every registry access, planning if necessary to script the debugger to log them all for me the next time I tried a pass at the customer's machine.&lt;/P&gt;
&lt;P&gt;We also discussed the issue quite a bit.&amp;nbsp; At one point we were considering buying / renting /borrowing one of the failing systems if we still couldn't find a way to solve the problem remotely.&lt;/P&gt;
&lt;P&gt;I also reviewed the coinstaller source code, and it was this review, coupled with all that time in the debugger on a working system,&amp;nbsp;that finally revealed the worst of my problems.&lt;/P&gt;
&lt;H2&gt;Doh!&lt;/H2&gt;
&lt;P&gt;Can't say it better than Homer!&amp;nbsp; Update.exe is where we've had problems, and the source code mentions it by name.&amp;nbsp; BUT, it is &lt;STRONG&gt;not&lt;/STRONG&gt; the program we extracted from the coinstaller, spawned and were checking the results of!&amp;nbsp; Instead, that program is a self-extracting CAB which has a very long name identifying the target OS and KMDF version.&amp;nbsp; In this particular case, it is &lt;FONT color=#00ff80&gt;&lt;EM&gt;&lt;FONT color=#0000ff&gt;Microsoft Kernel-Mode Driver Framework Install-v1.1-WinXP.exe&lt;/FONT&gt;. &lt;/EM&gt;&lt;/FONT&gt;&lt;FONT color=#000000&gt;The fatal access violation &lt;EM&gt;probably&lt;/EM&gt;&amp;nbsp;happened there after update.exe completed successfully!&lt;/FONT&gt;&lt;/P&gt;
&lt;H2&gt;Try, Try Again&lt;/H2&gt;
&lt;P&gt;After making such a blunder, I decide to be more careful the next time around.&amp;nbsp; This time, I script the debugger (after all an end user's machine is the only place this happens) to:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Debug the program and all of its child processes 
&lt;LI&gt;Take and overwrite the AV dump on each occurrence as before, but also 
&lt;LI&gt;Create a specific dump after each process exits (this is a point at which the debugger normally breaks, but I had turned it off on the previous try). 
&lt;LI&gt;Keep a log of everything for further reference in case I am making even&amp;nbsp;more mistakes.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;So I will have three dumps when all is done- the final two will include the stack with the ExitProcess call on it, and I can tell from such a trace what the return code was, so I will know (assusming as I had that the application is returning the code) which application set that code..&lt;/P&gt;
&lt;P&gt;The new registry file (note that the switches and key identity have changed):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;Windows Registry Editor Version 5.00&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Microsoft Kernel-Mode Driver Framework Install-v1.1-WinXP.exe]&lt;BR&gt;"Debugger"="C:\\Program Files\\Debugging Tools For Windows\\Cdb.Exe -o -logo C:\\Dumps\\Debugger.Log -c \"$&amp;lt;C:\\\\Dumps\\\\Script.Txt\""&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Second try- debug the self-extracting CAB and its children, also keep a log for later analysis.&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The script is also a bit more complicated:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;sxd -c ".dump /ma /o C:\\Dumps\\FinalAV.Dmp" av;g;g;.dump /ma /o C:\Dumps\EndUpdate.Dmp;g;.dump /ma /o C:\Dumps\EndExtractor.Dmp;q&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The new script is a bit more sophisticated, but still primitive, compared to what I've seen elsewhere.&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;For this, I'll give a brief breakdown:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;sxd -c ".dump /ma /o C:\\Dumps\\FinalAV.Dmp" av&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Issue the .dump command (this creates an "all process-related memory" user mode minidump, which is large but usually has everything you're likely to want) each time an access violation occurs- report the AV in the debugger log,&amp;nbsp;but&amp;nbsp;don't interfere with the&amp;nbsp;normal handling of it by the program which is being debugged.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;g&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Proceed with the self-extracting CAB.&amp;nbsp;&amp;nbsp;The debugger will break again&amp;nbsp;when update.exe, which is a child process of the one we began debugging, has been loaded and is ready to begin execution.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;g&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Let update.exe run until it ends (I know this will happen because it did the last time we tried this).&amp;nbsp; I expect the debugger&amp;nbsp;to break again when the process is exited.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;.dump /ma /o C:\Dumps\EndUpdate.Dmp&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Create a similar user mode minidump for update.exe at exit.&amp;nbsp;The &lt;STRONG&gt;kb &lt;/STRONG&gt;debugger command will show me the exit code from the process, and if I need to look at anything, there should at least be traces in this dump.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;g&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Resume execution now of the self-extracting CAB.&amp;nbsp; It should normally break when the CAB process exits.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;.dump /ma /o C:\Dumps\EndExtractor.Dmp&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Assuming this is the exit point for the extractor, create the final dump.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;q&lt;/STRONG&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Leave the debugger and stop the cab process.&amp;nbsp; If it wasn't done, we return anyway.&amp;nbsp; I will be able to tell from the dump if I've missed something.&lt;/P&gt;
&lt;H2&gt;You must have accidentally fixed it, or sent me the wrong stuff- it works now!&lt;/H2&gt;
&lt;P&gt;That was one user's reaction.&amp;nbsp; Actually,&amp;nbsp;in exiting by quitting the debugger, I caused the coinstaller to see a successful completion- so it looked like a successful install, and everything else then worked.&amp;nbsp; Good result, but not what I'd propose for a workaround!&lt;/P&gt;
&lt;H3&gt;Success!&lt;/H3&gt;
&lt;P&gt;This time, FinalAV.Dmp has exactly what I am looking for.&amp;nbsp; It also reveals my fallacy for good- this was an unhandled access violation after all (so the Watson tool could have been deployed as a much more elegant solution).&amp;nbsp; Still, I've got more data than Watson would normally provide, and you, gentle reader, now have a way to get a dump yourself if you ever find yourself in a similar situation...&lt;/P&gt;
&lt;P&gt;For the rest, I'll return to the record- this&amp;nbsp;snippet is&amp;nbsp;from the email I sent to the IHV's engineer, edited to remove names to protect privacy and IP.&amp;nbsp; The DWORD of 0's I highlighted in red is the return code passed to the Win32 ExitProcess API.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0:000&amp;gt; r&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;eax=00060800 ebx=00000001 ecx=00263e90 edx=00260608 esi=007a0031 edi=00000000&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;eip=10106022 esp=0006fd34 ebp=0006fd78 iopl=0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; nv up ei ng nz ac pe cy&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;cs=001b&amp;nbsp; ss=0023&amp;nbsp; ds=0023&amp;nbsp; es=0023&amp;nbsp; fs=003b&amp;nbsp; gs=0000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; efl=00010297&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;xxxxxxxx!clearxxHook+0xxxxx:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10106022 8b4010&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,dword ptr [eax+10h] ds:0023:00060810=????????&amp;nbsp; &amp;lt;- Note this is the address&amp;nbsp;&amp;lt;user&amp;nbsp;name&amp;gt;&amp;nbsp;reported (both the IP and Excepting address]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0:000&amp;gt; kb&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;ChildEBP RetAddr&amp;nbsp; Args to Child&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;WARNING: Stack unwind information not available. Following frames may be wrong.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006fd78 7c9111a7 10100000 00000000 00000001 &lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;xxxxxxxx&lt;/SPAN&gt;!clearxxHook+0xxxx&amp;nbsp; &amp;lt;- This is where the AV occurs&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006fd98 7c933f31 101081b4 10100000 00000000 ntdll!LdrpCallInitRoutine+0x14 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006fe1c 7c81cd76 0006ffc4 00082430 00000000 ntdll!LdrShutdownProcess+0x14f &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006ff10 7c81cdee 00000000 77e8f3b0 ffffffff kernel32!_ExitProcess+0x42 &lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006ff24 01005971 &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;00000000&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt; 00011970 7c9218f1 kernel32!ExitProcess+0x14 &amp;lt;- IE we were returning 0 (ERROR_SUCCESS)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0006ff30 7c9218f1 0006fff0 7ffde000 00000000 Microsoft_Kernel_Mode_Driver_Framework_Install_v1_1_WinXP+0x5971&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;&lt;o:p&gt;&lt;STRONG&gt;My first surprise- we are exiting the process when we take an access violation in cleanup code in a 3rd party's Windows global input hook DLL.&lt;/STRONG&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I poked around with the debugger until I had separated the failing routine to see if I could understand why it had the AV, and this snippet (edited for the privacy reasons noted above) finishes the story:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;This is the offending code (with some guesses, perhaps incorrect, as to what it is doing):&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10106010 51&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10106011 56&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106012 8b35f81a1110&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,dword ptr [xxxxxxxx!yyyyyyyy+0xxxxx (10111af8)] &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; fixed address, so must be in data segment&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106018 8b06&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,dword ptr [esi]&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010601a 3bc6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmp&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,esi&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; Looks like check for empty list (points to head)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010601c 89442404&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [esp+4],eax&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; Current list head saved to local variable???&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106020 7427&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; je&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xxxxxxxx!clearxxHook+0xxxxx (10106049) &amp;lt;- just leave if the list is empty&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106022 8b4010&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,dword ptr [eax+10h] &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; Attempt to access some value in the list item (this is where the AV occurs)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106025 85c0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; test&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,eax &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; check for some embedded structure?&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106027 740f&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; je&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xxxxxxxx!clearxxHook+0xxxxxx (10106038) &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; if not in use, jump ahead to what looks like a memory free / deallocate?&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106029 50&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp; eax &amp;lt;- looks like call to cleanup or deallocate said structure?&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010602a e887180000&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; xxxxxxxx!yyyyyyyy+0xxxxx (101078b6)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010602f 8b35f81a1110&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi,dword ptr [xxxxxxxx!yyyyyyyy+0xxxxx (10111af8)] &amp;lt;- get list head again (esi must not be preserved)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106035 83c404&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,4 &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; must be __cdecl…&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106038 8d4c2404&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; lea&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,[esp+4] &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; this looks like __thiscall which does something to the list item (cleanup / unlink?)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010603c e8cff9ffff&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp; xxxxxxxx!clearxxHook+0xxxxx (10105a10)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106041 8b442404&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,dword ptr [esp+4] &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: wingdings"&gt;ß&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt; get next item and repeat if list still not empty&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106045 3bc6&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; cmp&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,esi&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106047 75d9&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; jne&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; xxxxxxxx!clearxxHook+0xxxxx (10106022)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;10106049 5e&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esi&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010604a 59&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: red; FONT-FAMILY: 'Courier New'"&gt;1010604b c3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;My guesses (note, though, it’s possible the “list” was at least partially good, and we’re seeing something that actually happened after several passes through it)- they’re trying to walk a list, apparently, anchored in their data segment, but the list is pretty obviously trashed.&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;Why?&amp;nbsp; Well, let’s look at the segment section that’s trashed…&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;0:000&amp;gt; dc 10111a80&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111a80&amp;nbsp; 00000000 00000000 00000000 00000000&amp;nbsp; ................&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111a90&amp;nbsp; 00000000 00000000 00000000 00000000&amp;nbsp; ................&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111aa0&amp;nbsp; 00000000 00000000 00000000 00000000&amp;nbsp; ................&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111ab0&amp;nbsp; 00000000 00000000 00000000 00000000&amp;nbsp; ................&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111ac0&amp;nbsp; 00000000 00000000 7263696d 666f736f&amp;nbsp; ........microsof&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111ad0&amp;nbsp; 656b2074 6c656e72 646f6d2d 72642065&amp;nbsp; t kernel-mode dr&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111ae0&amp;nbsp; 00000000 61726620 6f77656d 69206b72&amp;nbsp; .... framework i&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Courier New'"&gt;10111af0&amp;nbsp; 6174736e 762d6c6c 007a0031 00000000&amp;nbsp; nstall-v1.z.....&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;Kind of looks like they didn’t expect our program name to be as long as it is, and never checked (also looks like they stopped at the first period they found in the name, rather than the final one, since “.1-WinXP” would be needed to complete the full file name).&amp;nbsp; &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;Copying it into their data segment trashed at least one critical structure (for instance, note that something wrote a NULL right in the middle of the name after it was presumably copied).&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt"&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: en-us; mso-fareast-language: en-us; mso-bidi-language: ar-sa"&gt;I’m doing an internet search to see if this is a known problem and if so, if there is a newer version of&amp;nbsp;&amp;lt;Product&amp;gt; that fixes this, and we can make the dump available to&amp;nbsp;&amp;lt;Vendor&amp;gt; if it isn’t and they need to see it.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: en-us; mso-fareast-language: en-us; mso-bidi-language: ar-sa"&gt;&lt;STRONG&gt;Snippet of my email reporting back to the IHV- I was close- the cause reported back to us was a "byte count vs character count" problem in a Unicode-&amp;gt;MBCS conversion.&lt;/STRONG&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;SPAN style="FONT-SIZE: 11pt; COLOR: #1f497d; FONT-FAMILY: 'Calibri','sans-serif'; mso-fareast-font-family: calibri; mso-fareast-theme-font: minor-latin; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: en-us; mso-fareast-language: en-us; mso-bidi-language: ar-sa"&gt;&lt;FONT color=#000000&gt;While I didn't mention it there, I actually did a search through the dump for the address at which the buffer started, to see if I could decipher that routine, but with no symbols, and calls going on to snake through, I cut it short after several minutes.&amp;nbsp; I clearly had enough to make an accurate report.&lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;H2&gt;The Aftermath...&lt;/H2&gt;
&lt;P&gt;I did indeed find&amp;nbsp;at least one 3rd party developer hit this bug before, but from the forum in which the report appeared, it did not sound like they actually reported it back to the producer of the faulty software.&amp;nbsp; We have contacted the provider of the suspect software, and they have confirmed that there is a&amp;nbsp;known defect&amp;nbsp;in that software that has since been fixed.&amp;nbsp; The product in this case is fairly old.&lt;/P&gt;
&lt;P&gt;I am not going to identify them, though.&amp;nbsp; If you are a developer using KMDF (this problem can affect all versions, and we have informed them of that), and you believe you are currently affected by this, contact us at &lt;A href="mailto:kmdffdbk@microsoft.com" mce_href="mailto:kmdffdbk@microsoft.com"&gt;kmdffdbk@microsoft.com&lt;/A&gt;, send me an email from this blog, or any other route you choose to get to us, and we will investigate the problem and make sure it gets solved if at all possible.&amp;nbsp; All indications (and this matches the vendor's report back to us) is that there is a small though finite probability this problem will affect you.&amp;nbsp; This isn't what I'd prefer to say, but it's the best I can do, for now.&lt;/P&gt;
&lt;H2&gt;Lessons?&lt;/H2&gt;
&lt;P&gt;I took away several, some of which apply to developers in a general sense:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;You can often debug effectively even without source code.&amp;nbsp; Strange as it may seem, I have no access to the source code for the (non-KMDF) Microsoft components involved, nor, of course, did I have it to the code which faulted.&lt;/LI&gt;
&lt;LI&gt;An openly cooperative stance toward your customers can make a world of difference.&amp;nbsp; In this case, our direct customer had such a stance with their end-user customers, and this transitive property of cooperativeness is what enabled us to finally identify the root cause.&lt;/LI&gt;
&lt;LI&gt;No matter how carefully you design and test, things are going to happen when you integrate various pieces of technology that you could not have predicted.&lt;/LI&gt;
&lt;LI&gt;If you're determined, persistent, and can establish a cooperative link to the person with a problem, you &lt;STRONG&gt;can&lt;/STRONG&gt; solve that problem even if you can't reproduce it yourself.&amp;nbsp; Maybe not every time, but that doesn't mean you shouldn't at least try.&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx" target=_blank mce_href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx"&gt;Debugging Tools For Windows&lt;/A&gt;&amp;nbsp;are &lt;STRONG&gt;&lt;EM&gt;&lt;U&gt;AWESOME!&lt;/U&gt;&lt;/EM&gt;&lt;/STRONG&gt;&amp;nbsp; I barely scratched the surface of their capability in this task.&lt;/LI&gt;
&lt;LI&gt;It can take a lot of heads to solve a problem like this.&amp;nbsp; Before being done, at least a dozen people contributed useful work in solving this problem.&lt;/LI&gt;&lt;/UL&gt;
&lt;H2&gt;Bye for a while...&lt;/H2&gt;
&lt;P&gt;Vacation coming- when I get back, I will do some articles on a WDK tool named WdfVerifier that should make it easier for you to test and debug your WDF drivers!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4417251" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category></item><item><title>Root causing a not reproducible KMDF installation issue- part 2: Not stupid, merely human</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2007/08/10/root-causing-a-not-reproducible-kmdf-installation-issue-part-2-not-stupid-merely-human.aspx</link><pubDate>Fri, 10 Aug 2007 20:39:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4323326</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/4323326.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=4323326</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=4323326</wfw:comment><description>&lt;P&gt;In the last installment, we had a workaround, so people could get on with their lives.&amp;nbsp; &lt;STRONG&gt;BUT&lt;/STRONG&gt;, there's still that problem of an access violation of unknown origin that happens every time we try to install KMDF 1.1 on a machine a continent or two away...&lt;/P&gt;
&lt;P&gt;I'll get right to the stupid / human part.&amp;nbsp; In my befuddled mind, I am convinced that this AV is being handled within the failing program itself.&amp;nbsp; Actually,&amp;nbsp;it is being handled by the OS code that manages the process.&amp;nbsp; But being lucky, my "direct approach" is still&amp;nbsp;a right one- if I try to use the normal post-mortem techniques, then the faulting stack will already have unwound to the exception handler that invoked a post-mortem debugger (however, the stack is typically still available using the debugger's &lt;STRONG&gt;&lt;EM&gt;.cxr&lt;/EM&gt;&lt;/STRONG&gt; command).&amp;nbsp; Being a simpleton, I want to see what's actually failing, rather than try to make guesses [because weeks have elapsed, there's been a whole lotta guessin' goin' on, and nothing really useful has come of it].&amp;nbsp; So I may be about to make things harder than they needed to be.&lt;/P&gt;
&lt;P&gt;So, the plan (simple minds like simple plans, and this is pure brute force]:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Have the user install the &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx" target=_blank mce_href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx"&gt;Debugging Tools For Windows&lt;/A&gt;&amp;nbsp;package, using the default settings. 
&lt;LI&gt;Create a REG file that uses &lt;A href="http://blogs.msdn.com/junfeng/archive/2004/04/28/121871.aspx" target=_blank mce_href="http://blogs.msdn.com/junfeng/archive/2004/04/28/121871.aspx"&gt;Image File Execution Options&lt;/A&gt;&amp;nbsp;to debug just the program I think is failing. 
&lt;LI&gt;Create a debugger script that,&amp;nbsp;&amp;nbsp;as each access violation&amp;nbsp;occurs (aka "first chance" exception), captures a rather exhaustive minidump, and just keeps doing this [overwriting it each time] until the process ends. 
&lt;LI&gt;Provide batch files for setting it all up and tearing it down, so that the user isn't left with a big mess on their machine when we're done [we are guests, after all- if we can't do the dishes, we can at least pick up after ourselves].&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The user received a ZIP file with several files and some instructions.&amp;nbsp; The first file here is this batch file, run to start the process:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;@echo off&lt;BR&gt;@Echo Preparing to capture dumps from broken installation...&lt;BR&gt;md c:\dumps&lt;BR&gt;md c:\dumps\backups&lt;BR&gt;@Echo Preparing to capture dumps from broken installation... &amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;reg import DebugUpdateExe.reg &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;net stop hypkern &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;net stop hypaudio &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;net stop wdf01000 &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;sc delete hypkern &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;sc delete hypaudio &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;sc delete wdf01000 &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\system32\drivers\hypkern.sys &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\system32\drivers\hypaudio.sys &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\system32\drivers\wdf01000.sys &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\system32\drivers\wdfldr.sys &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;copy script.txt c:\dumps &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;copy %windir%\setup*.log C:\Dumps\Backups &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;copy %windir%\wdf*.log c:\Dumps\Backups &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\setup*.log &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;del %windir%\wdf*.log &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;Echo You are now ready to attempt the installation again &amp;gt;&amp;gt; C:\Dumps\Preparation.log&lt;BR&gt;Echo You are now ready to attempt the installation again&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;&lt;FONT face="Courier New"&gt;A Batch file for a roll your own "try an install, get a minidump with the final AV, and make sure you get all the backup info you need in case anything in this massive hack breaks"&lt;/FONT&gt;&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The batch file does these things in order (I leave matching numbers to&amp;nbsp;batch&amp;nbsp;file lines&amp;nbsp;up to the reader, but you can always ask if you wants to).&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Directories are made to hold the dump and to backup setup-related files. 
&lt;LI&gt;A log file for the batch process is maintained, so we can review it in case anything breaks. 
&lt;LI&gt;We set things up so the debugger will debug the update binary when it spawns. 
&lt;LI&gt;Just to be safe, all of their driver services are stopped and then deleted (as is KMDF).&amp;nbsp; This is insurance, as they were told to uninstall first. 
&lt;LI&gt;To be even safer, all of the driver files are deleted. 
&lt;LI&gt;The debugger script is copied to a known directory, since the command line we registered references it. 
&lt;LI&gt;The setup-related log files are cached and then deleted. 
&lt;LI&gt;Just to be nice, we spit out a message saying they are now ready to retry the installation (the message being in a foreign language for them being hopefully forgivable under the circumstances).&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Our second file is this registry file that starts the secret debugging sauce:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;Windows Registry Editor Version 5.00&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\update.exe]&lt;BR&gt;"Debugger"="C:\\Program Files\\Debugging Tools For Windows\\Cdb.Exe -G -c \"$&amp;lt;C:\\\\Dumps\\\\Script.Txt\""&lt;BR&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;Secret sauce? No- just a way to make sure we debug only what we want to debug.&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Key things to note here:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;I used CDB&amp;nbsp;instead of WinDbg because by default, WinDbg is going to throw a popup when the session starts, and I don't want to confuse the user any further than I already will. 
&lt;LI&gt;The path is hard coded, but it is the default when the MSI on WHDC is used.&amp;nbsp; I verified this, and provided the user with instructions to allow them to double-check, just in case. 
&lt;LI&gt;The command line itself skips unneeded breaks [I imagine having a console window pop up in the middle of the installation is going to be shock enough, why make them punch keys?], and executes the script, which is what I will show next.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The third file in the package is the debugger script itself:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;sxd -c ".dump /ma /o C:\\Dumps\\UpdateAV.Dmp" av;g&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;FONT face="Courier New"&gt;A simple script for catching the final access violation in the program when it occurs, and then taking a "full minidump"&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Now this is pretty brute force- this script creates a dump &lt;EM&gt;every single time an access violation occurs!&lt;/EM&gt;&amp;nbsp; They occur a lot in user mode, but most are silently handled.&amp;nbsp; But it overwrites it each time.&amp;nbsp; Furthermore, if the final dump isn't the right one [as in maybe some AV occurs after the handler has decided to reflect the failure out], I can change a switch in the .dump command and get one each&amp;nbsp;time (and have them send the last half dozen or so, which I could mine to see if they had what I was looking for).&lt;/P&gt;
&lt;P&gt;Finally, being the good houseguest, there is the final file- the "cleanup script":&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;@Echo off&lt;BR&gt;echo Cleaning up the registry and collecting logs...&lt;BR&gt;echo Cleaning up the registry and collecting logs... &amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;reg delete "hklm\software\microsoft\windows NT\currentversion\Image File Execution Options\Update.Exe" /v Debugger /f &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;copy %windir%\setup*.log c:\Dumps &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;del %windir%\setup*.log &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;copy %windir%\wdf*.log c:\Dumps &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;del %windir%\wdf*.log &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;copy c:\Dumps\Backups %windir%&amp;nbsp; &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;@Echo Cleanup complete &amp;gt;&amp;gt; C:\Dumps\Cleanup.Log&lt;BR&gt;@Echo Cleanup complete&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;STRONG&gt;&lt;FONT face="Courier New"&gt;Cleaning up after the fact- turn off the debugger intervention, grab the installation logs, and put the original installation records back where you found them.&lt;/FONT&gt;&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;On my end, I not only try these pieces out to make sure they work, I save the final dump for comparison against the one they send back.&amp;nbsp; If it is the same AV, then we missed something.&amp;nbsp; I also make the change to catch "all" AVs (actually it doesn't- the switch uses the timestamp to name files, but the granularity isn't quite enough to literally catch all of them)- I'm looking at 100+MB of dumps, but I decide we can cross that bridge when we get to it.&lt;/P&gt;
&lt;H2&gt;So who gets to play host?&lt;/H2&gt;
&lt;P&gt;I already know from previous submissions that our valiant&amp;nbsp;European consumers can ZIP files, but even so, these dumps are going to be too big for an email.&amp;nbsp; Somebody needs an FTP site.&amp;nbsp; Yes, Microsoft has them, but its not like I know &lt;EM&gt;anything&lt;/EM&gt; about that!&amp;nbsp; So I ask the IHV engineer who's acting as the middleman if they have the capacity.&amp;nbsp; Turns out they do- so Bob can continue his&amp;nbsp;slacker ways, and let them host the files...&lt;/P&gt;
&lt;P&gt;When the middleman tries my technique, his installation breaks.&amp;nbsp; Might be the debugger return code is creeping out the code that calls it?&amp;nbsp; I decide that if we got the dumps, then we'll get what we really need so I urge him (perhaps against his better judgement) to pass it on to our end users [long may their devices function!].&lt;/P&gt;
&lt;H2&gt;No fairy tale ending here...&lt;/H2&gt;
&lt;P&gt;So, when all is said and done, what happens?&amp;nbsp; I get the same dump from the end user that I got on my own machine [cue Obi-Wan, who gestures and says "this is not the AV you are looking for"].&amp;nbsp; I could make the changes to ask for more, but for the moment, doubt about the whole chain of thought that has led us to this pass is the order of the day.&lt;/P&gt;
&lt;P&gt;Well, if George Lucas can end the second part of his trilogy on a down note, why can't I?&amp;nbsp; Since suspense won't change my compensation, I'll say now that I do eventually figure out where it all went wrong [and the above technique is basically sound, or I wouldn't have listed it here]- but I'm saving that for the next and final installment.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4323326" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category></item><item><title>Root causing a not reproducible KMDF installation issue- part 1: Looking for trouble, finding it, and working around it</title><link>http://blogs.msdn.com/bobkjelgaard/archive/2007/08/02/what-would-you-do-for-a-customer.aspx</link><pubDate>Thu, 02 Aug 2007 17:48:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:4190917</guid><dc:creator>BobKjelgaard</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/bobkjelgaard/comments/4190917.aspx</comments><wfw:commentRss>http://blogs.msdn.com/bobkjelgaard/commentrss.aspx?PostID=4190917</wfw:commentRss><wfw:comment>http://blogs.msdn.com/bobkjelgaard/rsscomments.aspx?PostID=4190917</wfw:comment><description>&lt;P&gt;Working in the Windows Driver Frameworks QA department has its challenges.&amp;nbsp; One of them for me has been that&amp;nbsp;occasionally there is a paucity of the interesting problems that make for an intense workday.&amp;nbsp; Since those are the days you write code or blog, they aren't wasted- they just lack that adrenaline...&lt;/P&gt;
&lt;P&gt;For one thing, in my opinion the development team is usually very good about testing before checking in.&amp;nbsp; Their unit tests are excellent and keep getting better [a topic I hope to return to someday].&amp;nbsp; For another, the other members of my team have put together additional tests that are also quite effective.&amp;nbsp; For instance, we have exhaustive DDI-level tests for the frameworks.&amp;nbsp; Microsoft has an excellent set of code coverage measurement tools, and we utilize these to further improve test coverage [the more you cover at even the path level, the less there is of "the easy stuff" to find].&amp;nbsp; In my case, a final factor is I'm Johnny-come-lately, so KMDF was much more stable by the time I began working on it than is often the case.&lt;/P&gt;
&lt;P&gt;But this is good- there are other aspects of quality than the simple bugcheck or hang, and that leaves time to go after them.&amp;nbsp; For instance, it leaves time to pursue "the ones that got away".&lt;/P&gt;
&lt;P&gt;This time, the problem could not be reproduced except on the end user's machine, and there were oceans, time zones, and a few national borders separating us.&amp;nbsp; Good reason to give up?&lt;/P&gt;
&lt;P&gt;Well, what &lt;U&gt;would&lt;/U&gt; &lt;STRONG&gt;&lt;EM&gt;you&lt;/EM&gt;&lt;/STRONG&gt; do for a customer with a problem?&amp;nbsp; The answer says a lot about how your business will fare [sorry- I used to run my own, so it's hard for me to not think in those terms].&lt;/P&gt;
&lt;H1&gt;&lt;STRONG&gt;Making House Calls?&amp;nbsp; Or Just "Beating the Bushes" to Search for Trouble?&lt;/STRONG&gt;&lt;/H1&gt;
&lt;P&gt;As an aside, this is how I got to where I could hear of this problem.&lt;/P&gt;
&lt;P&gt;The frameworks are developer tools, and developers of course have Internet communities.&amp;nbsp; Being shy to begin with and something of the lone wolf [although I prefer the term &lt;EM&gt;self-sufficient&lt;/EM&gt;], I have rarely participated in these.&amp;nbsp; But my manager insists I commit to doing &lt;EM&gt;something&lt;/EM&gt; to "engage customers", so I decide a mailing list is a good place to start.&lt;/P&gt;
&lt;P&gt;OSR's NTDEV mailing list is recommended to me by several colleagues as an active community of likely early adopters of KMDF, and also having a high level of expertise.&amp;nbsp; So, with a general idea of monitoring traffic to see if we missed anything in our test processes, I subscribe.&amp;nbsp; I also begin participating [often quite foolishly, because my judgement's never been terribly good in any community-&amp;nbsp;I also tend to shoot from the hip, which doesn't always go well with such an audience], but that's not of much further relevance.&lt;/P&gt;
&lt;H1&gt;An Opportunity to Help&lt;/H1&gt;
&lt;P&gt;So:&amp;nbsp;many days later, a post arrives (&lt;A href="http://www.osronline.com/showthread.cfm?link=110819" mce_href="http://www.osronline.com/showthread.cfm?link=110819"&gt;http://www.osronline.com/showthread.cfm?link=110819&lt;/A&gt;).&amp;nbsp; A developer has used KMDF in their product, and the installation is failing mysteriously on a very small percentage of machines, all of them in Europe.&amp;nbsp; This sounds like a potential test escape to me!&amp;nbsp;After exchanging a few posts on the mailing list, I ask the developer if we can work via email to address the problem.&amp;nbsp; He agrees.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;So, just what seems to be the problem?&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;Those who read &lt;A href="http://blogs.msdn.com/doronh" target=_blank mce_href="http://blogs.msdn.com/doronh"&gt;Doron Holan's blog&lt;/A&gt;&amp;nbsp;know that there are several files that can tell us quite a bit of history about what may have broken for you when a KMDF driver installation fails.&amp;nbsp; Our customer is obviously conversant with these facts, because&amp;nbsp;his very first post has the problem that I focus on from the beginning.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;WdfCoInstaller: [03/27/2007 23:59.53.609] DIF_INSTALLDEVICE: Pre-Processing&lt;BR&gt;WdfCoInstaller: [03/27/2007 23:59.53.718] ReadComponents:&amp;nbsp; WdfSection for Driver Service hypkern using KMDF lib version Major 0x1, minor 0x1&lt;BR&gt;WdfCoInstaller: [03/27/2007 23:59.53.875] VerifyMSRoot: exit: error(0) Op?ration r?ussie.&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT face="Courier New"&gt;&lt;STRONG&gt;WdfCoInstaller: [03/28/2007 00:01.11.203] Update process returned error code :status(C0000005) &amp;lt;no error text&amp;gt;. Possible causes are running fre version of coinstaller on checked version of OS and vice versa&lt;BR&gt;&lt;/STRONG&gt;&lt;BR&gt;WdfCoInstaller: [03/28/2007 00:01.17.875] DIF_INSTALLDEVICE: Pre-Processing&lt;BR&gt;WdfCoInstaller: [03/28/2007 00:01.17.890] ReadComponents:&amp;nbsp; WdfSection for Driver Service hypaudio using KMDF lib version Major 0x1, minor 0x1&lt;BR&gt;WdfCoInstaller: [03/28/2007 00:01.17.953] DIF_INSTALLDEVICE: GetLatestInstalledVersion install version major 0x1, minor 0x1 is less then or equal to latest major 0x1, minor 0x1, asking for post processing&lt;BR&gt;&lt;BR&gt;WdfCoInstaller: [03/28/2007 00:01.18.859] DIF_INSTALLDEVICE: Post-Processing&lt;BR&gt;WdfCoInstaller: [03/28/2007 00:03.19.437] DIF_INSTALLDEVICE: Pre-Processing&lt;BR&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;STRONG&gt;Take a look at the bolded line, here- looks like someone has a serious problem on their hands!&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;C0000005 is the exception code for an access violation [touching non-existent memory].&amp;nbsp; What seems strange (and this issue resurfaces later) is that this is usually accompanied by a popup, or an error report, and not one mention has been made of this.&lt;/P&gt;
&lt;P&gt;The rest of the error message indicates that perhaps we should be more explicit in checking error codes, because the customer was wasting his time pursuing a red herring,&amp;nbsp;so I make that suggestion to the development team.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;Favoring the Direct Approach&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;This gentleman's company apparently has an enviable dynamic with its customers, because they have several who are helping them troubleshoot the problem.&amp;nbsp; Not everyone has such a good relationship, and it made a world of difference here.&lt;/P&gt;
&lt;P&gt;Still, first you try to reproduce the problem right where you can get your hands on it if you can.&amp;nbsp; We know it's KMDF 1.1, and XP SP2 French and German- not much else seems relevant, although we do try more things than I'm going to bore you further with.&amp;nbsp; After a few fruitless attempts on our part to reproduce the problem (not a big surprise, since their engineers have also been unable to reproduce it), I begin to focus on two things:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;What can we do for a workaround? If the end user (and our IHV customer, who remains involved throughout this process) can see progress, then they will have more confidence that we can deliver a solution, and will be more motivated to continue to work with us to solve this problem.&amp;nbsp; Since it looks like we have to debug transcontinentally, it may take a while- lose the engagement, and you may never find out what really happened. 
&lt;LI&gt;How do we find the source of that access violation, when the only cases of it are thousands of miles away, OCA/Watson/WER doesn't seem to be happening, and we don't even share the same language?&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;The first is the more important- it is clear that we at least have clear reproduction of the problem &lt;U&gt;somewhere&lt;/U&gt;, and a workaround will make the IHV's (and by extension our) customers able to enjoy their product as intended, while we work on the second problem.&amp;nbsp; As I mentioned earlier, it will also boost confidence, helping to guarantee we keep the essential players involved.&lt;/P&gt;
&lt;P&gt;So after some of my typically incoherent requests for information, I write a batch file that generates a simple text file that will let us assess the current state of the installation on those machines.&amp;nbsp; It tells me if the files are where they should be, what their vintage is, and also if the registry shows the appropriate services installed, and also that the framework registry support has been properly created.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New"&gt;reg export hklm\System\CurrentControlSet\Services\wdf01000 Service.Prt&lt;BR&gt;reg export hklm\System\CurrentControlSet\Control\wdf Loader.Prt&lt;BR&gt;Dir %windir%\system32\wdf* &amp;gt; CoinstallerFiles.Prt&lt;BR&gt;Dir %windir%\system32\drivers\wdf* &amp;gt; RuntimeFiles.Prt&lt;BR&gt;copy *.prt InstallationStatus.Log&lt;BR&gt;del *.prt&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;EM&gt;Bob's handy-dandy batch file for assessing KMDF installation health in one swell foop.&amp;nbsp; Copy it, run it, and&amp;nbsp;send us&amp;nbsp;InstallationStatus.Log.&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;What we find is that on each machine, the framework's files have been copied to where they belong, but none of the registry entries have been made.&amp;nbsp; This and some reading of the coinstaller's source code provides the insight needed for solving the first priority.&lt;/P&gt;
&lt;P&gt;It is pretty clear now that this is what has happened:&lt;/P&gt;
&lt;P&gt;We provide developers with a coinstaller for KMDF.&amp;nbsp; They include this in their device package and make specific INF changes to invoke it when their device is installed.&lt;/P&gt;
&lt;P&gt;The KMDF coinstaller first checks to see if there is any need to install the version of the KMDF runtime it contains.&amp;nbsp; If it finds that&amp;nbsp;KMDF is not present, or that the version that is present is not as new as the one it contains, then it will try to install its payload.&lt;/P&gt;
&lt;P&gt;To do this, we have an executable hidden in the coinstaller's resources, which&amp;nbsp;is extracted as a temporary file, and then executed.&lt;/P&gt;
&lt;P&gt;Normally, this just works, or else it returns a specific error code related to checked/free mismatches between the coinstaller and the OS.&amp;nbsp; The latter should never happen for a typical end user, because checked OS versions are only provided to software developers, and are not redistributable by them.&lt;/P&gt;
&lt;P&gt;But this time it failed, and then [as often happens with unexpected failures] things got worse.&amp;nbsp; The installation has actually done its work, and all the files needed for the framework are on the machine.&amp;nbsp; But since it failed, we&amp;nbsp;will not complete the process and take the steps needed to make the framework usable.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;Unfortunately, the way&amp;nbsp;the check for&amp;nbsp;prior version installation&amp;nbsp;works is&amp;nbsp;this: we&amp;nbsp;check if the files are where they belong, and&amp;nbsp;if they are, we see&amp;nbsp;what version they are.&amp;nbsp; On these machines, this check tells us that the correct version is present, so all subsequent installations "succeed".&amp;nbsp; But &lt;U&gt;none&lt;/U&gt; of them actually &lt;STRONG&gt;work&lt;/STRONG&gt; (because the steps to make&amp;nbsp;KMDF usable were never taken).&lt;/P&gt;
&lt;P&gt;So I make another "suggestion"- that initial check needs to be strengthened- some malicious soul could just drop a file in the right place on an end user's machine that wasn't using our technology and we could never successfully install on it (for me clearing up an earlier mystery from NTDEV, where a developer trying to troubleshoot an installation issue did this to himself more than once).&lt;/P&gt;
&lt;P&gt;Now it's&amp;nbsp;time for that workaround- the coinstaller's developer has some REG files handy that we can use to complete the installation properly [normally used when working on WinPE].&amp;nbsp; We send these and instructions on how to use them to complete the aborted installation.&amp;nbsp; If they use these, and retry the installation, everything should work.&lt;/P&gt;
&lt;H2&gt;&lt;STRONG&gt;Get out the way...&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;After the usual transcontinental delays, we get back some results. We&amp;nbsp;now know that we have a workaround!&lt;/P&gt;
&lt;P&gt;That should ease some tensions and build confidence for both our direct and indirect customers.&amp;nbsp; After several weeks of frustrating delays, some progress!&lt;/P&gt;
&lt;P&gt;The job isn't over, yet- time now for the second problem- what is causing that access violation?&lt;/P&gt;
&lt;P&gt;This being plenty long for an initial post, I'll save THAT story for the next time around.&lt;/P&gt;
&lt;P&gt;Later...&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=4190917" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/KMDF/default.aspx">KMDF</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/customer+service/default.aspx">customer service</category><category domain="http://blogs.msdn.com/bobkjelgaard/archive/tags/debugging/default.aspx">debugging</category></item></channel></rss>