Getting started with NetExt

 

DISCLAIMER: NetExt is a free and open source WinDBG application that makes .NET debugging much easier as compared to the current options: sos or psscor. This extension is not a Microsoft product and limited support is provided only via its codeplex page. For now I am the only architect/developer, so you may experience delays in my responses.

Installing NetExt

I had released the WinDBG extension NetExt back in 2013 and recalled it soon after in order to port to use another .NET Debugging API. The bad part is that it is not pure (and standalone) C++ as it used to be. The good part is that it is much easier to add new features with this new API.

If you are new to WinDBG you first have to download the WinDBG version compatible with your operating system. For .NET you need to use WinDBG 32-bits to debug a 32-bits dump file (or process) and WinDBG 64-bits their 64-bits counterparts. To download the installer for both version go here: https://msdn.microsoft.com/en-us/library/windows/hardware/ff551063(v=vs.85).aspx

The installation is via WDK or SDK. I suggest the SDK installation. During the installation you can select only the debugging tools if you are not interested in the full SDK. To do this unselect all but Debugging Tools for Windows when you get in the “Select the features you want to install” in the install wizard:

image

 

If you install the SDK for Windows 8.1, your installation folders will be C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64 and  C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x86 for the 32-bits and 64-bits versions respectively.

After WinDBG is installed, you download NetExt here: http://netext.codeplex.com/. At the time of this writing the current version is 2.0.1.5000. Unzip the file you downloaded. Copy all content of the x64 folder to your WinDBG 64-bits installation folder (e.g: C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x64). Copy all content of the x86 folder to the 32-bits installation of WinDBG (e.g. C:\Program Files (x86)\Windows Kits\8.1\Debuggers\x86). IMPORTANT: you may be required to provide administrator credentials. Normally you should be able to chose any folder for the extension but a bug I thought I had resolved requires that at least Microsoft.Diagnostics.Runtime.dll is located at WinDBG root folder.

Debugging requires symbol files. As there is some delay in downloading symbols it is a good idea to have a symbol cache locally. As I spend most of my days debugging, I always create a symbol folder c:\symbols and I add the symbol path environment variable to set the symbol location (see more here: https://support.microsoft.com/KB/311503).

So, if you wish to follow my recommendation go to My Computer (or from Windows Explorer, right-click on “This PC”) | Properties | Advanced System Settings | Advanced | Environment Variable. Add this user variable (you have to have created the folder c:\symbols first):

image

Variable Name: _NT_SYMBOL_PATH

Variable Value: SRV*c:\symbols*http://msdl.microsoft.com/download/symbols

Loading NetExt in WinDBG

Depending on the target process or dump file bitness, open WinDBG 32 or 64-bits version. If you have no dump file to play with, you can download some along with the documentation here: https://netext.codeplex.com/documentation

Having the extension in the right place, open the dump file (or attach to a .NET process). Run this command:

.load netext

image

To verify if you have the most up to date version, please run:

!wver

It will show you the .NET version loaded in the process (or dump) and the current extension version.

image

Checking all types in .NET heap

If you are new to the extension or to the type of process of dump you loaded, you may run this command to create a tree of the types in the heap:

!windex -tree

If you receive an error it is because you do not have the appropriate symbols or the bitness of WinDBG and the process (or dump) are not matching. If this is the case run .cordll –l to see why it is unable to load the .NET DAC.

If the command succeed then it will index the heap (which is necessary for all advanced commands) and it will also create a tree visualization file of all the types. When it finishes it will show you the command you have to use to see the tree. The file name will be different every time you run this command:

image

 

Copy and paste the command. It will pop up a new windows with all types. If you double click a type it will show a list of all objects of the type. If you expand a type and double click a field, it will show the value of the field for all objects of this type in memory:

image

 

Some cool stuff

You can check all currently running http requests in a web application with this command:

!whttp -running

image

If you click on one of the addresses you will see the details of the particular request. Below is a listing showing a SOAP request (including the SOAP body):

image

For SOAP messages you also have the chance to show it XML-formatted or in tree style. The options are shown at the end of the command. The server variables are also shown when present so you can see the user making the request for example.

The extension also leverage a SQL-like command (and custom interpreter) to show heap object details based on a conditional and with several formatting options. The command is !wfrom. The command below will dump all HttpContext objects in the same format yielded by !whttp:

!wfrom -nospace -nofield -type *.HttpContext select $rpad($addr(),10)," ",$if(!_thread, " --",$lpad($thread(_thread.DONT_USE_InternalThread),4))," ",$if((_timeoutSet==1),$tickstotimespan(_timeout._ticks), "Not set "), " ", $if(_response._completed || _finishPipelineRequestCalled,"Finished", $tickstotimespan($now()-_utcTimestamp.dateData)), " ", $replace($lpad(_response._statusCode,8),"0n","")," ", $rpad($isnull(_request._httpMethod,"NA"),8), " ", $isnull(_request._url.m_String, _request._filePath._virtualPath)

image

Don’t let this huge query frighten you. You will learn with experience. This is a more typical query without much complexity as the one above showing only requests that are not returning 200, Please note that the default base for numbers is hexadecimal, so to use decimal you must prefix it with 0n like we are doing with the 0n200 for the status:

!wfrom -type *.HttpContext where (_response._statusCode != 0n200) select _request._url.m_String, _response._statusCode, _response._statusDescription

image

 

Moving forward

The best way to get detailed help is via command !whelp. For a more wiki like experience use the command below:

.browse !whelp

It will open a new window containing the hyper-linked help.

image

I strongly recommend you do the guided training: https://netext.codeplex.com/documentation

If you are novice or a hardcore debugger, you will only get going after the training.