Posts Tagged ‘Windows’

Monad Script to Scrub Perfmon Output

Here's the scenario: I had about eight hours of perfmon output, for several hundred counters sampled once per second. I wanted to put this into a database already containing the parsed IIS logs from the same machine, to try to correlate some of the resource utilization peaks with URL's.

The only snag was that Microsoft's LogParser couldn't handle the CSV files that perfmon generated. The input lines were far too long for it.

The call is from heroism. Will you accept the charges?

The solution I came up with was to hack together an MSH script that processed the files. It's not pretty (because it didn't have to be), but here it is.


#
# trim-perflog.msh
#   This pares down a set of enormous perfmon logs to a
#   size that can be managed by the Microsoft LogParser.
#
#   This finds the column indices that we're interested in,
#   then runs through each line in the input CSV file(s)
#   and pulls them out.
#

# The counters in the perfmon trace that we're interested in.
#
$counters =
"(PDH-CSV 4.0) (Eastern Standard Time)(300)",
"\\machine\.NET CLR Exceptions(w3wp)\# of Exceps Thrown / sec",
"\\machine\.NET CLR LocksAndThreads(w3wp)\Contention Rate / sec",
"\\machine\.NET CLR Memory(w3wp)\% Time in GC",
"\\machine\.NET CLR Remoting(w3wp)\Remote Calls/sec",
"\\machine\Process(w3wp)\Page Faults/sec",
"\\machine\Process(w3wp)\% Processor Time",
"\\machine\Process(w3wp)\% User Time",
"\\machine\Process(w3wp)\% Privileged Time",
"\\machine\Process(w3wp)\Private Bytes";

# Prettier names for the counters.
#
$columnAlias = "time", "exceptionsPerSecond",
"contentionPerSecond", "pctTimeInGC",
"remoteCallsPerSecond", "pageFaultsPerSecond",
"pctProcessorTime", "pctUserTime",
"pctPrivelegedTime", "privateBytes";

# Returns an array that contains the index of each of the
# $counters in the csv.
#
function getPerflogIndices
{
    param([System.String]$columns)

    $tokens = $columns.Split(',');
    for($i = 0; $i -lt $tokens.Length; $i++)
    {
        $t = $tokens[$i];
        $t = $t.Substring(1, $t.Length-2);
        $index = -1 ;
        for($j = 0; $j -lt $counters.Length; $j++)
        {
            if($t -eq $counters[$j])
            {
                $index = $j;
            }
        }
        if($index -ge 0)
        {
            write-object $i;
        }
    }
}

# writes a CSV line using the values in $array.
#
function write-array
{
    param([System.IO.StreamWriter]$writer, $array)
    $j = 0;
    $last = $array.Length;
    foreach($a in $array)
    {
        $writer.Write($a);
        if($j -ne $last)
        {
            $writer.Write(",");
        }
        $j++;
    }
    $writer.WriteLine();
}

# Writes a single line to the result CSV file.
# This requires:
#    $writer  - The output stream.
#    $ln      - A single line read from
#                the input stream.
#    $indices - The column indices of the
#                  subject perfmon counters.
#
function write-csv-line
{
    param([System.IO.StreamWriter]$writer,
       [System.String]$ln, [System.Object[]]$indices)

    $vals = $ln.Split(',');
    $j = 0;
    $last = $indices.Length - 1;
    foreach($i in $indices)
    {
        $writer.Write($vals[$i]);
        if($j -ne $last)
        {
            $writer.Write(",");
        }
        $j++;
    }
    $writer.WriteLine();
}

# Trims down the input CSV file. If $names is True,
# writes the names of the columns as the first line
# in the output.
function trim-perflog
{
    param([System.IO.FileInfo]$in, [System.Boolean]$names)

    $r = $in.OpenText();
    $ln = $r.ReadLine();
    $indices = getPerfLogIndices $ln;

    $wr = [System.IO.File]::AppendText($out);
    if($names)
    {
        write-array $wr $columnAlias;
    }
    while($r.Peek() -ge 0)
    {
        write-csv-line $wr $r.ReadLine() $indices;
    }
    $wr.Close();
}

