Debugging .Net Framework 4.0 without source code using windbg


In this post I am going to be discussing about debugging .Net Framework 4.0  using windbg . I am going to demonstrating how to have a break-point within a method, but without the framework source code. This would help in debugging .NET framework when you don’t have VS in a production environment and the same technique can be used to debug other third party assemblies where you don’t have the source code.  This is kind of like .NET Reflector where you can step through third party assemblies, but without any cost. It is not going to be as convenient as the professional version of Reflector.

I am going to be using the same example that I used to debug .NET Framework source 3.5 using windbg.

FYI the .NET framework 4.0 has private symbols available on MS symbol server, but the source code is still not available. To debug .NET framework source code it is important to have correct symbol path and here is my symbol path in the _NT_SYMBOL_PATH environment variable.


SRV*d:\dev\symbols*http://referencesource.microsoft.com/symbols; SRV*d:\dev\symbols*http://msdl.microsoft.com/download/symbols

Here is the sample source code that I am going to be using to demonstrate framework debugging


using System;
 using System.Net;
 namespace Test
 {
 class Program
 {
 static void Main(string[] args)
 {
 Console.WriteLine("Hello World of debugging");
 var wr = WebRequest.Create("http://www.google.com");
 Console.WriteLine("Web request created");
 var req = wr.GetRequestStream();
 Console.WriteLine("Hello World Debugging");
 Console.Read();
 }
 }
 }
 

Launched the exe within the debugger

Then issued the command to notify when the clrjit is loaded,


sxe ld:clrjit

This is because, to load sos and sosex after the framework is loaded.Then issued the following commands to load sos, sosex and to set break-point on WebRequest.Create


.loadby sos mscorwks
.load sosex
!mbm System.Net.WebRequest.Create

And when the break-point hits the first time, let it continue by using the g command. It would break into the debugger for other overloaded method for WebRequest.Create and here is the call-stack

0:000> !mk
Thread 0:
ESP              EIP
00:M 000000000023ece0 000007fef6ea5a44 System.Net.WebRequest.Create(System.Uri, Boolean)(+0x0 IL)(+0x14 Native) [f:\dd\ndp\fx\src\Net\System\Net\WebRequest.cs, @ 93,13]
01:M 000000000023ed60 000007ff00140176 Test.Program.Main(System.String[])(+0xc IL)(+0x56 Native)
02:U 000000000023edc0 000007fef8b210b4 clr!CallDescrWorker+0x84
03:U 000000000023ee10 000007fef8b211c9 clr!CallDescrWorkerWithHandler+0xa9
04:U 000000000023ee90 000007fef8b21245 clr!MethodDesc::CallDescr+0x2a1
05:U 000000000023f0c0 000007fef8c21675 clr!ClassLoader::RunMain+0x228
06:U 000000000023f310 000007fef8c217ac clr!Assembly::ExecuteMainMethod+0xac
07:U 000000000023f5c0 000007fef8c21562 clr!SystemDomain::ExecuteMainMethod+0x452
08:U 000000000023fb70 000007fef8c23dd6 clr!ExecuteEXE+0x43
09:U 000000000023fbd0 000007fef8c23cf3 clr!CorExeMainInternal+0xc4
0a:U 000000000023fc40 000007fef8ca7365 clr!CorExeMain+0x15
0b:U 000000000023fc80 000007fef9493309 mscoreei!CorExeMain+0x41
0c:U 000000000023fcb0 000007fef9525b21 MSCOREE!CorExeMain_Exported+0x57
0d:U 000000000023fce0 00000000776cf56d KERNEL32!BaseThreadInitThunk+0xd
0e:U 000000000023fd10 0000000077903281 ntdll!RtlUserThreadStart+0x1d

And here is the source code for this method using reflector


private static WebRequest Create(Uri requestUri, bool useUriBase)
{
 string absoluteUri;
 if (Logging.On)
 {
 Logging.Enter(Logging.Web, "WebRequest", "Create", requestUri.ToString());
 }
 WebRequestPrefixElement element = null;
 bool flag = false;
 if (!useUriBase)
 {
 absoluteUri = requestUri.AbsoluteUri;
 }
 else
 {
 absoluteUri = requestUri.Scheme + ':';
 }
 int length = absoluteUri.Length;
 ArrayList prefixList = PrefixList;
 for (int i = 0; i < prefixList.Count; i++)
 {
 element = (WebRequestPrefixElement) prefixList[i];
 if ((length >= element.Prefix.Length) && (string.Compare(element.Prefix, 0, absoluteUri, 0, element.Prefix.Length, StringComparison.OrdinalIgnoreCase) == 0))
 {
 flag = true;
 break;
 }
 }
 WebRequest retObject = null;
 if (flag)
 {
 retObject = element.Creator.Create(requestUri);
 if (Logging.On)
 {
 Logging.Exit(Logging.Web, "WebRequest", "Create", retObject);
 }
 return retObject;
 }
 if (Logging.On)
 {
 Logging.Exit(Logging.Web, "WebRequest", "Create", (string) null);
 }
 throw new NotSupportedException(SR.GetString("net_unknown_prefix"));
}

