Archive for the ‘WinDbg’ Category
NVARCHAR and the Oracle string aggregate function to perform concatenation
Thursday, December 31st, 2009My colleague Janice had a lot of fun while trying to concat NVARCHAR in oracle and she happens to share her findings with us. Hopefully, this will be helpful for someone
Just fyi…
I needed to create a string aggregate function for concatenation in Oracle. For example, given a user table where each record contains DepartmentCode and UserID, I would like to roll up the multiple UserIDs into one field with comma, etc separators.
| DepartmentCode | Users |
| 0 | User1, user2, user3, User4, User5 |
I found this nice summary of the problem along with six(6) potential solutions: http://www.oracle-base.com/articles/10g/StringAggregationTechniques.php
Bottom line…these techniques worked when the data involved was VARCHAR2 (1-byte char), . When I tried using NVARCHAR2 (multi-byte chars), I could not get all of the techniques to work. Here are my findings…
________________________________________
1. WMSYS.WM_CONCAT – This seems to be a slightly undocumented built-in function. Who knew? I am uncertain if it is fully supported by Oracle or not.
VARCHAR2: (Works!)
NVARCHAR2: (Doesn’t work. Returns nulls.)
2. Specific function – Needs a custom function for each string you might want to aggregate.
VARCHAR2: (Works!)
NVARCHAR2: (Works!)
3. Generic function with ref cursor – Only needs one function added. Usage in query is easy to understand.
VARCHAR2: (Works!)
NVARCHAR2: (Doesn’t work. Returns nulls.)
4. User defined aggregate function – Needs a type, type body, and function added. Support code is not obvious. Usage in query is easy to understand.
VARCHAR2: (Works!)
NVARCHAR2: (Doesn’t work. Returns nulls.) Note that when I changed the VARCHAR2 types to NVARCHAR2 in the sample code, I received a runtime error.
5. ROW_NUMBER() and SYS_CONNECT_BY_PATH functions – Needs nothing added. Query usage is by far the most complicated, but it certainly works.
VARCHAR2: (Works!)
NVARCHAR2: (Works!)
6. COLLECT function – Needs a type and a function added. Query usage is easy to understand.
VARCHAR2: (Works!)
NVARCHAR2: (Doesn’t work. Returns nulls.) Note that when I changed the VARCHAR2 types to NVARCHAR2 in the sample code, I received a runtime error.
________________________________________
NOTE: In all of the NVARCHAR2 examples that didn’t work, I tried a variety of explicit type conversions, TO_CHAR, TRANSLATE USING, etc. and nothing helped.
ASP.NET App Slow Response and Application Pool/AppDomain Recycle, Event message: Application is shutting down. Reason: Unknown - Windows Server 2003
Sunday, August 30th, 2009Scenario
From time to time, asp.net application response is very slow on Windows Server 2003
Some rants and the resolution
After turning on recycle events, logged message in application event log was Event message: Application is shutting down. Reason: Unknown. Slow response is always timed with this message in the application event log so that confirmed that Application Pool is terminating so no wonder asp.net response is slow from time to time.
However, the only missing piece was why? Since, the Reason is unknown :-). This application pool is configured for web garden with 6 app pools in it so we decided to attach debugger in production box to 2 worker processes.
If you are just starting out with debugging or have not read John Robbins Book on debugging, I would like to stress the followings when using debugger in production environment
1. By Default, ADPlus writes the call stack on first-chance exception. Walking call stack also results in Symbol loading, symbol loading along with the stack walking causes a performance hit when a debugger is attached. The last thing you want in production environment is to cause performance hit because of debugger.
2. Don’t just use ADPlus script to attach a debugger to the worker process by name because it will attach the debugger to each worker process in your production server causing further performance hit.
3. Don’t use DebugDiag in production environment unless you really have a good reason for it.
The reason I am stressing about these points is because I noticed someone following all the worst practices in production environment while debugging.
The best practice is to use adplus configuration file to attach to a worker process and preferably by worker process id.
Identifying the issue
First of all, I would like to mention that Tess has excellent blog on AppDomain recycle http://blogs.msdn.com/tess/archive/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles.aspx
We just needed to find out the reason for AppPool shutdown.
Our goal is to attach a debugger to one worker process to generate a memory dump on crash and another goal is, ctrl+c in debugger console should not kill the worker process. We used optimized ADPlus Config file for production environment as shown below
<ADPlus>
<Settings>
<RunMode>CRASH</RunMode>
<Option>Quiet</Option>
<OutputDir> c:\dumps </OutputDir>
<ProcessID> 2684 </ProcessID>
</Settings>
<Exceptions>
<Option> NoDumpOnFirstChance </Option>
<Config>
<Code> AllExceptions </Code>
<Actions1> Log </Actions1>
<Actions2> FullDump; </Actions2>
<ReturnAction1> GN </ReturnAction1>
<ReturnAction2> Q </ReturnAction2>
</Config>
</Exceptions>
</ADPlus>
once we have the crash dump, just dump the httpruntime object to find out the shutdown reason and the call stack as shown below
at System.Web.HttpRuntime.OnCriticalDirectoryChange(Object sender, FileChangeEvent e)
at System.Web.FileChangesMonitor.OnSubdirChange(Object sender, FileChangeEvent e)
at System.Web.DirectoryMonitor.FireNotifications()
at System.Web.Util.WorkItem.CallCallbackWithAssert(WorkItemCallback callback)
at System.Web.Util.WorkItem.OnQueueUserWorkItemCompletion(Object state)
at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)
Name: System.String
MethodTable: 79330a00
EEClass: 790ed64c
Size: 67576(0×107f8) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
String: Directory rename change notification for ‘C:\Inetpub\<>\<>’.
Web dir change or directory renameAppDomain is shutting down because of directory rename.
There are thousands of folders under the root website and after talking to customer I learnt that this is indeed the case.
Resolution
After googling or binging, I found out that there is no resolution and this was implemented in asp.net 2.0. AppDomain will recycle on directory rename or delete. However, I did come across a
Microsoft KB http://support.microsoft.com/kb/911272 which talks about changing this behavior from registry setting. The bad news is changing the registry setting [HKEY_LOCAL_MACHINE\SOFTWARE\
ASP.NET\"FCNMode"=dword:00000001 doesn't work. Although, KB article does suggest you to contact Microsoft support for hot fix but also suggests that it will be addressed in the next .NET SP.
OnFileChange(FileAction, String, DateTime)
OnCriticaldirChange(Object, FileChangeEvent)
OnSubdirChange(Object, FileChangeEvent)
Another cause of AppDomain recycle is overwhelming amount of file change notification but microsoft apparently fixed in .net 2.0 hot fix so who knows.
HttpRuntime also implements another method to monitor the directories
internal void StartListeningToLocalResourcesDirectory(VirtualPath virtualDir) { if (!this.IsFCNDisabled && ((this._callbackRenameOrCriticaldirChange != null) && (this._dirMonSpecialDirs != null))) { |
You will notice, how it checks for FCNDisabled which should have been the registry key since it return (this._FCNMode == 1);
All these settings are set in
internal FileChangesMonitor() { UnsafeNativeMethods.GetDirMonConfiguration(out this._FCNMode);
FCNMode value comes from native dll (webengine.dll)
[DllImport("webengine.dll")] internal static extern void GetDirMonConfiguration(out int FCNMode); |
Since, HttpRuntime controls the file monitoring so get the DirectoryMonitor object and calls StopMonitoring on it. Another way to probably implement is getting the FileChangesMonitor object and setting the FCNMode to 1 or setting the _dirMonSpecialDirs to null.
protected void Application_Start(object sender, EventArgs e)
{
System.Reflection.PropertyInfo p = typeof(System.Web.HttpRuntime)
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
object o = p.GetValue(null, null);
System.Reflection.FieldInfo f = o.GetType().GetField(”_dirMonSubdirs”,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.IgnoreCase);
object monitor = f.GetValue(o);
System.Reflection.MethodInfo m = monitor.GetType().GetMethod(”StopMonitoring”,
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
m.Invoke(monitor, null);
}
{
HttpRuntime runtime = (HttpRuntime)typeof(System.
BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField, null, null, null);
if (runtime == null)
return;
string shutDownMessage = (string)runtime.GetType().InvokeMember(”_shutDownMessage”,
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null);
string shutDownStack = (string)runtime.GetType().InvokeMember(”_shutDownStack”,
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, runtime, null);
if (!EventLog.SourceExists(”.NET Runtime”))
{
EventLog.CreateEventSource(”.NET Runtime”, “Application”);
}
EventLog log = new EventLog();
log.Source = “.NET Runtime”;
log.WriteEntry(String.Format(”\r\n\r\n_shutDownMessage={0}\r\n\r\n_shutDownStack={1}”,
shutDownMessage,
shutDownStack),
EventLogEntryType.Error);
}
Important Note
Microsoft KB http://support.microsoft.com/kb/911272 which talks about changing this behavior from registry setting doesn’t work in Windows Server 2003 but it does work on Windows Server 2008/R2 with IIS7 integrated/classic pipeline. The best way to address this issue is by modifying the registry key otherwise file handles don’t get released when dirMonSpecialDirs is set to null using reflection
LoadLibrary failed, Win32 error 0n193 “%1 is not a valid Win32 application.” Please check your debugger configuration and/or network access.
Wednesday, July 29th, 20090:000> .loadby sos coreclr
The call to LoadLibrary(c:\Program Files (x86)\Microsoft Silverlight\3.0.40624.0\sos) failed, Win32 error 0n193
“%1 is not a valid Win32 application.”
Please check your debugger configuration and/or network access.
Make sure you are not using WinDbg 64 bit version. Silverlight is not 64 bit yet so even if you have a browser running on 64 bit os, sos dll for silverlight coreclr will fail to load on WinDbg 64 bit. Analyze your dump with WinDbg x86 version. I have WinDbg 32 bit and 64 bit both installed on my vista 64 bit os, although I still prefer XP or may be windows 7 from now on.
interesting windows service hang issue because of zone identifier data
Saturday, July 11th, 2009The first time I came across this issue, my ex-boss Bill Vieux pointed it out immediately when we were looking at hang dump. I came across this issue again last week so I thought I will blog about it, just in case anyone finds it useful.
Scenario:
Windows Service is configured to watch a folder to export a file, when a file is written to disk it will launch an executable with parameters. First of all, yes it is always a bad idea to launch an exe from a windows service but anyways, sometime you don’t have a choice. Windows service was hanging with the release of new executable and we could never recreate this issue. We asked for hang dump and the following is what we found on a callstack.
0:012> ~6kb
ChildEBP RetAddr Args to Child
00e8d07c 7e419418 7e42770a 00000000 00000000 ntdll!KiFastSystemCallRet
00e8d0b4 7e4249c4 003d060c 00000000 00000001 USER32!NtUserWaitMessage+0xc
00e8d0dc 7e424a06 03850000 03ab83f8 00000000 USER32!InternalDialogBox+0xd0
00e8d0fc 7e4247ea 03850000 03ab83f8 00000000 USER32!DialogBoxIndirectParamAorW+0×37
00e8d120 77fa9ef1 03850000 00001140 00000000 USER32!DialogBoxParamW+0×3f
00e8d188 7e2f3dc1 03850000 00001140 00000000 SHDOCVW!SHFusionDialogBoxParam+0×3a
00e8d1a8 7e2f43b4 00000000 00001140 00e8d1fc SHDOCVW!_ShowSafeOpenDialog+0×26
00e8f6d0 7ca4d2ec 00000000 0019400c 00194008 SHDOCVW!SafeOpenPromptForShellExec+0×2ce
00e8f6f0 7ca04173 0019400c 00000001 00194008 shell32!CShellExecute::_ZoneCheckFile+0×60
00e8f708 7ca040fa 0019400c 013ca5c0 00194008 shell32!CShellExecute::_VerifyZoneTrust+0×2a
00e8f72c 7ca03071 0019400c 00e8fa0c 00194008 shell32!CShellExecute::_VerifyExecTrust+0xa4
00e8f754 7ca02f6a 013ca5c0 00190f00 00e8fa0c shell32!ShellExecuteNormal+0×30
00e8f770 00a3b0aa 013ca5c0 11ad3aad 00000000 shell32!ShellExecuteExW+0×8d
If you are familiar with alternate data stream, you will notice VerifyZoneTrust immediately. When we dump the parameter passed in internaldialogbox, below is what we have
0:012> dc 03ab83f8 03ab83f8 + 512
03ab83f8 80c80ac0 00000000 00000011 01090000 …………….
03ab8408 000000a9 00000000 004d0008 00200053 ……….M.S. .
03ab8418 00680053 006c0065 0020006c 006c0044 S.h.e.l.l. .D.l.
03ab8428 00000067 50000080 00000000 000a000a g……P……..
03ab8438 001400f5 ffff1141 00440082 0020006f ….A…..D.o. .
03ab8448 006f0079 00200075 00610077 0074006e y.o.u. .w.a.n.t.
03ab8458 00740020 0020006f 0070006f 006e0065 .t.o. .o.p.e.n.
03ab8468 00740020 00690068 00200073 00690066 .t.h.i.s. .f.i.
03ab8478 0065006c 0000003f 00000000 50000003 l.e.?……….P
03ab86f8 0069004c 006b006e 00540000 00690068 L.i.n.k…T.h.i.
03ab8708 00200073 00790074 00650070 006f0020 s. .t.y.p.e. .o.
03ab8718 00200066 00690066 0065006c 00630020 f. .f.i.l.e. .c.
03ab8728 006e0061 00680020 00720061 0020006d a.n. .h.a.r.m. .
03ab8738 006f0079 00720075 00630020 006d006f y.o.u.r. .c.o.m.
03ab8748 00750070 00650074 002e0072 004f0020 p.u.t.e.r… .O.
03ab8758 006c006e 00200079 00750072 0020006e n.l.y. .r.u.n. .
03ab8768 006f0073 00740066 00610077 00650072 s.o.f.t.w.a.r.e.
03ab8778 00660020 006f0072 0020006d 00750070 .f.r.o.m. .p.u.
03ab8788 006c0062 00730069 00650068 00730072 b.l.i.s.h.e.r.s.
03ab8798 00790020 0075006f 00740020 00750072 .y.o.u. .t.r.u.
03ab87a8 00740073 0020002e 0041003c 0048003e s.t… .<.A.>.H.
03ab87b8 0077006f 00630020 006e0061 00490020 o.w. .c.a.n. .I.
03ab87c8 00640020 00630065 00640069 00200065 .d.e.c.i.d.e. .
03ab87d8 00680077 00740061 00730020 0066006f w.h.a.t. .s.o.f.
03ab87e8 00770074 00720061 00200065 006f0074 t.w.a.r.e. .t.o.
03ab87f8 00740020 00750072 00740073 003c003f .t.r.u.s.t.?.<.
03ab8808 0041002f 0000003e 00000000 00000000 /.A.>………..
03ab8818 80c80ac0 00000000 00000011 01090000 …………….
03ab8828 000000a7 00000000 004d0008 00200053 ……….M.S. .
03ab8838 00680053 006c0065 0020006c 006c0044 S.h.e.l.l. .D.l.
03ab8848 00000067 50000080 00000000 000a000a g……P……..
03ab8858 001400f5 ffff1141 00440082 0020006f ….A…..D.o. .
03ab8868 006f0079 00200075 00610077 0074006e y.o.u. .w.a.n.t.
03ab8878 00740020 0020006f 0070006f 006e0065 .t.o. .o.p.e.n.
03ab8888 00740020 00690068 00200073 00690066 .t.h.i.s. .f.i.
03ab8898 0065006c 0000003f 00000000 50000003 l.e.?……….P
We have a modal dialog box with message “Do you want to …, file can harm your computer…” and since windows service is not running in interactive desktop mode, you are not going to see the warning message.
on executing streams( downloadable from http://technet.microsoft.com/en-us/sysinternals/bb897440.aspx) on exe, we see the following output
D:\Tools\Streams>streams “d:\xxxxx.exe”
Streams v1.56 - Enumerate alternate NTFS data streams
Copyright (C) 1999-2007 Mark Russinovich
Sysinternals - www.sysinternals.com
:Zone.Identifier:$DATA 26
Zone.identifier is added as a security measure to every executable when downloaded from http or on a network share.
Since this application could be deployed using xcopy, so someone unzipped on a network share to copy the executable and of course windows service is now hung. Although, it is always a bad idea to launch exe but sometime there is no option so watch out for this scenario
WinDbg meta-command tip to display all the extension commands exported by WinDbg extension
Tuesday, July 7th, 2009Usually, A WinDbg extension will have the !help command in case you need to look at the supported commands in an extension. However, not all commands may be documented or no documentation at all. In that case you can use Depends or any dissembler to look at the Export section.
But, with .extmatch command, you can achieve the same right in the debugger itself as shown below.
Below is the executed command to display all the extension commands supported by loaded SOS in CLR 4.0
remember the space between sos and *
0:020> .extmatch /D /e c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos *
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.AnalyzeOOM
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.BPMD
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.CLRStack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.COMState
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ClrStack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpArray
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpAssembly
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpClass
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpDomain
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpHeap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpIL
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpLog
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpMD
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpMT
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpModule
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpObj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpRuntimeTypes
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpSig
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpSigElem
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpStack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpStackObjects
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.DumpVC
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Dumplog
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Dumpruntimetypes
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.EEHeap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.EEStack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.EEVersion
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.EHInfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Ehinfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.FinalizeQueue
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.FindAppDomain
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.FindRoots
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Findappdomain
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCHandleLeaks
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCHandleleaks
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCHandles
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCHeapStat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCInfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCRoot
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GCWhere
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GcHeapStat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.GcWhere
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Gchandleleaks
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HandleCLRN
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HeapStat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Help
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistClear
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistInit
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistObj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistObjFind
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistRoot
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.HistStats
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.IP2MD
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ListNearObj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.MinidumpMode
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Minidumpmode
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Name2EE
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ObjSize
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.PrintException
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Printexception
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ProcInfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.RCWCleanupList
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Rcwcleanuplist
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.SOSFlush
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.SaveModule
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.StopOnException
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Stoponexception
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.SyncBlk
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ThreadPool
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ThreadState
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Threads
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Token2EE
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.TraverseHeap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Traverseheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.U
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.VMMap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.VMStat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.VerifyHeap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.VerifyObj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.VerifyStackTrace
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.Verifyheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.WatsonBuckets
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.analyzeoom
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ao
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.bpmd
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.clrstack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.comstate
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.da
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.do
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dso
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumparray
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpassembly
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpclass
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpdomain
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpil
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumplog
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpmd
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpmodule
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpmt
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpobj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpruntimetypes
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpsig
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpsigelem
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpstack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpstackobjects
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.dumpvc
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.eeheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.eestack
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.eeversion
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ehinfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.finalizequeue
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.findappdomain
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.findroots
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.fq
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gchandleleaks
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gchandles
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gcheapstat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gcinfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gcroot
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.gcwhere
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.heapstat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.help
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histclear
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histinit
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histobj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histobjfind
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histroot
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.histstats
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.hof
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.ip2md
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.listnearobj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.lno
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.minidumpmode
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.name2ee
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.objsize
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.pe
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.printexception
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.procinfo
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.rcwcleanuplist
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.savemodule
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.soe
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.sosflush
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.stoponexception
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.syncblk
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.t
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.threadpool
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.threads
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.threadstate
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.token2ee
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.tp
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.traverseheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.u
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.verifyheap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.verifyobj
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.vh
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.vmmap
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.vmstat
!c:\WINDOWS\Microsoft.NET\Framework\v4.0.20506\sos.vo
Interesting WinDbg Extension SOS commands in CLR 4.0/.NET Framework 4.0 CTP, .NET runtime dll renamed and sos commands just got richer
Tuesday, July 7th, 2009We will review the WinDbg Extension SOS.dll in .NET Framework 4.0 CTP. CLR 4.0 has renamed runtime dll from mscorwks.dll to CLR.DLL, that’s really helpful.
loading SOS dll depending on the location of .net 4.0 runtime aka CLR.DLL, execute the following command
.loadby sos clr
1. DML Support - YES, finally. SOS supports DML in .NET 1.1 but it was gone in clr 2.0. Silverlight CoreCLR supports DML and now .NET framework 4.0 supports it as well.
Execute the following command to turn on DMLfor every command or use /D option
0:003> .prefer_dml 1
DML versions of commands on by default
0:003> !dumpheap /D -type Exception -stat
For people new to WinDbg, Why am I so excited about DML support in SOS?
If you look at the above snapshot, you have the link for each MethodTable address which you can just click on to execute the command. No need to type, however not every commands will have the DML support but !dumpobject is another important one, you can just click on object address to dump an object from GC Heap.
2. The following additional extension commands are added
Examining code and stacks
!ThreadState
Examining CLR data structures
!DumpSigElem
Diagnostic Utilities
!VerifyObj
!FindRoots
!HeapStat
!GCWhere
!ListNearObj (lno)
!AnalyzeOOM (ao)
Examining the GC history
!HistInit
!HistStats
!HistRoot
!HistObj
!HistObjFind
!HistClear
!ThreadState Command
When you execute !threads command, you will see the similar output as shown below
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 310 00161438 a020 Enabled 013b4c64:013b5fe8 00159230 1 MTA
2 2 8c4 0016dab0 b220 Enabled 00000000:00000000 00159230 0 MTA (Finalizer)
First column is your debugger thread id and the second column ID is ManagedThread ID, OSID column is OS thread ID so that means OSID column will be 0 or some garbage when a runtime uses Fiber.
You will see the State column which is a bit flag as shown below(taken from Shared CLI)
TS_Unknown = 0×00000000, // threads are initialized this way
TS_AbortRequested = 0×00000001, // Abort the thread
TS_GCSuspendPending = 0×00000002, // waiting to get to safe spot for GC
TS_UserSuspendPending = 0×00000004, // user suspension at next opportunity
TS_DebugSuspendPending = 0×00000008, // Is the debugger suspending threads?
TS_GCOnTransitions = 0×00000010, // Force a GC on stub transitions (GCStress only)
TS_SuspendUnstarted = 0×00400000, // latch a user suspension on an unstarted thread
TS_ThreadPoolThread = 0×00800000, // is this a threadpool thread?
TS_TPWorkerThread = 0×01000000, // is this a threadpool worker thread?
TS_Interruptible = 0×02000000, // sitting in a Sleep(), Wait(), Join()
TS_Interrupted = 0×04000000, // was awakened by an interrupt APC. !!! This can be moved to TSNC
TS_CompletionPortThread = 0×08000000, // Completion port thread
………………………………………………………………………..
SOS in CLR4.0 has !threadstate command, which tells you exactly the state of the thread given the bit field, the following output shows you the threadstate bit for Worker Thread, Completion Port Thread and Finalizer Thread
0:000> !ThreadState 1009220
Legal to Join
Background
CLR Owns
In Multi Threaded Apartment
Thread Pool Worker Thread
0:000> !ThreadState 800a220
Legal to Join
Background
CoInitialized
In Multi Threaded Apartment
Completion Port Thread
0:000> !ThreadState b220
Legal to Join
Background
CLR Owns
CoInitialized
In Multi Threaded Apartment
Other Important Commands
!findroots - This is a very powerful and interesting command, because it allows you to break into debugee when CLR garbage collect generational objects.
!GCWhere - tells you the generation number along with the GC heap segment, you no longer need to map the object address with the GC heap segment or use any other extension dll
!HeapStat- This is another cool command, this command displays the stat on generational heap including generation sizes
!AnalyzeOOM - displays the detailed informatin on Last System.OutOfMemoryException
I can’t do justice on detailed documentation for each of these commands because SOS !help documentation has done a very good job. You can either look at !help documentation or read below. I am just copying and pasting from SOS Help documentation
0:020> !help ThreadState
——————————————————————————-
!ThreadState value
The !Threads command outputs, among other things, the state of the thread.
This is a bit field which corresponds to various states the thread is in.
To check the state of the thread, simply pass that bit field from the
output of !Threads into !ThreadState.
Example:
0:003> !Threads
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 250 0019b068 a020 Disabled 02349668:02349fe8 0015def0 0 MTA
2 2 944 001a6020 b220 Enabled 00000000:00000000 0015def0 0 MTA (Finalizer)
0:003> !ThreadState b220
Legal to Join
Background
CLR Owns
CoInitialized
In Multi Threaded Apartment
Possible thread states:
Thread Abort Requested
GC Suspend Pending
User Suspend Pending
Debug Suspend Pending
GC On Transitions
Legal to Join
Yield Requested
Hijacked by the GC
Blocking GC for Stack Overflow
Background
Unstarted
Dead
CLR Owns
CoInitialized
In Single Threaded Apartment
In Multi Threaded Apartment
Reported Dead
Task Reset
Sync Suspended
Debug Will Sync
Stack Crawl Needed
Suspend Unstarted
Aborted
Thread Pool Worker Thread
Interruptible
Interrupted
Completion Port Thread
Abort Initiated
Finalized
Failed to Start
Detached
0:020> !help DumpSigElem
——————————————————————————-
!DumpSigElem <sigaddr> <moduleaddr>
This command dumps a single element of a signature object. For most circumstances,
you should use !DumpSig to look at individual signature objects, but if you find a
signature that has been corrupted in some manner you can use !DumpSigElem to read out
the valid portions of it.
If we look at a valid signature object for a method we see the following:
0:000> !dumpsig 0×000007fe`ec20879d 0×000007fe`eabd1000
[DEFAULT] [hasThis] Void (Boolean,String,String)
We can look at the individual elements of this object by adding the offsets into the
object which correspond to the return value and parameters:
0:000> !dumpsigelem 0×000007fe`ec20879d+2 0×000007fe`eabd1000
Void
0:000> !dumpsigelem 0×000007fe`ec20879d+3 0×000007fe`eabd1000
Boolean
0:000> !dumpsigelem 0×000007fe`ec20879d+4 0×000007fe`eabd1000
String
0:000> !dumpsigelem 0×000007fe`ec20879d+5 0×000007fe`eabd1000
String
We can do something similar for fields. Here is the full signature of a field:
0:000> !dumpsig 0×000007fe`eb7fd8cd 0×000007fe`eabd1000
[FIELD] ValueClass System.RuntimeTypeHandle
Using !DumpSigElem we can find the type of the field by adding the offset of it (1) to
the address of the signature:
0:000> !dumpsigelem 0×000007fe`eb7fd8cd+1 0×000007fe`eabd1000
ValueClass System.RuntimeTypeHandle
!DumpSigElem will also work with generics. Let a function be defined as follows:
public A Test(IEnumerable<B> n)
The elements of this signature can be obtained by adding offsets into the signature
when calling !DumpSigElem:
0:000> !dumpsigelem 00000000`00bc2437+2 000007ff00043178
__Canon
0:000> !dumpsigelem 00000000`00bc2437+4 000007ff00043178
Class System.Collections.Generic.IEnumerable`1<__Canon>
The actual offsets that you should add are determined by the contents of the
signature itself. By trial and error you should be able to find various elements
of the signature.
0:020> !help VerifyObj
——————————————————————————-
!VerifyObj <object address>
!VerifyObj is a diagnostic tool that checks the object that is passed as an
argument for signs of corruption.
0:002> !verifyobj 028000ec
object 0×28000ec does not have valid method table
0:002> !verifyobj 0680017c
object 0×680017c: bad member 00000001 at 06800184
0:020> !help FindRoots
——————————————————————————-
!FindRoots -gen <N> | -gen any | <object address>
The “-gen” form causes the debugger to break in the debuggee on the next
collection of the specified generation. The effect is reset as soon as the
break occurs, in other words, if you need to break on the next collection you
would need to reissue the command.
The last form of this command is meant to be used after the break caused by the
other forms has occurred. Now the debuggee is in the right state for
!FindRoots to be able to identify roots for objects from the current condemned
generations.
!FindRoots is a diagnostic command that is meant to answer the following
question:
“I see that GCs are happening, however my objects have still not been
collected. Why? Who is holding onto them?”
The process of answering the question would go something like this:
1. Find out the generation of the object of interest using the !GCWhere
command, say it is gen 1:
!GCWhere <object address>
2. Instruct the runtime to stop the next time it collects that generation using
the !FindRoots command:
!FindRoots -gen 1
g
3. When the next GC starts, and has proceeded past the mark phase a CLR
notification will cause a break in the debugger:
(fd0.ec4): CLR notification exception - code e0444143 (first chance)
CLR notification: GC - end of mark phase.
Condemned generation: 1.
4. Now we can use the !FindRoots <object address> to find out the cross
generational references to the object of interest. In other words, even if the
object is not referenced by any “proper” root it may still be referenced by an
older object (from an older generation), from a generation that has not yet been
scheduled for collection. At this point !FindRoots will search those older
generations too, and report those roots.
0:002> !findroots 06808094
older generations::Root: 068012f8(AAA.Test+a)->
06808094(AAA.Test+b)
0:020> !help HeapStat
——————————————————————————-
!HeapStat [-inclUnrooted | -iu]
This command shows the generation sizes for each heap and the total, how much free
space there is in each generation on each heap. If the -inclUnrooted option is
specified the report will include information about the managed objects from the
GC heap that are not rooted anymore.
Sample output:
0:002> !heapstat
Heap Gen0 Gen1 Gen2 LOH
Heap0 177904 12 306956 8784
Heap1 159652 12 12 16
Total 337556 24 306968 8800
Free space: Percentage
Heap0 28 12 12 64 SOH: 0% LOH: 0%
Heap1 104 12 12 16 SOH: 0% LOH:100%
Total 132 24 24 80
0:002> !heapstat -inclUnrooted
Heap Gen0 Gen1 Gen2 LOH
Heap0 177904 12 306956 8784
Heap1 159652 12 12 16
Total 337556 24 306968 8800
Free space: Percentage
Heap0 28 12 12 64 SOH: 0% LOH: 0%
Heap1 104 12 12 16 SOH: 0% LOH:100%
Total 132 24 24 80
Unrooted objects: Percentage
Heap0 152212 0 306196 0 SOH: 94% LOH: 0%
Heap1 155704 0 0 0 SOH: 97% LOH: 0%
Total 307916 0 306196 0
The percentage column contains a breakout of free or unrooted bytes to total bytes.
0:020> !help GCWhere
——————————————————————————-
!GCWhere <object address>
!GCWhere displays the location in the GC heap of the argument passed in.
0:002> !GCWhere 02800038
Address Gen Heap segment begin allocated size
02800038 2 0 02800000 02800038 0282b740 12
When the argument lies in the managed heap, but is not a valid *object* address
the “size” is displayed as 0:
0:002> !GCWhere 0280003c
Address Gen Heap segment begin allocated size
0280003c 2 0 02800000 02800038 0282b740 0
0:020> !help ListNearObj
——————————————————————————-
!ListNearObj <object address>
!ListNearObj is a diagnostic tool that displays the object preceeding and
succeeding the address passed in:
The command looks for the address in the GC heap that looks like a valid
beginning of a managed object (based on a valid method table) and the object
following the argument address.
0:002> !ListNearObj 028000ec
Before: 0×28000a4 72 (0×48 ) System.StackOverflowException
After: 0×2800134 72 (0×48 ) System.Threading.ThreadAbortException
Heap local consistency confirmed.
0:002> !ListNearObj 028000f0
Before: 0×28000ec 72 (0×48 ) System.ExecutionEngineException
After: 0×2800134 72 (0×48 ) System.Threading.ThreadAbortException
Heap local consistency confirmed.
The command considers the heap as “locally consistent” if:
prev_obj_addr + prev_obj_size = arg_addr && arg_obj + arg_size = next_obj_addr
OR
prev_obj_addr + prev_obj_size = next_obj_addr
When the condition is not satisfied:
0:002> !lno 028000ec
Before: 0×28000a4 72 (0×48 ) System.StackOverflowException
After: 0×2800134 72 (0×48 ) System.Threading.ThreadAbortException
Heap local consistency not confirmed.
0:020> !help AnalyzeOOM
——————————————————————————-
!AnalyzeOOM
!AnalyzeOOM displays the info of the last OOM occured on an allocation request to
the GC heap (in Server GC it displays OOM, if any, on each GC heap).
To see the managed exception(s) use the !Threads command which will show you
managed exception(s), if any, on each managed thread. If you do see an
OutOfMemoryException exception you can use the !PrintException command on it.
To get the full callstack use the “kb” command in the debugger for that thread.
For example, to display thread 3’s stack use ~3kb.
OOM exceptions could be because of the following reasons:
1) allocation request to GC heap
in which case you will see JIT_New* on the call stack because managed code called new.
2) other runtime allocation failure
for example, failure to expand the finalize queue when GC.ReRegisterForFinalize is
called.
3) some other code you use throws a managed OOM exception
for example, some .NET framework code converts a native OOM exception to managed
and throws it.
The !AnalyzeOOM command aims to help you with investigating 1) which is the most
difficult because it requires some internal info from GC. The only exception is
we don’t support allocating objects larger than 2GB on CLR v2.0 or prior. And this
command will not display any managed OOM because we will throw OOM right away
instead of even trying to allocate it on the GC heap.
There are 2 legitimate scenarios where GC would return OOM to allocation requests -
one is if the process is running out of VM space to reserve a segment; the other
is if the system is running out physical memory (+ page file if you have one) so
GC can not commit memory it needs. You can look at these scenarios by using performance
counters or debugger commands. For example for the former scenario the “!address
-summary” debugger command will show you the largest free region in the VM. For
the latter scenario you can look at the “Memory\% Committed Bytes In Use” see
if you are running low on commit space. One important thing to keep in mind is
when you do this kind of memory analysis it could an aftereffect and doesn’t
completely agree with what this command tells you, in which case the command should
be respected because it truly reflects what happened during GC.
The other cases should be fairly obvious from the callstack.
Sample output:
0:011> !ao
———Heap 2 ———
Managed OOM occured after GC #28 (Requested to allocate 1234 bytes)
Reason: Didn’t have enough memory to commit
Detail: SOH: Didn’t have enough memory to grow the internal GC datastructures (800000 bytes) -
on GC entry available commit space was 500 MB
———Heap 4 ———
Managed OOM occured after GC #12 (Requested to allocate 100000 bytes)
Reason: Didn’t have enough memory to allocate an LOH segment
Detail: LOH: Failed to reserve memory (16777216 bytes)
0:020> !help FAQ
——————————————————————————-
>> Where can I get the right version of SOS for my build?
If you are running version 1.1 or 2.0 of the CLR, SOS.DLL is installed in the
same directory as the main CLR dll (CLR.DLL). Newer versions of the
Windows Debugger provide a command to make it easy to load the right copy of
SOS.DLL:
“.loadby sos clr”
That will load the SOS extension DLL from the same place that CLR.DLL is
loaded in the process. You shouldn’t attempt to use a version of SOS.DLL that
doesn’t match the version of CLR.DLL. You can find the version of
CLR.DLL by running
“lmvm clr”
in the debugger. Note that if you are running CoreCLR (e.g. Silverlight)
then you should replace “clr” with “coreclr”.
If you are using a dump file created on another machine, it is a little bit
more complex. You need to make sure the mscordacwks.dll file that came with
that install is on your symbol path, and you need to load the corresponding
version of sos.dll (typing .load <full path to sos.dll> rather than using the
.loadby shortcut). Within the Microsoft corpnet, we keep tagged versions
of mscordacwks.dll, with names like mscordacwks_<architecture>_<version>.dll
that the Windows Debugger can load. If you have the correct symbol path to the
binaries for that version of the Runtime, the Windows Debugger will load the
correct mscordacwks.dll file.
>> I have a chicken and egg problem. I want to use SOS commands, but the CLR
isn’t loaded yet. What can I do?
In the debugger at startup you can type:
“sxe clrn”
Let the program run, and it will stop with the notice
“CLR notification: module ‘mscorlib’ loaded”
At this time you can use SOS commands. To turn off spurious notifications,
type:
“sxd clrn”
>> I got the following error message. Now what?
0:000> .loadby sos clr
0:000> !DumpStackObjects
Failed to find runtime DLL (clr.dll), 0×80004005
Extension commands need clr.dll in order to have something to do.
0:000>
This means that the CLR is not loaded yet, or has been unloaded. You need to
wait until your managed program is running in order to use these commands. If
you have just started the program a good way to do this is to type
bp clr!EEStartup “g @$ra”
in the debugger, and let it run. After the function EEStartup is finished,
there will be a minimal managed environment for executing SOS commands.
>> I have a partial memory minidump, and !DumpObj doesn’t work. Why?
In order to run SOS commands, many CLR data structures need to be traversed.
When creating a minidump without full memory, special functions are called at
dump creation time to bring those structures into the minidump, and allow a
minimum set of SOS debugging commands to work. At this time, those commands
that can provide full or partial output are:
CLRStack
Threads
Help
PrintException
EEVersion
For a minidump created with this minimal set of functionality in mind, you
will get an error message when running any other commands. A full memory dump
(obtained with “.dump /ma <filename>” in the Windows Debugger) is often the
best way to debug a managed program at this level.
>> What other tools can I use to find my bug?
Turn on Managed Debugging Assistants. These enable additional runtime diagnostics,
particularly in the area of PInvoke/Interop. Adam Nathan has written some great
information about that:
http://blogs.msdn.com/adam_nathan/
>> Does SOS support DML?
Yes. SOS respects the .prefer_dml option in the debugger. If this setting is
turned on, then SOS will output DML by default. Alternatively, you may leave
it off and add /D to the beginning of a command to get DML based output for it.
Not all SOS commands support DML output.
0:020> !help HistInit
——————————————————————————-
!HistInit
Before running any of the Hist - family commands you need to initialize the SOS
structures from the stress log saved in the debuggee. This is achieved by the
HistInit command.
Sample output:
0:001> !HistInit
Attempting to read Stress log
STRESS LOG:
facilitiesToLog = 0xffffffff
levelToLog = 6
MaxLogSizePerThread = 0×10000 (65536)
MaxTotalLogSize = 0×1000000 (16777216)
CurrentTotalLogChunk = 9
ThreadsWithLogs = 3
Clock frequency = 3.392 GHz
Start time 15:26:31
Last message time 15:26:56
Total elapsed time 25.077 sec
……………………………….
—————————- 2407 total entries —————————–
SUCCESS: GCHist structures initialized
0:020> !help HistStats
——————————————————————————-
!HistStats
HistStat provides a number of garbage collection statistics obtained from the
stress log.
Sample output:
0:003> !HistStats
GCCount Plugs Promotes Relocs
———————————–
2296 0 35 86
2295 0 34 85
2294 0 34 85
…
2286 0 32 83
2285 0 32 83
322 0 23 55
0 0 0 0
Root 01e411b8 relocated multiple times in gc 322
Root 01e411bc relocated multiple times in gc 322
…
Root 01e413f8 relocated multiple times in gc 322
Root 01e413fc relocated multiple times in gc 322
0:020> !help histroot
——————————————————————————-
!HistRoot <root>
The root value obtained from !HistObjFind can be used to track the movement of
an object through the GCs.
HistRoot provides information related to both promotions and relocations of the
root specified as the argument.
0:003> !HistRoot 01e411b8
GCCount Value MT Promoted? Notes
———————————————————
2296 028970d4 5b6c5cd8 yes
2295 028970d4 5b6c5cd8 yes
2294 028970d4 5b6c5cd8 yes
2293 028970d4 5b6c5cd8 yes
2292 028970d4 5b6c5cd8 yes
2291 028970d4 5b6c5cd8 yes
2290 028970d4 5b6c5cd8 yes
2289 028970d4 5b6c5cd8 yes
2288 028970d4 5b6c5cd8 yes
2287 028970d4 5b6c5cd8 yes
2286 028970d4 5b6c5cd8 yes
2285 028970d4 5b6c5cd8 yes
322 028970e8 5b6c5cd8 yes Duplicate promote/relocs
…
0:020> !help HistObj
——————————————————————————-
!HistObj <obj_address>
This command examines all stress log relocation records and displays the chain
of GC relocations that may have led to the address passed in as an argument.
Conceptually the output is:
GenN obj_address root1, root2, root3,
GenN-1 prev_obj_addr root1, root2,
GenN-2 prev_prev_oa root1, root4,
…
Sample output:
0:003> !HistObj 028970d4
GCCount Object Roots
———————————————————
2296 028970d4 00223fc4, 01e411b8,
2295 028970d4 00223fc4, 01e411b8,
2294 028970d4 00223fc4, 01e411b8,
2293 028970d4 00223fc4, 01e411b8,
2292 028970d4 00223fc4, 01e411b8,
2291 028970d4 00223fc4, 01e411b8,
2290 028970d4 00223fc4, 01e411b8,
2289 028970d4 00223fc4, 01e411b8,
2288 028970d4 00223fc4, 01e411b8,
2287 028970d4 00223fc4, 01e411b8,
2286 028970d4 00223fc4, 01e411b8,
2285 028970d4 00223fc4, 01e411b8,
322 028970d4 01e411b8,
0 028970d4
0:020> !help HistObjFind
——————————————————————————-
!HistObjFind <obj_address>
To examine log entries related to an object whose present address is known one
would use this command. The output of this command contains all entries that
reference the object:
0:003> !HistObjFind 028970d4
GCCount Object Message
———————————————————
2296 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
2296 028970d4 Relocation NEWVALUE for root 00223fc4
2296 028970d4 Relocation NEWVALUE for root 01e411b8
…
2295 028970d4 Promotion for root 01e411b8 (MT = 5b6c5cd8)
2295 028970d4 Relocation NEWVALUE for root 00223fc4
2295 028970d4 Relocation NEWVALUE for root 01e411b8
…
0:020> !help HistClear
——————————————————————————-
!HistClear
This command releases any resources used by the Hist-family of commands.
Generally there’s no need to call this explicitly, as each HistInit will first
cleanup the previous resources.
visual studio 2008 memory leak/memory issue on x86 - the operation could not be completed.Not enough storage is available to complete this operation
Friday, July 3rd, 2009And No I don’t have a solution for it and probably the only workaround is to make your visual studio Large Address Aware(3GB switch) on x86.

Steps to re-create
1. download and unzip http://debuggingblog.com/resources/transcripts.zip
2. open, close the xml file and try to load it the second time
3. If you load the xml file using IE8, you will see the followings once you close it
——————– State SUMMARY ————————–
TotSize ( KB) Pct(Tots) Usage
19e6f000 ( 424380) : 20.24% : MEM_COMMIT
f3b4000 ( 249552) : 11.90% : MEM_FREE
56dcd000 ( 1423156) : 67.86% : MEM_RESERVE
Almost 1.4 GB Memory allocated in GC Segements for xml file is still reserved even after unloading the xml file.
However, visual studio 2008 is another story
0:000> !eeheap -gc
ephemeral segment allocation context: none
segment begin allocated size
01830000 01831000 027ecadc 0×00fbbadc(16497372)
12860000 12861000 137616c4 0×00f006c4(15730372)
………………………………………………………………………………..
We have bunch of 16MB GC segments and most of the objects are in gen 2.
0c55d1ec 739459 85777244 Microsoft.XmlEditor.XmlElement
0c559858 1496448 89786880 Microsoft.XmlEditor.Identifier
001f1918 105303 97472784 Free
793308ec 2369315 387475460 System.String
Total 9375571 objects
we have 90+ MB of free blocks and 380+MB in System.String. There are 2.36 million string objects, yeah so you don’t wanna pick each one of the string object to find GC root unless Microsoft or someone is paying you a dime to dump each object and aha a dump a day will make your day for sure.
0:000> !dumpheap -mt 0c9d4134
Address MT Size
018f241c 0c9d4134 68
5f610108 0c9d4134 68
total 2 objects
Statistics:
MT Count TotalSize Class Name
0c9d4134 2 136 Microsoft.XmlEditor.XmlDocumentProperties
Total 2 objects
0:000> !objsize 018f241c
sizeof(018f241c) = 507372388 ( 0×1e3de364) bytes (Microsoft.XmlEditor.XmlDocumentProperties)
0:000> !objsize 5f610108
sizeof(5f610108) = 507371128 ( 0×1e3dde78) bytes (Microsoft.XmlEditor.XmlDocumentProperties)
Did you just see that almost 1GB of virtual memory rooted in Microsoft.XmlEditor.XmlDocumentProperties? That’s just outrageous, I mean why would microsoft visual studio take up 1.2 GB of virtual memory to open a 58MB file, although It does make use of schema context cache.
0:000> !gcroot -nostacks 018f241c
DOMAIN(001EC570):HANDLE(RefCnt):16d1b20:Root:018f241c(Microsoft.XmlEditor.XmlDocumentProperties)
GCHandle of type RefCnt is keeping reference to Microsoft.XmlEditor.XmlDocumentProperties
There is an OutOfMemoryException thrown with the following callstack
Exception object: 5ed00a34
Exception type: System.OutOfMemoryException
Message: Insufficient memory to continue the execution of the program.
InnerException: <none>
StackTrace (generated):
SP IP Function
0012F5A0 0C97E8B3 Microsoft_VisualStudio_Package_LanguageService_9_0!Microsoft.VisualStudio.NativeMethods.ThrowOnFailure(Int32, Int32[])+0×3b
0012F5AC 0C9E94BB Microsoft_VisualStudio_Package_LanguageService_9_0!Microsoft.VisualStudio.Package.Source.GetText()+0×3c
0012F5DC 0C9E9360 Microsoft_VisualStudio_Package_LanguageService_9_0!Microsoft.VisualStudio.Package.Source.BeginParse()+0×55
0012F644 0C9ECF38 Microsoft_VisualStudio_Package_LanguageService_9_0!Microsoft.VisualStudio.Package.Source.OnIdle(Boolean)+0×80
0012F654 0C9ECE28 Microsoft_VisualStudio_Package_LanguageService_9_0!Microsoft.VisualStudio.Package.LanguageService.OnIdle(Boolean)+0xd8
0012F674 0C9ECCDD Microsoft_XmlEditor!Microsoft.XmlEditor.XmlLanguageService.OnIdle(Boolean)+0×35
0012F684 0C9ECC34 Microsoft_XmlEditor!Microsoft.XmlEditor.Package.FDoIdle(UInt32)+0xc4
Conclusion
I hope this is fixed in Visual Studio 2010, I do need to try it out.
why is my System.ServiceModel.OperationContext null from silverlight client and the SOAP Message Header - note to me
Monday, June 29th, 2009When you are starting out with Silverlight and WCF/SOAP to implement WS-Security using SOAP headers into request messages or for that matter if you are accessing SOAP services from silverlight, you may run into this silly issue that’s why I am making note of it here.
Silverlight documentation clearly says that
SOAP headers are supported via the OutgoingMessageHeaders and IncomingMessageHeaders properties inside an operation method call.
OutgoingMessageHeaders is the outgoing message headers for the active OperationContext.
Use the OperationContext from within a service operation to access the current operation execution environment.
The OperationContext has the following properties and methods.
- The Current property returns the OperationContext object that represents the current execution context.
Documentation is not very clear so this is when you may run into this issue because OperationContext is null if you directly access OperationContext.Current from silverlight client.
Let’s look at OperationContext .Current setter to find out who sets it, as shown below in reflector snapshot. Now you know OperationContextScope sets the Context so you have to first create OperationContextScope using your ContextChannel before accessing the current Operation Execution Environment.
using (OperationContextScope contextScope = new OperationContextScope(client.InnerChannel))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader
}
Tess Blog - First look at debugging .NET 4.0 dumps in Visual Studio 2010
Wednesday, June 17th, 2009First look at debugging .NET 4.0 dumps in Visual Studio 2010
Tess talks about debugging a memory dump generated in .NET 4.0 using VS2010.
And Wow, VS 2010 supports post mortem debugging for managed application and as Tess mentioned you no longer need to learn WinDbg/SOS for some of the common debugging scenarios. VS2010 also has source server support and along with intutive debugging environment, VS2010 is a big step forward to integrate mixed mode debugging in it.
presentation slides @ portland .net user group are published
Wednesday, June 10th, 2009Silverlight App not working as expected in FireFox, IE shows error message “Unhandled Error in Silverlight 2 Application - Element is already the child of another element”
Monday, June 8th, 2009Problem Description
This exception is thrown in a Silverlight 2 App while trying to show and hide System.Windows.Controls.TabItem in System.Windows.Controls.TabControl
Steps to Recreate
browse to http://debuggingblog.com/sl/project1/default.html and click on button “Show Angelina” 3 times
Debugging Silverlight app using WinDbg
We will be analyzing a memory dump of IE on System.InvalidOperationException
1. We have the following two InvalidOperationException exception objects on managed heap
0:007> !dumpheap -type System.InvalidOperationException
Address MT Size
1013c79c 0f1ff824 72
1015addc 0f1ff824 72
total 2 objects
Statistics:
MT Count TotalSize Class Name
0f1ff824 2 144 System.InvalidOperationException
Total 2 objects
2. Lets get the stack trace when this exception occured
0:007> !pe 1013c79c
Exception object: 1013c79c
Exception type: System.InvalidOperationException
Message: Element is already the child of another element.
InnerException: <none>
StackTrace (generated):
SP IP Function
021FF640 0F40F06A !MS.Internal.XcpImports.CheckHResult(UInt32)+0×32
021FF64C 0E3A4CE9 !MS.Internal.XcpImports.SetValue(MS.Internal.INativeCoreTypeWrapper, System.Windows.DependencyProperty, System.Windows.DependencyObject)+0xa9
021FF680 0E3A4118 !MS.Internal.XcpImports.SetValue(MS.Internal.INativeCoreTypeWrapper, System.Windows.DependencyProperty, System.Object)+0×100
021FF71C 0E3A3FBC !System.Windows.DependencyObject.SetObjectValueToCore(System.Windows.DependencyProperty, System.Object)+0×1c4
021FF760 0E3A1CBB !System.Windows.DependencyObject.SetValueInternal(System.Windows.DependencyProperty, System.Object, Boolean, Boolean, Boolean)+0×503
021FF834 0E3A17A1 !System.Windows.DependencyObject.SetValueInternal(System.Windows.DependencyProperty, System.Object)+0×21
021FF848 0E3A1763 !System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty, System.Object)+0×1b
021FF85C 0E3D68D7 !System.Windows.Controls.ContentControl.set_Content(System.Object)+0×37
021FF870 0E3212CF !SilverlightApplication1.Page.ShowContent()+0×57
021FF880 0E3208BE !SilverlightApplication1.Page.ShowHideAngelina_Click(System.Object, System.Windows.RoutedEventArgs)+0×76
021FF898 0E4099B5 !System.Windows.Controls.Primitives.ButtonBase.OnClick()+0×5d
021FF8B0 0E40993F !System.Windows.Controls.Button.OnClick()+0×47
021FF8C0 0E40986D !System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs)+0×85
021FF8D0 0E4097D1 !System.Windows.Controls.Control.OnMouseLeftButtonUp(System.Windows.Controls.Control, System.EventArgs)+0×41
021FF8E0 0E36C887 !MS.Internal.JoltHelper.FireEvent(IntPtr, IntPtr, Int32, System.String)+0×1b7
3. This exception occured while trying to Set the Content of a Control, so lets find out what is this content and who holds this UIElement, lets get the IL of method SilverlightApplication1.Page.ShowContent()
0:007> !dumpil 0f224060
ilAddr = 0f4607f8
IL_0000: ldarg.0
IL_0001: newobj System.Windows.Controls.TabItem::.ctor // A new TabItem object is created
IL_0006: stfld SilverlightApplication1.Page::item
IL_000b: ldarg.0
IL_000c: ldfld SilverlightApplication1.Page::item
IL_0011: ldstr “Angelina Jolie”
IL_0016: callvirt System.Windows.Controls.TabItem::set_Header
IL_001b: ldarg.0
IL_001c: ldfld SilverlightApplication1.Page::item//Get the reference to a TabItem object created earlier
IL_0021: ldarg.0
IL_0022: ldfld SilverlightApplication1.Page::content
IL_0027: callvirt System.Windows.Controls.ContentControl::set_Content //Set_Content is called with SilverlightApplication1.Page object’s data member content
IL_002c: ldarg.0
IL_002d: ldfld SilverlightApplication1.Page::TabList
IL_0032: callvirt System.Windows.Controls.ItemsControl::get_Items
IL_0037: ldarg.0
IL_0038: ldfld SilverlightApplication1.Page::item
We have 2 interesting objects TabItem and SilverlightApplication1.Page::content here
4. First get the address of SilverlightApplication1.Page::content object which is being set in TabItem because that’s what resulting in exception
0:007> !do 1003b3c0
Name: SilverlightApplication1.Page
Fields:
MT Field Offset Type VT Attr Value Name
0f42e730 400000d 58 …Windows.UIElement 0 instance 1011c0e8 content
0:007> !dumpheap -mt 0e396648
Address MT Size
1003ed3c 0e396648 140
101276a0 0e396648 140
1013c050 0e396648 140
total 3 objects
Statistics:
MT Count TotalSize Class Name
0e396648 3 420 System.Windows.Controls.TabItem
Total 3 objects
We have 3 TabItem objects on heap and the address of the content object(UIElement) is 1011c0e8
5. The next step to find out is which TabItem object has this UIElement and why is this TabItem object still around.
0:007> !dumpheap -mt 0e396648
Address MT Size
1003ed3c 0e396648 140
101276a0 0e396648 140
1013c050 0e396648 140
total 3 objects
0:007> !do 101276a0
Name: System.Windows.Controls.TabItem
MethodTable: 0e396648
EEClass: 0e3bb768
Size: 140(0×8c) bytes
File: System.Windows.Controls, Version=2.0.5.0, Culture=neutral
Fields:
MT Field Offset Type VT Attr Value Name
0ec444e8 40002b4 34 System.Object 0 instance 1011c0e8 _treeContent
0:007> !gcroot 101276a0
Note: Roots found on stacks may be false positives. Run “!help gcroot” for
more info.
Scan Thread 7 OSTHread 1710
Scan Thread 27 OSTHread 1200
Scan Thread 28 OSTHread 1278
Scan Thread 31 OSTHread 1488
6. TabItem object with address = 0e396648 has the reference to content object 1011c0e8 and this object is not rooted so that means this object is ready to be garbage collected.
There is already a TabItem object on managed heap holding reference to the same content object which is being assigned to new TabItem object on SilverlightApplication1.Page.ShowHideAngelina_Click(), that’s why we get System.InvaildOperationException with the error message “Element is already the child of another element”
7. You can get the address of Method Description for each of the methods in SilverlightApplication1.Page
0:007> !dumpmt -md 0f224094
————————————–
MethodDesc Table
Entry MethodDesc JIT Name
0e320848 0f224038 JIT SilverlightApplication1.Page.ShowHideAngelina_Click(System.Object,
0e321300 0f224058 JIT SilverlightApplication1.Page.HideContent()
0e321278 0f224060 JIT SilverlightApplication1.Page.ShowContent()
Let’s look at the implementation of ShowHideAngelina_Click
0:007> !dumpil 0f224038
ilAddr = 0f46071c
IL_0012: ldstr “Show”
IL_0017: callvirt System.String::Contains
IL_001c: brfalse.s IL_003f
IL_001e: ldloc.0
IL_0039: call SilverlightApplication1.Page::ShowContent
IL_003e: ret
IL_003f: ldloc.0
IL_004a: ldarg.0
IL_004b: call SilverlightApplication1.Page::HideContent
IL_0050: ret
This method checks the Text of the button and calls ‘ShowContent’ if the text =“Show” otherwise calls ‘HideContent’, so let’s look at HideContent implementation
0:007> !dumpil 0f224058
ilAddr = 0f4607d6
IL_0000: ldarg.0
IL_0001: ldfld SilverlightApplication1.Page::item
IL_0006: brfalse.s IL_001f
IL_0008: ldarg.0
IL_0009: ldfld SilverlightApplication1.Page::TabList
IL_000e: callvirt System.Windows.Controls.ItemsControl::get_Items
IL_0013: ldarg.0
IL_0014: ldfld SilverlightApplication1.Page::item
IL_0019: callvirt class [System.Windows]System.Windows.PresentationF◆䷒¥⽫Ż�::Remove
IL_001e: pop
IL_001f: ret
HideContent calls TabList.get_Items and remove the TabItem from System.Windows.Control.TabControl
Resolution
HideContent() method removes the TabItem from TabControl.Items so unless TabItem is Garbage Collected removed TabItem will still hold the reference to Content UIElement. You can quickly fix this issue by assiging Content = null, when that item is removed as shown below in HideContent
//OLD Buggy Implementation
private void HideContent()
{
if (item != null)
this.TabList.Items.Remove(item);
}
//new implementation to make sure Content is set to null
private void HideContent()
{
item.Content = null; //assign TabItem Content = NULL
if (item != null)
this.TabList.Items.Remove(item);
}
Unhandled Error in Silverlight 2 Application - Invalid or malformed application: Check manifest
Sunday, June 7th, 2009This error is very silly and obviously there is something wrong with the Manifest file as shown below
Webpage error details
Message: Unhandled Error in Silverlight 2 Application
Code: 2103
Category: InitializeError
Message: Invalid or malformed application: Check manifest
Code: 0
URI:
But if this helps anyone, i would like to point out that When you create a silverlight application using visual studio, it copies XAP package in ‘ClientBin” folder. You can either unzip the .XAP file to look at AppManifest.xaml or if you have access to source code then you can direcly open “AppManifest.xaml” file from bin/<> folder.
Make sure these entries are correct
<Deployment
EntryPointAssembly=”SilverlightApplication1”
EntryPointType=”SilverlightApplication1.App” //this should be same as your “Namespace.Application” class
RuntimeVersion=”2.0.31005.0″>
<Deployment.Parts>
<AssemblyPart x:Name=”SilverlightApplication1″ Source=”SilverlightApplication1.dll” (make sure that, this is the output dll you have in your project configuration)/>
</Deployment.Parts>
</Deployment>
By default, app.xaml will have the application class=”App”, i have changed it to “MyControl” as shown below so if you are using visual studio and you have renamed your project or App class make sure to make the corresponding changes in Project Configuration (assembly name, startup project)
public class MyControl: Application
{
public App()
{
this.RootVisual = new Page();
}
}
Dissecting Silverlight Control/XAP package and How to create a barebone silverlight application - Silverlight wins hands down over ADOBE AIR/Flash in some areas
Friday, June 5th, 2009When you use visual studio to create a silverlight application, you will notice that it creates the application xaml, page xaml and their corresponding code behinds. When you build the application, xap package will be created inside ‘ClientBin” folder along with a test page.
I will show you how to create a silverlight xap package without visual studio with a very simple control to help you understand how silverlight control essentially works. In my previous post I mentioned how a browser based on http response loads Silverlight Plug-in(NPCTRL.DLL) with MIME type=”application/x-silverlight-2″ specified in object tag.
Let’s first look at Silverlight Application Project which gets created by default using Silverlight Application project template in visual studio. It creates the following files in a silverlight application project
-Properties
—AppManifest.xml
—AssemblyInfo.cs
-App.xaml
—App.xaml.cs
-Page.xaml
—Page.xaml.cs
AppManifest.xml contains the XAML object elements Deployment and Depolyment Parts which is used to build application package’s manifest file. When AppManifest xaml file is generated for XAP package, it also includes the followings
< EntryPointAssembly=”MySilverlightControl”
EntryPointType=”MySilverlightControl”
RuntimeVersion=”2.0.31005″>
<AssemblyPart x:Name=”XName” Source=”MySilverlightControl.dll” />
EntryPointAssembly/Type and the Assembly Part are mandatory in a Silverlight Application because that’s how coreservices determines the entry point in an assembly.
App.xaml.cs implements the followings
public partial class App : Application
{
public App()
{
this.Startup += this.Application_Startup;
this.Exit += this.Application_Exit;
this.UnhandledException += this.Application_UnhandledException;
InitializeComponent();
}
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new Page();
}
private void Application_Exit(object sender, EventArgs e)
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e)
Application class is essentially adding the event listener to AGCORE.DLL through Managed Runtime and sets the root as Page object in a visual tree. Below is the implementation of InitializeComponent
public void InitializeComponent() { if (!this._contentLoaded) { this._contentLoaded = true; Application.LoadComponent(this, new Uri("/MyControl;component/App.xaml", UriKind.Relative)); } } |
InitializeComponent implementation will fool you into believing that you will need xaml file. But you don’t even need to call InitializeComponent unless of course you are using designer generated code, behind the scene designed generates the source code for xaml file
So far, we have seen that silverlight project has an App class which derives from System.Windows.Application and apart from setting the event listeners for error handling and etc, it just sets the visual root to a Page object which is nothing but System.Windows.Control.UserControl deriving from System.Windows.Controls.Control ..and Control in turn from UIElement.
When you build the project, it will create a xap pacakge which is nothing but just a ZIP file. XAP package includes assemblies and the application manifest XAML file and that’s what get hosted in a web page
Let’s put these pieces together
1. We need a web server which can support MIME Type=application/x-silverlight-2 to serve silverlight content
2. web page hosts silverlight control by including a XAP package in object tag
3. XAP package is a zip archive format which includes application manifest(xaml file) and a managed assembly
4. managed assembly should have System.Windows.Application object
5. Application object needs a visual root tree which could be any control/UIElement
6. and of course managed assembly will need silverlight runtime
Steps to create a barebone Silverlight Control with no visual studio or xaml
1. Open your notepad and type the followings to create your barebone silverlight control deriving from System.Windows.Application and save it as MySilverlightControl.cs
public class MySilverlightControl : System.Windows.Application
{
//constructor
public MySilverlightControl()
{
//create a textblock control and assign a width,height with text =”hello silverlight”
System.Windows.Controls.TextBlock txtBlock = new System.Windows.Controls.TextBlock();
txtBlock.Text = “Hello Silverlight”;
txtBlock.Width = 800;
txtBlock.Height = 600;
//make sure it is centered
txtBlock.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
txtBlock.VerticalAlignment = System.Windows.VerticalAlignment.Center;
//margin (left,top,..)
txtBlock.Margin = new System.Windows.Thickness(400, 300, 0, 0);
txtBlock.FontSize = 24;
//set the application visual root to txtblock control
this.RootVisual = txtBlock;
}
}
2. Launch command prompt to compile this file to create a MySilverlightControl.dll
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc /target:library MySilverlightControl.csc.exe /reference:”C:\Program Files\Microsoft Silverlight\2.0.40115.0\System.Windows.dll”
3. Type the followings in a notepad to create application manifest xaml file
<Deployment xmlns=”http://schemas.microsoft.com/client/2007/deployment”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
EntryPointAssembly=”MySilverlightControl”
EntryPointType=”MySilverlightControl”
RuntimeVersion=”2.0.31005″>
<Deployment.Parts>
<AssemblyPart x:Name=”XName” Source=”MySilverlightControl.dll” />
</Deployment.Parts>
</Deployment>
Rememeber these attributes are mandatory in a silverlight application assembly but not in a class library. I have copied Runtime Version from http://msdn.microsoft.com/en-us/library/cc265156(VS.95).aspx
The above URL describes the MIME type and their corresponding silverlight runtime version. EntryPointAssembly and the other attributes are self explanatory and that’s what will be used by coreservices.
4. Zip those 2 files AppManifest.xaml and MySilverlightControl.dll with .xap extension
5. Create the following html file and copy it under the same folder as .xap file
<html>
<head>
<title>Barebones - Silverlight Control Testing</title>
</head>
<body>
<div id=”silverlightControlHost”>
<object data=”data:application/x-silverlight-2,” type=”application/x-silverlight-2″ width=”100%” height=”100%”>
<param name=”source” value=”MySilverlightControl.xap”/>
</object>
</div>
</body>
</html>
Below is the snapshot

This is it and your silverlight control is ready to be hosted.
Obviously, you don’t need to manually create it, but this is an attempt to explain how silverlight works and what are the components involved in a silverlight control. You can dynamically generate a code or even use Reflection.Emit to generate MSIL and above all host your content on any webserver with mime type=”application/x-silverlight-2″ for silverlight 2 runtime.
This makes Silverlight very powerful and at the same time very simple to implement and silverlight coreclr has great debugging tool in WinDbg/CoreCLR!SOS.
Kudos to Microsoft Silverlight team.
silverlight is very appealing when it comes to out of browser experience and the development platform. Of course there are some limitations in silverlight app because it runs in security sandbox model so that means no access to filesystem but the development platform along with deployment makes a great case for consideration if you are thinking about using Adobe Flash/AIR
Dissecting Silverlight and CoreCLR Runtime on Windows OS using WinDbg – Silverlight Plugin and Silverlight .NET runtime explained
Thursday, June 4th, 2009The purpose of this article is to demonstrate the use of WinDbg to demonstrate request processing in Silverlight Runtime
We need fiddler , WinDbg and a browser in Windows OS. We have a simple html page hosted in IIS with a Silverlight control in it as shown below
<html><head> <title>SilverlightApplication1</title></head>
<body> <div id=”silverlightControlHost”>
<object data=”data:application/x-silverlight-2,” type=”application/x-silverlight-2″>
<param name=”source” value=”ClientBin/SilverlightApplication1.xap”/>
</object> </div></body></html>
Attach browser to WinDbg, if you are using IE8 then make sure that you are attaching the child process (tabbed browser), use process explorer to identify the child process.
Execute command “.cmdtree <pathname>sld.txt” as shown below; you can download sld.txt from here as shown below

Silverlight runtime by default gets installed under <system drive> \Program Files\Microsoft Silverlight\<version #>
As shown below

We will be interested more in native dll which makes up of Silverlight runtime. .NET library is part of Silverlight CoreCLR.
In order to get the order of the loaded modules of Silverlight runtime, we can execute command “sxe ld” or you can double click on “Break On Loaded Modules” from command tree and browse to html page containing Silverlight xap file.
You need to ignore most of the dlls but the one loaded from “C:\Program Files\Microsoft Silverlight\2.0.40115.0” (Silverlight runtime path on my machine). The order of loaded modules is
Npctrl.dll, agcore.dll, coreclr.dll, .net dlls
You can use any disassembler or ndepends to look at the exported functions or download one from http://www.smidgeonsoft.prohosting.com/pebrowse-pro-file-viewer.html to look at these native dlls
Below is the snapshot for NPCTRL.DLL

NPCTRL.dll is a COM dll which gets loaded in browser when http request is made with silverlight control in it(object tag). Shown below in the fiddler
Browser determines this based on http response since the MIME type in html file is
type=”application/x-silverlight-2″. NPCTRL.dll gets loaded as Silverlight Plug-in.
This occurs before XAP package gets downloaded,

As shown below, you can now clear breakpoints on loaded modules and set breakpoint for each of dll one by one because debugger remembers the last ld settings.

You may want to change the symbols path to Silverlight runtime so that you can set breakpoints on all exported methods (see the above snapshot).
NPCTRL.DLL imports followings from AGCORE.DLL

NPCTRP.DLL first loads AGCORE.DLL. NPCTRL.dll implements CXcpBrowserHost/CommonBrowserHost and it makes a call to agcore!ObtainCoreServices to set the frameworkcallbacks. NPCTRL.DLL also implements CWindowsServices::CreateCLRRuntimeHost. NPCTRL.dll calls NPCTRL!GetCLRRuntTimeHost to load CORECLR.dll . CORECLR.dll is our Silverlight .NET runtime engine, basically stripped down version of MSCORWKS.dll

Once CLRRuntime is created, coreclr will create a domain and load the .net assembly as a private copy using normal assembly binding. CORECLR will use PEImage layout to map the view of file same as .net runtime. Below is the call stack when application domain for coreclr is set up
0220f4d4 04a9b399 System.Activator.CreateInstance(System.String, System.String)
0220f4e8 04a9b349 System.AppDomain.CreateInstance(System.String, System.String)
0220f504 04a9b298 System.AppDomain.CreateInstanceAndUnwrap(System.String, System.String)
0220f51c 04a9b1d8 System.AppDomain.CreateDomainManager(System.String, System.String)
0220f560 04a94d6a System.AppDomain.SetDomainManager(System.Security.Policy.Evidence, System.Security.Policy.Evidence, IntPtr, Boolean)
0220f5b0 04a98dfd System.AppDomain.Setup(System.Object)
Once app domain is set up, ManagedRuntimeHost will be created as shown below from the reflector

This is when coreclr will also set up System.Windows.Threading.DispatcherSynchronizationContext for Single Threaded Apartment (UI). At this point, it will also create a callback handler in AGCORE.DLL. AGCORE.DLL is the Unmanaged version of Silverlight. AGCORE.DLL implements event listener, Setting the visual root and the callback handler is used for communication between CORECLR and AGCORE.
The main interface for communication between CORECLR and AGCORE is MS.Internal.XcpImports(implemented in System.Windows.DLL) XcpImports is the interop layer importing the exports section in AGCORE.dll


Once XcpImports.SetFrameworkCallbacksNative is called to set the callback handler, MS.Internal.FrameworkCallbacks will create System.Windows.DependencyObject.
After dependency object is created, Application object will be created as shown below
0220f2e4 0108008d SilverlightApplication1.App..ctor()
0220f850 026b2e90 System.Reflection.ConstructorInfo.Invoke(System.Object[])
0220f860 026b2a98 MS.Internal.TypeProxy.CreateInstance(UInt32)
.net library will be responsible for creating the visual tree and passing the buffer into agcore.dll native code and so on.
when does XAP package get downloaded?
Once NPCTRL.DLL and AGCORE.DLL are loaded, NPCTRL!CommonBrowserHost implements (shown below) npctrl!CommonBrowserHost::OnGotSourceDownloadResponse and this will make a call into agcore!CCoreServices::StartDeploymentTree which in turn calls agcore!CCoreServices::CLR_Startup and finally this will be routed to npctrl!CWindowsServices::CreateCLRRuntimeHost to load CORECLR.DLL, see below for the callstack
kernel32!LoadLibraryW - Will load CORECLR.DLL
npctrl!GetCLRRuntimeHost
npctrl!CWindowsServices::CreateCLRRuntimeHost
agcore!CCLRHost::Initialize
agcore!CRuntimeHost::Initialize
agcore!CCoreServices::CLR_Startup
agcore!CDeployment::Start
agcore!CCoreServices::StartDeploymentTree
npctrl!CXcpBrowserHost::put_Source
npctrl!CommonBrowserHost::OnGotSourceDownloadResponsetype=”application/x-silverlight-2″