$out = "c:\perflogs\output.csv";

trim-perflog c:\perflogs\prod_000005.csv True
trim-perflog c:\perflogs\prod_000006.csv False
trim-perflog c:\perflogs\prod_000007.csv False

The Debugger Extension, Part 6 - Scanning Threads

The Debugger Extension

We already have an extension that might be pretty useful in some scenarios, but another common situation is determining what a particular thread is doing. You might want to look at instances of a particular type on the stack of a thread that is maxing out your CPU, or you might want to look at two or more threads that appear to be deadlocked.

We can get something like this out of the extension we have written already if we alter it to search only the stack for the current thread. How do we do that? On an x86 machine, the stack looks something like this:

Thread Stack

Finding one end of the stack region is very easy. The top of the stack (but the "bottom" address, since the stack grows down) should always be in the ESP register. To get the base of the stack we need to be able to read an NT structure called the Thread Environment Block, or TEB.

The TEB is defined as follows in the Platform SDK.

typedef struct _TEB {
    BYTE Reserved1[1952];
    PVOID Reserved2[412];
    PVOID TlsSlots[64];
    BYTE Reserved3[8];
    PVOID Reserved4[26];
    PVOID ReservedForOle;
    PVOID Reserved5[4];
    PVOID TlsExpansionSlots;
} TEB, *PTEB;

We're all ecstatic that the TEB is undocumented when this allows the kernel team to freely implement new features, I guess, but this is no help to us right now. This is closer to what the TEB header really looks like.

typedef struct tagTEB_INTERNAL
{
    DWORD dwExceptionList;
    DWORD dwStackBase;
    DWORD dwStackLimit;
    DWORD lpTIB;
    DWORD lpFiberInfo;
    DWORD lpUserPointer;
    DWORD lpSelf;
    DWORD lpEnvironmentPointer;
    DWORD dwProcessId;
    DWORD dwThreadId;
    DWORD dwActiveRPCHandle;
    DWORD lpPEB;
    DWORD dwLastError;
    // More fields follow but are not included here.
} TEB_INTERNAL, *PTEB_INTERNAL;

I took that from chapter six of Microsoft Windows Internals by Mark Russinovich. He's done many useful and awe-inspiring things besides discovering the Sony Rootkit DRM. The DbgEng SDK exposes a method to us (IDebugSystemObjects::GetCurrentThreadTeb) that makes it trivial to write a function to read in this structure in the debugger (download the source if you want to see it).

We can now write a templated search function (much like those we wrote in part four) to search only the current stack. Since the stack will contain handles/pointers to the objects, we'll also need a function that searches with a level of indirection.

// Performs a range search on the current
// thread's stack.
//
template<class search_command>
inline void SearchStack(ULONG64 pattern)
{
    TEB_INTERNAL teb = {0};
    HRESULT hr = GetCurrentTEB(&teb);
    if( FAILED(hr) )
    {
        Out("Could not retrieve the TEB.\n");
        return;
    }

    ULONG64 esp = 0;
    hr = m_Registers->GetStackOffset(&esp);
    if( FAILED(hr) )
    {
        Out("Could not read the stack pointer.\n");
        return;
    }
    Out("Thread %d:\n", teb.dwThreadId);

    // Thunk the dword to a 64-bit integer.
    // Otherwise we'll take the previous dword
    // field in the TEB structure with us into
    // the Search call.
    ULARGE_INTEGER li = { teb.dwStackBase, 0L };
    this->SearchPointers<search_command>(
         pattern,
         esp,
         li.QuadPart);
}

// Searches for the pattern with a level
// of indirection.
//
template<class search_command>
inline void SearchPointers(ULONG64 pattern,
     ULONG64 start, ULONG64 end)
{
    search_command sc;
    int hits = 0;
    for(ULONG64 offs = start;
        offs <= end;
        offs += m_PtrSize)
    {
        ULONG64 ptr = 0;
        HRESULT hr = m_Data->ReadPointersVirtual(
            1L, offs, &ptr);
        ULONG64 ptrVal = 0;
        hr = m_Data->ReadPointersVirtual(
            1L, ptr, &ptrVal);
        if( hr == S_OK && ptrVal == pattern )
        {
            if( sc.HandleMatch(ptr) )
            {
                ++hits;
            }
        }
    }
    sc.ShowResults(hits);
}