Let’s try and have a break-point on line   “ ArrayList prefixList = PrefixList;” so that we can check the local variables value.  Just because I have the private symbols ,I could have counted the line numbers manually and then set a break-point using !mbp command, but that is no fun. Here is another way of doing this.


.shell -ci "!u 000007fef6ea5a44 "  findstr get_PrefixList

In the above command I am disassembling the ip 000007fef6ea5a44 (which is there in the above callstack )to look for  get_PrefixList Instruction pointer . Here is the outcome

0:000> .shell -ci “!u 000007fef6ea5a44 ”  findstr get_PrefixList

000007fe`f6ea5a7a e8f1000000      call    System_ni+0x275b70 (000007fe`f6ea5b70) (System.Net.WebRequest.get_PrefixList(), mdToken: 00000000060019bc)

.shell: Process exited

I use the .shell command to manually avoid searching for an instruction. Now that I have the instruction pointer ,I am going to set a break-point on that using


bp 000007fe`f6ea5a7a "!mdv"

and here is the result of the break-point

0:000> g
(1758.167c): CLR notification exception – code e0444143 (first chance)
(1758.167c): CLR notification exception – code e0444143 (first chance)
Frame 0x0: (System.Net.WebRequest.Create(System.Uri, Boolean)):
[A0]:requestUri:<?>
[A1]:useUriBase:<?>
[L0]:LookupUri:0x00000000022c1a98 (System.String) STRVAL=http://www.google.com/
[L1]:Current:<?>
[L2]:Found:0x0000000000000000 (System.Boolean)
[L3]:LookupLength:0x0000000000000016 (System.Int32)
[L4]:prefixList:<?>
[L5]:i:<?>
[L6]:webRequest:<?>

System_ni+0x275a7a:
000007fe`f6ea5a7a e8f1000000      call    System_ni+0x275b70 (000007fe`f6ea5b70)

Voila! now I am able to have a break-point within the framework method  and also see locals and parameters like Visual Studio. The same technique can be used to debug third party assemblies where you don’t have source code or symbols.

Piracy in .NET Code – Part 2 – Even when the code is obfuscated


Continuing with my previous post, one of the biggest security holes I have noticed in certain application is using unsecure Network I/O communication, especially when activating license. I have seen software where they have used the best tool to obfuscate the code, it is extremely hard to disassemble this. But lose out by invoking a web service with plaintext xml for registration and communication. Like I mentioned in my previous post, I am not going to be discussing on how to solve this problem.

I have seen applications which would have a trial period after which the application pops-up a dialog box for activating license. Only if license text matches the format criteria (like xxx-xx-xxxx-xx) the send button enables. To circumvent the disabled button, some of the smart developers could enable the button within the debugger (windbg /cdb) or using a something like HawkEye . This is the first line of defense for the application.

The next thing is launching something like Fiddler and checking out the web service request /response for the activation request. I am sure most of us have dealt with fiddler, and if you are not aware, fiddler gives an option to have a break-point on response from the server. So it is easy to do a Man-in-the-middle attack by injecting your own response or someone could even hack the lmhost file to act as a server.

And just because it is plain text, I have usually seen a bool variable in the response being activated or not. And it is not hard for someone to update the response text and pass it as a response back from the server.

The updated xml might not comply with the response expected by the application, it might throw an exception like this

0:020> !pe

Exception object: 045b4314

Exception type:   System.Xml.XmlException

Message:          Unexpected end of file while parsing Test  has occurred. Line 13, position 81.

InnerException:   <none>

StackTrace (generated):

<none>

StackTraceString: <none>

HResult: 80131940

Because it is xml, usually these applications end up using XmlTextReader to parse it and from the exception someone could figure out what element is expected and build the xml out of this. FYI the XmlTextReader library is usually never obfuscated.

The idea behind this post is to let the dev’s understand the security risks and someone with little advanced knowledge can exploit the holes. This is not just applicable for software piracy, but in general, especially with the RIA growing rapidly we would want to consider the security aspect also.

Case of NullReferenceException not handled by sos / windbg


In this post I am going to be discussing about the NullReferenceException which is not trapped “sxe clr” command. FYI “sxe  clr” is the command in debugging tools to catch any clr exception.  Here is the kind of  code that I was debugging.


using System;

namespace Test
{
 class Program
 {
 string test;

 static void Main(string[] args)
  {
   try{
     new Program().Testing();
     }
   catch {
    Console.WriteLine("Something went wrong");
    }
   Console.Read();
 }

 int Testing(){
   if (test.Substring(10,20) == "asd")
     return 10;
   return 1;
   }
 }
}

The application was reporting “something went wrong”, just another day where I had to debug some code which I don’t appreciate debugging. I was asked to debug the issue. And I use windbg for all my production debugging.

Attached the process and issued the command sxe -c “!clrstack;!pe” clr, which instructs the debugger to trap any exception from clr and then print stack-trace and exception whenever an exception is thrown. And to my surprise the debugger didn’t break on the exception and I never got the call-stack.  And  my debugger was set ignore AV exception so it didn’t report on AV, if not I could have managed to get the call-stack and figure out the exception.  And to my surprise when I issued the command !pe I didn’t get any result.

From my past experience of debugging I know if have bp on KERNELBASE!RaiseException  I should be able to catch any exception. This is one advantage of understanding code close to metal , comes in handy when everything else fails. So issued the command bp KERNELBASE!RaiseException and here is the call-stack from the breakpoint

0:000> !mk

Thread 0:

ESP              EIP

00:U 000000000031e738 000007fefdafaa40 KERNELBASE!RaiseException

01:U 000000000031e740 000007fee4b6dbdc mscorwks!NakedThrowHelper2+0xc

02:U 000000000031e770 000007fee4b6dc2a mscorwks!NakedThrowHelper_RspAligned+0x3d

03:U 000000000031ece8 000007fee4b6dc35 mscorwks!NakedThrowHelper_FixRsp+0x5

04:M 000000000031ecf0 000007ff001a027f Test.Program.Testing()(+0x1 IL)(+0x3f Native) [C:\Users\naveen\Documents\Visual Studio 2010\Projects\ConsoleApplication4\Program.cs, @ 19,13]

05:M 000000000031ed40 000007ff001a0170 Test.Program.Main(System.String[])(+0x7 IL)(+0x50 Native) [C:\Users\naveen\Documents\Visual Studio 2010\Projects\ConsoleApplication4\Program.cs, @ 10,17]

06:U 000000000031ed90 000007fee4b6d502 mscorwks!CallDescrWorker+0x82

07:U 000000000031ede0 000007fee4a29fd3 mscorwks!CallDescrWorkerWithHandler+0xd3

08:U 000000000031ee80 000007fee4a3a3af mscorwks!MethodDesc::CallDescr+0x24f

09:U 000000000031f0d0 000007fee49adc7f mscorwks!ClassLoader::RunMain+0x22b

0a:U 000000000031f330 000007fee4991c74 mscorwks!Assembly::ExecuteMainMethod+0xbc

0b:U 000000000031f620 000007fee49c9955 mscorwks!SystemDomain::ExecuteMainMethod+0x491

0c:U 000000000031fbf0 000007fee4addb07 mscorwks!ExecuteEXE+0x47

0d:U 000000000031fc40 000007fee499855c mscorwks!CorExeMain+0xac

0e:U 000000000031fca0 000007fef9493309 mscoreei!CorExeMain+0x41

0f:U 000000000031fcd0 000007fef9525b21 MSCOREE!CorExeMain_Exported+0x57

10:U 000000000031fd00 00000000776cf56d KERNEL32!BaseThreadInitThunk+0xd

11:U 000000000031fd30 0000000077903281 ntdll!RtlUserThreadStart+0x1d

Now I see which line is causing the exception. I could guess what the exception could be. To confirm my assumption I issued the command !dso after the catch block message and here is the output

0:000> !dso

OS Thread Id: 0x1590 (0)

RSP/REG          Object           Name

000000000031ea58 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031ea68 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031eb18 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031eb58 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031eb80 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031eba0 00000000026a5ae0 Microsoft.Win32.SafeHandles.SafeFileHandle

000000000031ebe0 00000000026a5b58 System.IO.StreamReader

000000000031ebf0 00000000026a5b58 System.IO.StreamReader

000000000031ec10 00000000026a5b58 System.IO.StreamReader

000000000031ec40 00000000026a5b58 System.IO.StreamReader

000000000031ec50 00000000026a5b58 System.IO.StreamReader

000000000031ec60 00000000026a5b00 System.IO.__ConsoleStream

000000000031ec68 00000000026a5e68 System.Byte[]    (System.Byte[])

000000000031ec98 00000000026a6198 System.IO.TextReader+SyncTextReader

000000000031eca0 00000000026a5b58 System.IO.StreamReader

000000000031ecb0 00000000026a5b58 System.IO.StreamReader

000000000031ecd8 00000000026a6198 System.IO.TextReader+SyncTextReader

000000000031ed40 00000000026a6198 System.IO.TextReader+SyncTextReader

000000000031ed48 00000000026a4070 System.String

000000000031ed68 00000000026a4058 Test.Program

000000000031ed78 00000000026a4090 System.NullReferenceException

000000000031ed90 00000000026a3ff0 System.Object[]    (System.String[])

000000000031ef18 00000000026a3ff0 System.Object[]    (System.String[])

000000000031f100 00000000026a3ff0 System.Object[]    (System.String[])

000000000031f128 00000000026a3ff0 System.Object[]    (System.String[])

I could see a NullReferenceException on the stack, issued !pe on exception object and here is the output

0:000> !pe 00000000026a4090

Exception object: 00000000026a4090

Exception type: System.NullReferenceException

Message: Object reference not set to an instance of an object.

InnerException: <none>

StackTrace (generated):

SP               IP               Function

000000000031ECF0 000007FF001A027F ConsoleApplication4!Test.Program.Testing()+0x3f

000000000031ED40 000007FF001A0170 ConsoleApplication4!Test.Program.Main(System.String[])+0x50

StackTraceString: <none>

HResult: 80004003

And now I know which code to fix.

Using a native Dll via LoadLibrary within ASP.NET runtime


I was recently debugging a code that was trying to load a native Dll using LoadLibrary within ASP.NET process. The code was trying a load native Dll and then dynamically invoke a method by name using GetProcAddress. The loadlibrary code was working as expected within a managed Dll and was also tested with in a console application.  But it started throwing exception when it was used by the ASP.NET process. Debugged and figured out the exception was FileNotFoundException for loading the Dll via LoadLibrary. The Dll was copied into the bin folder in spite of it the ASP.NET runtime didn’t copy the Dll to the shadow location.  After doing a research figured out the runtime would copy dependencies that have been referenced by the code and referenced via PInvoke, and that was the reason the Dll wasn’t copied.

So I had three choices

  1. Copy the native Dll’s to system32 directory – Certainly wasn’t a good idea
  2. Change the native code to implement COM – So that the Dll can be in any location and the ASP.NET can still load them. This wasn’t possible because we didn’t have source code
  3. Add the path of the Dll to the environment path variable – This was the most viable solution. The one drawback with this solution was if there was another native Dll with the similar name and if it was found in lookup then that would be loaded.

So we went ahead took the third option and renamed the Dll to include the organization name. The loadlibrary code within the  ASP.NET runtime was able to locate the native Dll and load it.

FYI if the path environment variable is updated then the IIS has to be restarted to load the updated path variable.

Flattening List in F# and C#


I was teaching someone F# and comparing it with C#.  I had to bring in similarities between F# and C# and one of the key things List module. I was showing List Concatenation using “@” and also showing it C#. Here is an example of using it solving with selectmany


var x = new [] {new [] {10,20,30},new [] {40,50,60}};

x.SelectMany (y => y).ToList().ForEach(Console.WriteLine);

F# Solution


[10;20;30] @ [40;50;60]

Someone threw in a challenge by asking what if the list contains values and as well as other lists. Like example


var list = new List<object>();

list.AddRange(new object [] {14,new List<int>(),new List<int>() {1,10,23}});

And here was the code someone came up with in C#

list.Flatten<int>().ToList().ForEach(Console.WriteLine);

static class Extensions
{
 public static IEnumerable<T> Flatten<T>(this IEnumerable<Object> List)
 {
 var l = new List<T>();
 foreach (var element in List)
 {
 if (element is T)
 l.Add((T) element );
 else
 l.AddRange(((IEnumerable)element).Cast<T>());
 }
 return l;
 }
}

First of all the code isn’t type safe. I know there is a better way to solve in C#, but I wanted to show how this can be solved in a terse manner with F#

And here is my solution to above problem using in F#

type  T<'t> =
 |L of 't
 |N of T<'t> list

let rec flatten l =
 match l with
 |L x -> [x]
 |N x -> List.concat(List.map flatten x)

 let tree = N[L 14;N[];N[L 1;L 10;L 23]]
 let result = flatten tree

Get managed call-stacks in .NET for Registry access using ETW


I was recently debugging managed code which was accessing system registry implicitly because of an external dependent library.  So the first thing I asked was a Procmon log for of registry access. And then I also wanted look at the call-stacks for registry access, which Procmon does provide.

Here is a sample call-stack from Procmon for registry access. I am using linqpad as an example in this

ntoskrnl.exe    CmpCallCallBacks + 0x1c0    0xfffff80002c870d0
ntoskrnl.exe     ?? ::NNGAKEGL::`string’ + 0x4c81d    0xfffff80002c31116
ntoskrnl.exe    KiSystemServiceCopyEnd + 0x13    0xfffff800028d4853
ntdll.dll    ZwSetInformationKey + 0xa    0x779214aa
wow64.dll    wow64.dll + 0x2d252    0x7399d252
wow64.dll    wow64.dll + 0x1008f    0x7398008f
wow64.dll    wow64.dll + 0xcf87    0x7397cf87
wow64cpu.dll    TurboDispatchJumpAddressEnd + 0x24    0x7390276d
wow64.dll    wow64.dll + 0xd07e    0x7397d07e
wow64.dll    wow64.dll + 0xc549    0x7397c549
ntdll.dll    LdrpInitializeProcess + 0x17e2    0x779184c8
ntdll.dll     ?? ::FNODOBFM::`string’ + 0x2bea0    0x77917623
ntdll.dll    LdrInitializeThunk + 0xe    0x7790308e
ntdll.dll    NtOpenKey + 0x12    0x77acf9da
KernelBase.dll    OpenRegKey + 0x134    0x772f2ef3
KernelBase.dll    OpenAltSortsKey + 0x29    0x772de216
KernelBase.dll    IsValidLocale + 0x127    0x772e3271
clr.dll    clr.dll + 0xe4d5f    0x6be34d5f
clr.dll    clr.dll + 0xe4ba8    0x6be34ba8
mscorlib.ni.dll    mscorlib.ni.dll + 0x2ba2f1    0x697ba2f1
mscorlib.ni.dll    mscorlib.ni.dll + 0x2ba2c1    0x697ba2c1
mscorlib.ni.dll    mscorlib.ni.dll + 0x2b9faa    0x697b9faa
mscorlib.ni.dll    mscorlib.ni.dll + 0x2b9e0a    0x697b9e0a
mscorlib.ni.dll    mscorlib.ni.dll + 0x2ba15c    0x697ba15c
mscorlib.ni.dll    mscorlib.ni.dll + 0x2ba106    0x697ba106
mscorlib.ni.dll    mscorlib.ni.dll + 0x2b9db8    0x697b9db8
mscorlib.ni.dll    mscorlib.ni.dll + 0x2b9d34    0x697b9d34
clr.dll    clr.dll + 0x24a2a    0x6bd74a2a
clr.dll    clr.dll + 0x23153    0x6bd73153
clr.dll    clr.dll + 0x231cc    0x6bd731cc
clr.dll    clr.dll + 0x2323b    0x6bd7323b
clr.dll    clr.dll + 0x23415    0x6bd73415
clr.dll    clr.dll + 0x2355a    0x6bd7355a
clr.dll    clr.dll + 0x94844    0x6bde4844
<unknown>    0xb2420    0xb2420
mscorlib.ni.dll    mscorlib.ni.dll + 0x255870    0x69755870
mscorlib.ni.dll    mscorlib.ni.dll + 0x2557cd    0x697557cd
mscorlib.ni.dll    mscorlib.ni.dll + 0x255764    0x69755764
<unknown>    0x4e00d9    0x4e00d9
clr.dll    clr.dll + 0x21db    0x6bd521db
clr.dll    clr.dll + 0x24a2a    0x6bd74a2a
clr.dll    clr.dll + 0x24bcc    0x6bd74bcc
clr.dll    clr.dll + 0x24c01    0x6bd74c01
clr.dll    clr.dll + 0x24c21    0x6bd74c21
clr.dll    clr.dll + 0xece82    0x6be3ce82
clr.dll    clr.dll + 0xecf90    0x6be3cf90
clr.dll    clr.dll + 0xecda4    0x6be3cda4
clr.dll    clr.dll + 0xed199    0x6be3d199
clr.dll    clr.dll + 0xed09a    0x6be3d09a
clr.dll    clr.dll + 0x16af00    0x6bebaf00
mscoreei.dll    mscoreei.dll + 0x55ab    0x726355ab
mscoree.dll    mscoree.dll + 0x7f16    0x75077f16
mscoree.dll    mscoree.dll + 0x4de3    0x75074de3
ntdll.dll    __RtlUserThreadStart + 0x70    0x77ae9d72
ntdll.dll    _RtlUserThreadStart + 0x1b    0x77ae9d45

It is all unmanaged call-stacks , what I was looking for was managed call-stacks. The solution to this was ETW tracing. I use Perfmonitor from the BCL teams codeplex site for getting managed call-stacks.

Here are the steps to get managed call-stacks for registry access

PerfMonitor.exe /registry /stacks /lineNumbers start

Run the process and do the steps for registry access

PerfMonitor.exe /registry /stacks /lineNumbers stop
PerfMonitor.exe  /stacks /lineNumbers print

The above should produce a xml file which is by default named as PerfMonitorOutput.print.xml

And here is the managed call-stacks for registry access.

<Event MSec=  “3449.0880” PID=”3356″ PName= “LINQPad” TID=”4536″ EventName=”RegistryOpen” Status=”0x00000000″ KeyHandle=”0x00000000″ ElapsedTime=”0″ KeyName=”\Registry\Machine\System\CurrentControlSet\Control\Nls\Locale\Alternate Sorts” Index=”0″ InitialTime=”1/3/1601 1:11:43 PM”>
<StackTrace>
<CodeAddress Address=”0xfffff80002c22003″ FullMethodName=”_NULL_IMPORT_DESCRIPTOR” ModuleName=”ntoskrnl”/>
<CodeAddress Address=”0xfffff80002bb5d3b” FullMethodName=”$$VProc_ImageExportDirectory” ModuleName=”ntoskrnl”/>
<CodeAddress Address=”0xfffff800028d4853″ FullMethodName=”KiDeliverApc” ModuleName=”ntoskrnl”/>
<CodeAddress Address=”0x77920e0a” FullMethodName=”ZwOpenKeyEx” ModuleName=”ntdll”/>
<CodeAddress Address=”0x7399d1f1″ ModuleName=”wow64″/>
<CodeAddress Address=”0x7398008f” ModuleName=”wow64″/>
<CodeAddress Address=”0x7397cf87″ ModuleName=”wow64″/>
<CodeAddress Address=”0x7390276d” ModuleName=”wow64cpu”/>
<CodeAddress Address=”0x7397d07e” ModuleName=”wow64″/>
<CodeAddress Address=”0x7397c549″ ModuleName=”wow64″/>
<CodeAddress Address=”0x779184c8″ FullMethodName=”LdrpInitializeProcess” ModuleName=”ntdll”/>
<CodeAddress Address=”0x77917623″ FullMethodName=” ?? ::FNODOBFM::`string&apos;” ModuleName=”ntdll”/>
<CodeAddress Address=”0x7790308e” FullMethodName=”LdrInitializeThunk” ModuleName=”ntdll”/>
<CodeAddress Address=”0x77acf9da” FullMethodName=”NtOpenKey” ModuleName=”ntdll”/>
<CodeAddress Address=”0x772f2ef3″ ModuleName=”KernelBase”/>
<CodeAddress Address=”0x772de216″ ModuleName=”KernelBase”/>
<CodeAddress Address=”0x772e3264″ ModuleName=”KernelBase”/>
<CodeAddress Address=”0x6be34d5f” ModuleName=”clr”/>
<CodeAddress Address=”0x6be34ba8″ ModuleName=”clr”/>
<CodeAddress Address=”0x697ba2f1″ FullMethodName=”System.Globalization.CultureData.InitCultureData()” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697ba2c1″ FullMethodName=”System.Globalization.CultureData.CreateCultureData(class System.String,bool)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697b9faa” FullMethodName=”System.Globalization.CultureData.GetCultureData(class System.String,bool)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697b9e0a” FullMethodName=”System.Globalization.CultureInfo..ctor(class System.String,bool)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697ba15c” FullMethodName=”System.Globalization.CultureInfo.GetCultureByName(class System.String,bool)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697ba106″ FullMethodName=”System.Globalization.CultureInfo.InitUserDefaultCulture()” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697b9db8″ FullMethodName=”System.Globalization.CultureInfo.Init()” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697b9d34″ FullMethodName=”System.Globalization.CultureInfo..cctor()” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x6bd74a2a” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd73153″ ModuleName=”clr”/>
<CodeAddress Address=”0x6bd731cc” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd7323b” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd73415″ ModuleName=”clr”/>
<CodeAddress Address=”0x6bd7355a” ModuleName=”clr”/>
<CodeAddress Address=”0x6bde4844″ ModuleName=”clr”/>
<CodeAddress Address=”0x122420″/>
<CodeAddress Address=”0x69755870″ FullMethodName=”System.Version.TryParseVersion(class System.String,value class VersionResult&amp;)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x697557cd” FullMethodName=”System.Version.Parse(class System.String)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x69755764″ FullMethodName=”System.Version..ctor(class System.String)” ModuleName=”mscorlib”/>
<CodeAddress Address=”0x1e00d9″ FullMethodName=”LINQPad.Loader.Main(class System.String[])” ModuleName=”LINQPad”/>
<CodeAddress Address=”0x6bd521db” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd74a2a” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd74bcc” ModuleName=”clr”/>
<CodeAddress Address=”0x6bd74c01″ ModuleName=”clr”/>
<CodeAddress Address=”0x6bd74c21″ ModuleName=”clr”/>
<CodeAddress Address=”0x6be3ce82″ ModuleName=”clr”/>
<CodeAddress Address=”0x6be3cf90″ ModuleName=”clr”/>
<CodeAddress Address=”0x6be3cda4″ ModuleName=”clr”/>
<CodeAddress Address=”0x6be3d199″ ModuleName=”clr”/>
<CodeAddress Address=”0x6be3d09a” ModuleName=”clr”/>
<CodeAddress Address=”0x6bebaf00″ ModuleName=”clr”/>
<CodeAddress Address=”0x726355ab” ModuleName=”mscoreei”/>
<CodeAddress Address=”0x75077f16″ ModuleName=”mscoree”/>
<CodeAddress Address=”0x75074de3″ ModuleName=”mscoree”/>
<CodeAddress Address=”0x77ae9d72″ FullMethodName=”__RtlUserThreadStart” ModuleName=”ntdll”/>
<CodeAddress Address=”0x77ae9d45″ FullMethodName=”_RtlUserThreadStart” ModuleName=”ntdll”/>
</StackTrace>
</Event>

Here I was  able to get the managed as well as native call-stacks for registry access by keyname.  And here is my list of posts on ETW

Visualizing Silverlight / .NET managed memory using Pivot


I got to see this amazing video on Pivot from Gary Flake.  Pivot is about visualizing data. It’s primarily for visualizing patterns and trends. What other way I would use other than analyzing managed memory using pivot. I spend a lot of time in windbg to look at memory for patterns, analyzing memory leaks.  And I also know not many of them want to learn the arcane commands of windbg. So I went ahead took the data from managed memory and ported it in to pivot format , which is cxml. I use the “!Traverseheap –xml” command from sos to generate the xml ,which I port it to cxml format.My initial thought was use dgml to visualize the data, but pivot is way better. Pivot can only be used in Vista+  OS.

FYI I know this is not for everyone, there are geeks who wouldn’t want to look at memory in a visual format, they prefer looking at in cdb.  I took Facebook Silverlight client app and got a snapshot of the memory for this demonstration

The few things that can be done with this are

  • Drill down objects by type with just one click : What I mean by this is , you could probably have 6000 odd types of objects and not instances (instances could be in thousands), but if you wanted to look at all the instance of customer objects  , it is as easy as one click from the filter.

Here is an example of filtering securitypermission objects in memory

  • Drill down members: The objects members can be looked up. So if you are looking at the customer object then you can view  strings, ints and all its members. It WILL NOT have the value for these members. It is not provided by the traverseheap command

  • Filter objects by namespace– All the objects belonging to namespaces can be drilled down.

  • Filter by object size


void Main()
{
 var startString =@"<?xml version=""1.0"" encoding=""utf-8""?>
<?xml-stylesheet type=""text/xsl"" href=""../pivot.xsl""?>
<Collection xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""
 Name=""Memory Visualization"" SchemaVersion=""1"" d1p1:Icon=""icon.ico""
 xmlns:d1p1=""http://schemas.microsoft.com/livelabs/pivot/collection/2009"" xmlns=""http://schemas.microsoft.com/collection/metadata/2009"">
 <FacetCategories>
 <FacetCategory Name=""Type"" Type=""String"" d1p1:IsFilterVisible=""true"" d1p1:IsMetaDataVisible=""true"" d1p1:IsWordWheelVisible=""true"" />
 <FacetCategory Name=""Address"" Type=""String"" d1p1:IsFilterVisible=""true"" d1p1:IsMetaDataVisible=""true"" d1p1:IsWordWheelVisible=""true"" />
 <FacetCategory Name=""Size""  Type=""Number"" d1p1:IsFilterVisible=""true"" d1p1:IsMetaDataVisible=""true"" d1p1:IsWordWheelVisible=""true"" />
 <FacetCategory Name=""Namespaces"" Type=""Link"" d1p1:IsFilterVisible=""true"" d1p1:IsMetaDataVisible=""true"" d1p1:IsWordWheelVisible=""true"" />
 <FacetCategory Name=""Members"" Type=""Link"" d1p1:IsFilterVisible=""true"" d1p1:IsMetaDataVisible=""true"" d1p1:IsWordWheelVisible=""true"" />
 </FacetCategories>
 <Items ImgBase=""test.gif"">";

 var endString = @"</Items>
</Collection>";

 var counter = 0;
 var outputFileName = "sl.cxml";
 var dict = new Dictionary<string,string>() { {"String","img5.jpg"},{"Object","img6.jpg"}};
 var getimg = new Func<string,string>((t) => dict.ContainsKey(t) ? dict[t] : "img8.jpg");

 var doc = XDocument.Load(@"c:\Temp\fb.xml");

 var types = (from i in doc.Descendants().Descendants().Descendants("type").AsParallel()
 let ns = i.Attribute("name").Value.SplitEx().ToList()
 select new {Id = int.Parse( i.FirstAttribute.Value),Name = ns.Last(),
 Namespaces = ns.Count()  > 2 ? ns.Take(ns.Count () -2) : ns.Take(ns.Count -1)}).ToList();
 var y = from i in doc.Descendants().Descendants().Descendants("object").AsParallel()
 let type = types.First (t => t.Id== int.Parse( i.Attribute("typeid").Value))
 select new {Address = i.FirstAttribute.Value,
 Type = type.Name,
 Namespaces = type.Namespaces,
 Size = int.Parse( i.LastAttribute.Value),
 children = from k in i.Descendants().AsParallel()
 from o in doc.Descendants().Descendants().Descendants("object").AsParallel()
 where k.FirstAttribute.Value == o.FirstAttribute.Value
 select new {Address = k.FirstAttribute.Value,Type = types.First (t => t.Id == int.Parse( o.Attribute("typeid").Value) ).Name}
 };

 var x = from i in y.Take(2000).AsParallel()
 let increment = new Func<int>(() => Interlocked.Increment(ref counter))
 select new XElement("Item",new XAttribute("Img",getimg(i.Type)),new XAttribute("Id",increment()),new XAttribute("Name",i.Type),
 new XElement("Facets",
 new XElement("Facet",new XAttribute("Name","Type"),
 new XElement("String",new XAttribute("Value",i.Type))),
 new XElement("Facet",new XAttribute("Name","Size"),
 new XElement("Number",new XAttribute("Value",i.Size.ToString()))),
 new XElement("Facet",new XAttribute("Name","Address"),
 new XElement("String",new XAttribute("Value",i.Address))),
 new XElement("Facet",new XAttribute("Name","Namespaces"),
 i.Namespaces.Select (n =>new XElement("Link",new XAttribute("Name",n),new XAttribute("Href",string.Format("{0}#Link=EQ.{1}",outputFileName,n))))),
 i.children.Any() == false ? default(XElement):
 new XElement("Facet",new XAttribute("Name","Members"),
 i.children.Select (n =>new XElement("Link",new XAttribute("Name",n.Type),new XAttribute("Href",string.Format("{0}#Address=EQ.{1}",outputFileName,n.Address)))))
 )).ToString();
 File.WriteAllText(@"c:\temp\sl.cxml",string.Format("{0}{1}{2}",startString,x.Select (s => s).Aggregate(new StringBuilder(), (ag, n) => ag.Append(n)).ToString(),endString));
 Console.WriteLine ("Done");
}

static class Foo
{
 public static IEnumerable<string> SplitEx(this string s)
 {
 if (s.Contains("`") == false)
 return s.Split(new []{'.'});
 else
 {
 var stringList = new List<string>();
 var index =0;
 var counter = 0;
 var splitString = "";
 while (counter < s.Length)
 {
 index = s.IndexOf(".",counter);
 if (index < 0)
 {
 stringList.Add(s.Substring(counter));
 break;
 }
 splitString = s.Substring(counter,index -counter );
 if (splitString.Contains("`"))
 {
 stringList.Add(s.Substring(counter));
 break;
 }
 stringList.Add(splitString);
 counter = index +1;
 }
 return stringList;
 }
 }
}

The above code converts the xml format from !traverseheap to pivot xml format. This is CPU intensive and I have not profiled and fine tuned it. I use plinq for conversion primarily because I have quad-core box. I use pictures from powerpoint for visualizing  objects and I also wrote SplitEx method to avoid splitting namespaces that are part of the type name within generics “GenericEqualityComparer`1[[System.String, mscorlib]]”

And here is the command to get the xml input for the above code as input

!TraverseHeap -xml c:\temp\mem.xml
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: