This project is read-only.
Lets start with a hello world program.Create a file named "helloworld.csx" and add following code

Output("Hello World!");

the above script, can output string "Hello World" to your debugger.

load the extension

.load extcs"

execute the hello world program

!execute -file c:\scripts\helloworld.csx

By default, every c# script executed will have following namespaces/references added .


Also the Script will be running in the context of Debugger Object.

so the above hello world program can be written as

using System;
using ExtCS.Debugger;
var d=Debugger.Current;
d.Output("Hello world!");

every script you write can be thought of as an extension to the Debugger (Debugger.Current) object.So following calls are same

Debugger.Current.Output("Hello world!");
Output("Hello world");

Working with arguments and Script context

arguments should be defined in such way that it should always prefix a hyphen '-'

e.g. !execute -file c:\scripts\showarguments -maxcount 100 -showdml

var d = Debugger.Current;
var scriptContext = d.Context;
//get the arguments
var args = scriptContext.Args;
//get the location of script file
var scriptlocation = scriptContext.ScriptLocation;
var scriptfilepath = scriptContext.ScriptPath;
//checking if an argument is passed
if (args.HasArgument("-maxcount"))
	d.Output(args["-maxcount"]);//getting the argument value passed

above program will output 100. args will contain both -maxcount and -showdml.You can check if an argument is passed or not using HasArgument(), you can directly get the value using args["-maxcount"]

Execute method

Execute can be used to run any command you run in your debuuger.Only different is that u will get the output back as string.

using System;
using ExtCS.Debugger;
var d=Debugger.Current;
var stacktrace= d.Execute("kpn");

stacktrace variable will hold the current threads stacktrace.You are free to parse this text anyway you like :)

debugging support

debugging can be enabled by a simple command !debug . This command will toggle the debugging .

the scripts will emit lot more output to the debugger if on debug mode.

var context=new CLRObject("000007fba91de923");

normally will not emit any information to debugger windows.But on debug mode,it will emit the internals of the what command is called and what operations are happening.

Also only on debug mode,you can attach visual studio do do line by line debugging,You can also put breakpoint on c# script

internally !debug will emit all the infromation passed to function OutputDebugInfo()

this will emit the output to debugger only on debug mode.


we can enable debugging contextually inside the script file. say you only want to enable the debug mode only for part of the script.You can do this

	 var contextObject=new CLRObject(context);
	 var request=contextObject["_request"];
	 d.Context.Debug = true;
	 var response=contextObject["_response"];
	 var items=new Dictionary<string,object>()	 		
	 d.Context.Debug = false;

The above code will only emit debuggin info for accessing response,rawurl and -statusCode. It wil not emit any debugging info for accessing the contentType or request fields of CLR object.

simple script to get the output of !sos.dumpheap -stat

//contents of heapstat.csx
#r "C:\Program Files\Debugging Tools for Windows (x64)\ExtCS.Debugger.dll"
#r "System.Data"
#r "System.Xml"
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using ExtCS.Debugger;
using System.Data;
using System.Xml;
using System.Text;

var d = Debugger.Current;
//load the sos.dll
var sos=new Extension("sos.dll");
//call the command on sos.dll and get tehe output to variable heapstat
var heapstat=sos.Call("!dumpheap -stat");
//output heapstat to debugger

all the above references and namespaces are required if you writing with help of visual studio.Those are required for Visual studio to give intellisense

#r "C:\Program Files\Debugging Tools for Windows (x64)\ExtCS.Debugger.dll" is required for VS reference

How to load an existing debugger extension

have two options:

var d=Debugger.Current;


//this will internally call Require only
var ext=new Extension("psscor4.dll");

Helper Objects available


CLR object is a wrapper around the !dumpobj command text output. using this object,u can easily navigate to any property of the managed object inside the memory

the below code shows how to get a http context object and get the request url

var contextObject = new CLRObject(context);
var rurl = contextObject["_request"]["_rawUrl"].Value;

context is an object address(same as the one you pass to !do command.)
System.Web.HttpContext object has a field request which is of HttpRequest. This object has a field of rawurl which is string object.
contextObject["_request"]["_rawUrl"].Value can read the string from the dump memory directly.

Also CLR object can automatically detect if the field you are reading is value type or not.


Address object can be used to read values from dump virtual memory. You can pass hex address or long to read the value. You cannot use this to read a value of value type.

you can pass a hex address or long to create an address object.

how to use DataTable(the below script displays aspx requests with the error messages(If any happened 404,500)

#r "C:\Program Files\Debugging Tools for Windows (x64)\ExtCS.Debugger.dll"
#r "System.Data"
#r "System.Xml"

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using ExtCS.Debugger;

var d = Debugger.Current;
	Dictionary<string, Dictionary<string, object>> outputData = new Dictionary<string, Dictionary<string, object>>();
var mt = Utilities.GetHttpContextMT();
	var currentContexts = d.Execute("!dumpheap -short -mt " + mt);

DataTable table = new DataTable();

foreach (string context in currentContexts.GetLines())
		var contextObject = new CLRObject(context);

	var rContext = "<b>" + context + "</b>";

	var rurl = contextObject["_request"]["_rawUrl"].Value;
		var errors = contextObject["_errors"];
	object exceptionMessage;
	if (errors.HasValue)

			var items = contextObject["_errors"]["_items"];
			var length = contextObject["_errors"]["_size"].Value;
			string arrayOutput = d.Execute("!da " + items.Address.ToHex());

			//array output shows each item in the array.
			//it starts with 6th line
			string[] lines = arrayOutput.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

			for (int i = 6; i < 7; i++)
				string[] httpException = lines[i].Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

				exceptionMessage = new CLRObject(httpException[1])["_message"].Value;

	table.Rows.Add(rContext, rurl, exceptionMessage);



Last edited Jul 9, 2013 at 12:46 AM by rohithkrajan, version 7


alikucukcc May 19, 2014 at 12:23 PM 

First of all, it is very good idea to combine abilities windbg and c#.

But, it has memory leak.

even simple example consumes lots of memory.


var debuger = Debugger.Current;
var output = debuger.Execute("!dumpheap -stat");
//no printing etc..

and call it many times

.for(r$t0=0; @$t0< 100; r$t0=@$t0+1 ){ !extcs.execute -file C:\scripts\test.csx }