The EngExtCpp framework makes it very easy to add a switch to enable searching with this method:

0:000> !atstat /?
!atstat [/s] <The MethodTable for SampleApp.ArbitraryType.>
  <The MethodTable for SampleApp.ArbitraryType.>
  /s - Searches only the current stack.
Displays statistics about ArbitraryType instances in memory.

That lets us build some cool composite commands in WinDbg like this:

0:000> ~*e!atstat /s 009131b0
Thread 2624:
Searching for ArbitraryTypes...
--------------------------------------------
01272bf8 : Purple
01272bf8 : Purple
01272bdc : Blue
01272bf8 : Purple
--------------------------------------------
Found 4 total instances.
Totals:
  Blue: 1
  Purple: 3

Thread 1924:
Searching for ArbitraryTypes...
--------------------------------------------
--------------------------------------------
Found 0 total instances.
Totals:

Thread 2096:
Searching for ArbitraryTypes...
--------------------------------------------
--------------------------------------------
Found 0 total instances.
Totals:

I think that's where we'll leave it for now. Not bad for a day of work or so, when you consider that we're empowered to crank out similar utilities in no time at all. I hope you've enjoyed the debugger extension series.

The Debugger Extension, Part 5 - Manipulating Managed Types

The Debugger Extension

In the last post in this series, we succeeded in writing a working extension that searched memory for instances of a particular type. Trouble is, we haven't done anything useful yet. We've merely duplicated a very small subset of the functionality offered by SOS's !DumpHeap command, and poorly at that.

In the problem setup, we said we wanted to show statistics about a particular property of these instances–for the purposes of this example, we're calling that their "Color." A sensible step in this direction would be to write some utility C++ code to accompany the Colors enumeration that we wrote earlier in C#.

// Some definitions that correspond to the managed
// SampleApp.Colors enum.
typedef ULONG Color;
const Color COLOR_RED = 0;
const Color COLOR_GREEN = 1;
const Color COLOR_BLUE = 2;
const Color COLOR_PURPLE = 3;
const Color MAX_COLOR = COLOR_PURPLE;

PCSTR g_szColorNames[] = { "Red", "Green",
    "Blue", "Purple" };

bool IsColor(Color c)
{
    if( c <= MAX_COLOR )
    {
        return true;
    }
    return false;
}

PCSTR ColorName(Color c)
{
    if( !IsColor(c) )
    {
        return NULL;
    }
    return g_szColorNames[static_cast<int>(c)];
}

Part of the point of this series has been to develop a framework that deals with instances of .NET objects. To that end, we should try to write a generic base class that loads a managed instance in the debuggee into the debugger's process. This is my implementation of such a class.

// ------------------------------------------------------
// mtypes.h
//        Some base classes for dealing with instances
//        of managed objects.
//
#pragma once

template<class object_fields>
class ManagedInstance
{
protected:
    object_fields m_Fields;
    ULONG64 m_offset;
    bool m_valid;

    // Can be used by derived classes can to refer
    // to this class.
    typedef ManagedInstance<object_fields> base_t;

    // Constructor - pass the offset of the managed
    // object. Check the result of IsValid() before
    // using an instance derived from this class.
    ManagedInstance(ULONG64 offset) : m_Fields()
    {
        // Load the data for the fields from the
        // debugee process / memory dump
        IDebugDataSpaces* pData = g_Ext->m_Data;
        m_offset = offset;
        ULONG read = 0L;
        HRESULT hr = pData->ReadVirtual(
            m_offset,
            reinterpret_cast<void*>(&m_Fields),
            sizeof(object_fields),
            &read);
        m_valid = SUCCEEDED(hr) &&
            (read == sizeof(object_fields));
    }

    virtual ~ManagedInstance() {}

public:
    // Returns true if the object was successfully
    // read from the debugee. Doesn't validate that
    // it actually is a managed object of the desired
    // type, but overridden implementations should
    // do this.
    virtual bool IsValid() { return m_valid; }
};

// This can be used as a base class for classes used
// as the object_fields template parameter.
class ObjectFields
{
public:
    ULONG pMethodTable;
};

The template parameter for the ManagedInstance class takes a POD ("plain old data") type that should just list the fields in the instance. The constructor for ManagedInstance loads the data at the specified offset as those fields. I declared a virtual function that indicates whether or not the managed instance is valid. In this base class, all we can really say about that is whether or not we could read the data at the provided address.

I've also defined a base class for the fields of a managed object, and put the MethodTable address in it. Given these classes, it's not a lot of work to write the implementations for ArbitraryType.

// Represents the fields of a
// SampleApp.ArbitraryType instance.
class ArbitraryTypeFields
     : public ObjectFields
{
public:
    Color col;
    ULONG id;
};

// Represents a single ArbitraryType instance.
class ArbitraryType :
    public ManagedInstance<ArbitraryTypeFields>
{
public:
    ArbitraryType(ULONG64 offset)
        : base_t(offset) {}
    virtual bool IsValid();
    Color GetColor() { return m_Fields.col; }
};

// Returns true if the loaded data is a valid
// ArbitraryType instance.
bool ArbitraryType::IsValid()
{
    if( base_t::IsValid() &&
        IsColor(m_Fields.col) )
    {
        return true;
    }
    return false;
}

In the last post, the only criteria we used for finding ArbitraryType instances was that we had found a INT_PTR containing the address of its MethodTable. That's obviously going to result in false positives, because the CLR's execution engine will certainly have this pointer in several places in its own internal data structures. We can do a little better now by making sure that the Color field is within the range of expected values. While we're changing our HandleMatch function to implement this, we'll add an STL map to the mix to keep track of the colors we find.

class AtStatCmd : public SearchCommand
{
protected:
    typedef map<Color, int>  CountMap_t;
    CountMap_t m_counts;

public:
    virtual void ShowResults(int totalHits);
    virtual bool HandleMatch(ULONG64 offset);
    AtStatCmd();
};

bool AtStatCmd::HandleMatch(ULONG64 offset)
{
    ArbitraryType at(offset);
    if( at.IsValid() )
    {
        Color c = at.GetColor();
        g_Ext->Out("%08I64x : %s\n",
           offset, ColorName(c));
        m_counts[c]++;
        return true;
    }
    return false;
}

The output of the extension in WinDbg now looks like this:

    0:000> !atstat 009131b0
    Searching for ArbitraryTypes...
    --------------------------------------------
    Searching 00000000 to 7fffffff.
    009100cc : Red
    009130e0 : Red
    01271ce4 : Red
    01271d00 : Blue
    01271d1c : Red
    01271d38 : Blue
    01271d54 : Red
    --------------------------------------------
    Found 7 total instances.
    Totals:
      Red: 5
      Blue: 2

Incidentally, this is debugging the same sample code that, in the previous post, was declared to have 20 instances in memory. As you can see, adding some basic validation reduced the number of bogus hits considerably. A more complex object–one you might actually use, I suppose–could have an even smaller incidence of errors.

There's one obvious problem with this that I can think of, and that is the fact these objects are not necessarily alive (rooted) on the GC heap. They could very well be collected and sitting in freed memory. In my case, this is not a concern since I am interested mostly in debugging leaked memory. This may be an issue for other users, however.

Since the extension we set out to build is basically complete, I'll post the code now even though I have one more feature in mind for the next post. You can download the code here.

My Tentative Approval of Visual Studio 2005

Despite some initial bad press, my impression so far is that Visual Studio 2005 is a pretty nice product. I would qualify that by saying that I haven't yet used it to work on a massive web project, and as we all know web projects were definitely Visual Studio 2003 at its worst. (After two years, I will NOT use Visual Studio 2003 for web projects. I refuse. They were broken. I'm 100% text editor and NAnt from the command line now.)

I am loathe to be seen as a cheerleader, and rest assured I could point to many things about Visual Studio in general and VS2005 specifically that I can't stand. But somebody out there deserves some credit for the fact that startup performance seems to have been drastically improved. In my informal test ("One Mississippi .. two Mississippi"), VS 2005 outperforms 2003's startup by an order of magnitude. Two seconds compared to thirty seconds on the same machine. That's certainly nothing to sneeze at.

You click on the icon, it opens. All software should work this way. I'm looking directly at you, OpenOffice, Trillian, and every single product developed by Adobe. While I'm on the subject, never allowing your program to close is not an acceptable solution to this problem.

I am also a fan of this:

The "close all but this" button replaces these steps:

  1. Ctrl+Shift+S
  2. Ctrl+F4, hold for five seconds
  3. Find the original file and reopen it

The Debugger Extension, Part 4 - Searching Memory

The Debugger Extension

Now that we know how to solve our problem conceptually, we can put pen to paper. Metaphorically speaking, I suppose. As I said in the last post, our strategy will be to search memory for INT_PTRs matching the MethodTable for our ArbitraryType. When we find matches, we'll perform some further validation to reduce the likelihood of false positives.

It's not unreasonable to assume that if we're successful in writing an extension to look at this class, we might want to do something like it again in the future. So let's define an interface for commands that search through memory.

// ------------------------------------------------------
// SearchCommand.h
//        Defines the interface for extension commands
//        that search through memory.
//
#pragma once

class SearchCommand
{
public:
    // Called whenever the search pattern is encountered
    // at the provided offset. The method should return
    // true if the offset is a hit.
    virtual bool HandleMatch(ULONG64 offset)=0;

    // Called when the search is finished. The parameter
    // will contain the total number of matches found.
    virtual void ShowResults(int totalHits)=0;
};

This should give us some flexibility later on if we need it. We can also abstract the process of searching through memory. The DbgEng API that is available to us is the IDebugDataSpaces interface. This defines a SearchVirtual function, which we'll use to scan for the ArbitraryType's MethodTable. This is its definition.

HRESULT
  IDebugDataSpaces::SearchVirtual(
    IN ULONG64  Offset
    IN ULONG64  Length
    IN PVOID  Pattern
    IN ULONG  PatternSize
    IN ULONG  PatternGranularity
    OUT PULONG64  MatchOffset
    );

To make our algorithm generic, we'll add a templated function to our extension class.

// ------------------------------------------------------
// dmext.h
//
#pragma once
#include "engextcpp.hpp"
#include "searchcommand.h"

class EXT_CLASS : public ExtExtension
{
protected:

   // Does a range search for the pattern, keeps track of the hits, and
   // calls methods matching the SearchCommand interface on an instance
   // of the search_command parameter.
   //
   template<class search_command>
   inline void Search(ULONG64 pattern, ULONG64 start, ULONG64 end)
   {
      if( start > end )
      {
         Err("The start cannot be after the end.\n");
         return;
      }

      search_command sc;
      Out("Searching %08I64x to %08I64x.\n", start, end);

      HRESULT hr = 0;
      int hits = 0;
      ULONG64 offs = start;
      do
      {
         hr = m_Data->SearchVirtual(offs,
            end - offs,
            &pattern,
            this->m_PtrSize,
            1,
            &offs);
         if( hr == S_OK )
         {
            if( sc.HandleMatch(offs) )
            {
               ++hits;
            }

            // Search again, starting at the the next
            // pointer-sized location.
            offs += m_PtrSize;
         }
       }
       while( hr == S_OK );
       sc.ShowResults(hits);
    }

    // Shortcut for an x86 without the /3GB switch.
    template<class search_command>
    inline void Search(ULONG64 pattern)
    {
       this->Search<search_command>(pattern, 0, 0x7fffffff);
    }

 public:
    EXT_CLASS();
    EXT_COMMAND_METHOD(atstat);
};

I also added a shortcut function that searches all of the virtual memory that is available to user mode. This function assumes that we're debugging on an Intel x86 machine, and that the process is not LARGEADDRESSAWARE–that is to say, it can't make use of more that 2 gigabytes of virtual memory.

(A brief aside: although I'm using ULONG64 addresses and other conventions, I'm making no sincere attempt to ensure that this extension will work properly with a 64-bit debuggee. That much should be obvious from my last shortcut. Where I can, I will try to make life easy for someone writing a port.)

We now have enough framework to implement the skeleton of our extension command. For now, we'll just spit out addresses when we think we have a match.

// ------------------------------------------------------
// atstat.cpp
//
#include "stdafx.h"
#include "dmext.h"

class AtStatCmd : public SearchCommand
{
public:
    virtual void ShowResults(int totalHits);
    virtual bool HandleMatch(ULONG64 offset);
    AtStatCmd();
};

AtStatCmd::AtStatCmd()
{
    g_Ext->Out("Searching for ArbitraryTypes...\n");
    g_Ext->Out("--------------------------------------------\n");
}

bool AtStatCmd::HandleMatch(ULONG64 offset)
{
    g_Ext->Out("%08I64x\n", offset);
    return true;
}

void AtStatCmd::ShowResults(int totalHits)
{
    g_Ext->Out("--------------------------------------------\n");
    g_Ext->Out("Found %d total instances.\n\n", totalHits);
}

EXT_COMMAND(atstat,
   "Displays statistics about ArbitraryType instances in memory.",
   "{;e;The MethodTable for SampleApp.ArbitraryType.}")
{
    ULONG64 mt = this->GetUnnamedArgU64(0);
    this->Search<AtStatCmd>(mt);
}

The !atstat command is defined using the EngExtCpp framework's macro; this will automatically parse any parameters and provide debugger help. Look in the engextcpp.hpp header for the definition of this macro–I'm not even going to try to explain it here. As you can see, I've simplified matters by assuming that we can just retrieve the MethodTable for our type by some other means and provide it to the extension.

Here's some output of what we have finished so far:

0:000> .load C:\src\samples\dmext\dmext\objfre_wnet_x86\i386\dmext ;
0:000> .load C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\SOS
0:000> !name2ee sampleapp!SampleApp.ArbitraryType
Module: 00912c14 (SampleApp.exe)
Token: 0x02000003
MethodTable: 009131b0
EEClass: 00911410
Name: SampleApp.ArbitraryType

0:000> !atstat 00912c14
Searching for ArbitraryTypes...
--------------------------------------------
Searching 00000000 to 7fffffff.
0012f560
0012f72c
00167628
0016832c
001685f4
0016860c
00168624
0016abec
0016ae28
009101c0
009101e8
009111f8
00911268
009112d0
00911414
00911478
00913058
00913118
009131c4
00c316b8
--------------------------------------------
Found 20 total instances.

In the next post, we'll work on trimming down false positives and accomplishing what we set out to do: showing statistics about the "colors" of the ArbitraryTypes.

Using WinDbg to Log Exceptions, Part III

Part I

Part II

In my original post, I left you with the assignment of modifying this command to create a series of dump files instead of overwriting the same one repeatedly.

0:003> bp kernel32!RaiseException ".dump /ma /o c:\\temp\\myapp.dmp; g"
breakpoint 0 redefined

Well, this is going to be a short post because shortly after writing that I realized there was a much easier way to do this than what I had in mind.

The /u switch for the .dump command appends a timestamp and the PID to the filename.

0:003> bp kernel32!RaiseException ".dump /ma /u c:\\temp\\myapp.dmp; g"
breakpoint 0 redefined

An effective way to fill up the hard drive on a production machine, if I do say so myself.

Using WinDbg to Log Exceptions, Part II

In my last post, I asked you to explain how to derive this command:

0:000> bp mscorwks!JIT_Throw "du poi(@ecx+10)+c; !clrstack; g"

The purpose of which is to print out the exception text when a CLR exception occurs.

Finding the Function

The first question here might be, how did I know to break on this function? This is the easiest part to get. If we break on kernel32!RaiseException and examine the unmanaged stack, we can see that this is the first function called from managed code when an exception is thrown.

0:000> k
ChildEBP RetAddr
0012f5a8 79238b7d KERNEL32!RaiseException
0012f600 792f0d05 mscorwks!RaiseTheException+0xa0
0012f66c 02e000a0 mscorwks!JIT_Throw+0x4d
WARNING: Frame IP not in any known module. Following frames may be wrong.
0012f69c 791d94bc 0x2e000a0
0012f6a4 791ed194 mscorwks!CallDescrWorker+0x30
…

I have one important note about the JIT_Throw function. I’ve shown it here in the mscorwks module. This is the workstation CLR. If you are working on a server application, you should change all references to that to mscosvr, which is the server version of the CLR.

The more interesting part, of course, is how I figured out how to use du poi(@ecx+10)+c to print out the exception text.

Finding the Exception

If we actually break on JIT_Throw, we can locate the address of the current managed exception using the DumpStackObjects command in the SOS extension.

0:000> !dso
Thread 0
ESP/REG    Object     Name
ecx        0x00aaabfc System.Exception
0x0012f680 0x00aaabfc System.Exception
0x0012f688 0x00aaab6c System.Object[]
…

Notice that !dso gives us an additional piece of information: at the start of this call to the JIT_Throw function, the address of the current exception is in the ECX register. Can we rely on that to be true in every case? It turns out that we can, and I think it is instructive to explain why this is so.

Some of you will already know why ECX is special here, and if we take a look at the prologue of this function in assembly it might confirm your suspicions.

mscorwks!JIT_Throw:
792f0cb8 55               push    ebp
792f0cb9 8bec             mov     ebp,esp
792f0cbb 83ec58           sub     esp,0x58
792f0cbe 56               push    esi
792f0cbf 8bf1             mov     esi,ecx

The last two instructions are a common sight when working with functions declared with the __fastcall calling convention. This convention places the first two arguments to the function in the ECX and EDX registers.

For the sake of completeness I should say that you will also see the same kind of prologue if a C++ member function is being called (__thiscall). However, we know that this is not the case here.

Taking a quick look at the assembly here would be enough proof, but we can confirm that __fastcall is actually being used by reading the comments in fcall.h in the SSCLI, and then looking up the definition of JIT_Throw in jitinterface.cpp.

To summarize, as long as we are running on an x86 machine, we can always grab a pointer to the current exception at this breakpoint from the ECX register.

The Home Stretch (Finding the Exception Text)

Now that we can locate the managed Exception, we can take a stab at finding the text to go along with it. Take a look at the output when we dump the Exception object (using the DumpObject command in SOS):

0:000> !do @ecx
Name: System.Exception
MethodTable 0x79b947ac
EEClass 0x79b94850
Size 64(0x40) bytes
GC Generation: 0
mdToken: 0x02000012  (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79b948b4
    MT      Field     Offset          Type   Attr     Value       Name
0x79b947ac 0x400001d     0x4         CLASS   instance 0x00000000  _className
0x79b947ac 0x400001e     0x8         CLASS   instance 0x00000000  _exceptionMethod
0x79b947ac 0x400001f     0xc         CLASS   instance 0x00000000  _exceptionMethodString
0x79b947ac 0x4000020    0x10         CLASS   instance 0x00aaab7c  _message
0x79b947ac 0x4000021    0x14         CLASS   instance 0x00000000  _innerException
0x79b947ac 0x4000022    0x18         CLASS   instance 0x00000000  _helpURL
0x79b947ac 0x4000023    0x1c         CLASS   instance 0x00000000  _stackTrace
0x79b947ac 0x4000024    0x20         CLASS   instance 0x00000000  _stackTraceString
0x79b947ac 0x4000025    0x24         CLASS   instance 0x00000000  _remoteStackTraceString
0x79b947ac 0x4000026    0x2c  System.Int32   instance 0           _remoteStackIndex
0x79b947ac 0x4000027    0x30  System.Int32   instance -2146233088 _HResult
0x79b947ac 0x4000028    0x28         CLASS   instance 0x00000000  _source
0x79b947ac 0x4000029    0x34  System.Int32   instance 0           _xptrs
0x79b947ac 0x400002a    0x38  System.Int32   instance -532459699  _xcode
-----------------
Exception 00aaabfc in MT 79b947ac: System.Exception
_message: You stink!

The third column, Offset, is what is important to us right now. This tells us the address of each field relative to the base address of the object. If we want the System.String object instance for the _message field, we can refer to that like this:

0:000> ? poi(@ecx+10)
Evaluate expression: 11185020 = 00aaab7c

(The poi keyword in this expression returns a pointer-sized variable at the specified address. It is the same as “*(pException+0x10)” would be in C or C++).

We can use the same kind of procedure on the String instance to get the actual characters.

0:000> !do poi(@ecx+10)
Name: System.String
…
FieldDesc*: 0x79b92978
     MT      Field     Offset                 Type       Attr  Value  Name
0x79b925c8 0x4000013      0x4         System.Int32   instance     11  m_arrayLength
0x79b925c8 0x4000014      0x8         System.Int32   instance     10  m_stringLength
0x79b925c8 0x4000015      0xc          System.Char   instance   0x59  m_firstChar
…

The first character in the string is at 0xC relative to the base of the object. We know that the CLR uses Unicode to represent strings internally, so we can use the du command (display memory, Unicode) to print it out.

0:000> du poi(@ecx+10)+c
00aaab88  "You stink!"

Conclusion

Well, there you have it. With a little elbow grease, WinDbg is a tremendously powerful tool. I hope you’ve found this particular odyssey entertaining.

A Word for OllyDbg

OllyDbg is a very nice tool for debugging other people’s code. While I definitely still prefer WinDbg in most situations, OllyDbg is great for stepping through assembly.

OllyDbg

I had a good reason to use it last week. I have an old VB6 application that needs to interop with new .NET applications. The VB6 code is using an ancient COM library for encryption; this library is fairly opaque in regards to what it is actually doing.

Without giving away too many details, there’s no way I can move the old code to over to anything else. I wish the original author had just imported the advapi32 Crypt* functions, but it’s too late for that now.

So, needing to decrypt data coming from the VB6 side, I was left with a few choices. I could just use COM Interop and reference the old library in my new code. But I wasn’t really happy with that, mostly because of the complexity that it adds to deployment.

I was familiar enough with the Crypto API to know that the COM library couldn’t be doing anything too complicated. This is where OllyDbg comes in.

I stepped through the library call in assembly, stopping when it made Crypt* calls. I got the parameters from the stack, and wrote them all down.

From there, I wrote a quick C++ console app to test out recreating the calls and decrypting some sample data. As it turned out, the specific algorithms that the COM library was using weren’t exposed in System.Security.Cryptography, so the C# version I ended up with had to use P/Invoke with advapi32.

But anyway, I got rid of an annoying dependency. A very satisfying hack. You can read about an even better one here—Lee Holmes uses OllyDbg to crack a program to run as a non-admin.

DivX Sux

Look –

I am an end user of DivX. I could not possibly care less about how great the DivX codec is. To be honest, my discerning eye cannot tell the difference between a DivX-encoded movie and an animated GIF. I do not encode my own movies.

So given all of that, explain to me why in the hell I would want this notification icon.

The DivX notification icon makes me want to die

Even if you MUST create a notification icon, I still expect it to hide correctly. Instead, for some reason, it shows and hides itself about once a second while I am watching, say, a Channel 9 video.

This resizes everything on my taskbar. It is absurdly distracting, and makes it more difficult to concentrate on the video. If for no other reason, this makes DivX automatically the worst possible codec with which to record a movie.

DivX, you are not the coolest most amazing program ever written in the history of mankind. You are a stupid video format and you should operate behind the scenes where you belong.

A pox on you and your family.

Visual C++ 6.0 Crashing on Startup

If you still need to occasionally use Visual C++ 6.0 (as I do), this advice is for you.

If the IDE starts crashing on you on startup, rename or delete this registry key:

HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Layout

That might fix it.

It took me forever to figure that out.