SOS is a debugger extension used to debug managed code. As a debugging extension, it must be loaded into a Win32-compliant debugger, such as WinDbg. SOS can provide information about the inner workings of a managed application. This might require that the user have a better understanding of the internal workings and structures of the CLR. SOS abstracts as much of the details as possible, allowing you to concentrate on the problem—debugging the application. When using a debugging extension, the debugger and debugging extension collaborate. Without a doubt, you will rely on both to resolve any application bugs.
Any of the following statements loads the SOS.dll debugging extension. To load a particular version of SOS, provide the fully qualified directory path. Here are some examples of loading SOS:
.load sos
.load sos.dll
.load c:pathsos.dll
You might have multiple versions of the .NET Framework installed on your computer. There also will be comparable versions of SOS.dll—one for each version of the .NET Framework. The following command loads the correct version of SOS.dll for the appropriate version of the CLR:
.loadby sos mscorwks
This example provides an introduction to SOS. Some of the output from the example has been shortened for clarity.
Start the Store application in the sos subfolder outside a debugger. Only one debugger can be attached to an application at any time. Open the Transaction dialog box, as shown in Figure 16-3. Do not complete or close this dialog box.
Start the WinDbg debugger and attach to the Store application. Load SOS.
Enter the !threads command, which lists the managed threads and related information. Here is the abbreviated result:
0:004> !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
0 1 424 001501f8 6020 Enabled 013da5dc:013dadb8 001483a8 0
2 2 c24 00153e40 b220 Enabled 00000000:00000000 001483a8 0
Change to Thread 0, which is a managed thread. This is a native WinDbg command:
0:004> ~0s
eax=790ff90c ebx=01392b50 ecx=013a7704 edx=0000ce7d esi=00000000 edi=013da5b8
eip=7c90eb94 esp=0012edb4 ebp=0012ee4c iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!KiFastSystemCallRet:
7c90eb94 c3 ret
Enter the !clrstack command to display the stack trace for thread 0. The -p option shows the parameters for each method:
0:000> !clrstack -p
OS Thread Id: 0x424 (0)
ESP EIP
0012edc0 7c90eb94 [InlinedCallFrame: 0012edc0] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0012edbc 7b094838 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
PARAMETERS:
this = 0x013a76ac
dwComponentID = <no data>
reason = 0x00000004
pvLoopData = 0x00000000
0012eef8 7b22e03e System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
PARAMETERS:
this = 0x013b4494
owner = <no data>
The ShowDialog method and its parameters appear in the stack trace. The this reference is the first parameter of the method. The address of the this reference is provided. Use the dumpobj command to dump the this reference with this address. The output shows the identity of the this object as a Store.Transaction type. From the fields of Store.Transaction, it appears that Store.Transaction is a form:
0:000> !dumpobj 0x013b4494
Name: Store.Transaction
MethodTable: 00d453a4
EEClass: 00db3034
Size: 372(0x174) bytes
(C:storeStore.exe)
Fields:
MT Field Offset Type VT Attr Value Name
790fa098 4000184 4 System.Object 0 instance 00000000 __identity
7a765ca4 40008bc 8 ...ponentModel.ISite 0 instance 00000000 site
7a762e84 40008bd c ....EventHandlerList 0 instance 013b6964 events
790fa098 40008bb 108 System.Object 0 static 00000000 EventDisposed
7b4777e4 40010fa 10 ...ntrolNativeWindow 0 instance 013b55c4 window
7b4754b4 40010fb 14 ...ows.Forms.Control 0 instance 00000000 parent
7b4754b4 40010fc 18 ...ows.Forms.Control 0 instance 00000000 reflectParent
7b478924 40010fd 1c ...orms.CreateParams 0 instance 013b560c createParams
790fe920 40010fe 34 System.Int32 0 instance 346 x
790fe920 40010ff 38 System.Int32 0 instance 22 y
790fe920 4001100 3c System.Int32 0 instance 266 width
Table 16-7 gives an overview of some of the SOS commands. For a complete listing, use the !help command.
Table 16-7. SOS commands
Command | Description |
---|---|
!ClrStack option | Displays the call stack of the current thread. Here are some of the options:
|
!DumpHeap option startaddress endaddress | Displays objects that are on the managed heap and then displays statistics about the type of objects on the managed heap. Here are some of the options:
|
!DumpIL mdaddress | Displays the Microsoft Intermediate Language (MSIL) of a method, based on the method descriptor. |
!DumpMT mtaddress | Displays information about the method table. The –md option lists the methods of the method table. |
!DumpObj objaddress | Displays information on the specific object. |
!DumpStackObjects option | Lists objects that are referenced from the current stack. |
!EEHeap options | Displays information on generations 0, 1, 2, and the large object heap. (The large object heap is explained in the section "Generations," later in this chapter.) The gc option limits the display to information pertaining to the generations and the large object heap. |
!EEVersion | Displays information about the runtime environment, such as the version number. |
!FinalizeQueue option | Lists objects currently on the finalization queue. |
!GCroot option objaddress | Shows how references are rooted, which is the path from the object to the root. In C#, root objects include static and local references. These objects represent the base of a branch in the object graph. The –nostacks option excludes references held on the stack. |
!IP2MD jitaddress | Displays the method descriptor of a jitted method. |
!Name2EE programtarget | If the target is a type, provides information on that type. If the target is a method name, displays information on the method descriptor. |
!Syncblk | Lists the entries of the sync block table. |
!Threads | Lists the managed threads. |
!Token2EE token | For this command, the token must reference the typedef or methoddef table. If it is a typedef token, the command displays information on the referenced type. If it is a methoddef token, the command displays information on the referenced methods. |
!u | This command displays the disassembly for a jitted method. |
!Help command | Displays help for SOS commands. Without the command option, the command provides an overview of all the commands. |
Now that a few more commands have been introduced, an additional example is helpful. This example lists the source, MSIL, and assembly code of the btnTransaction_Click button handler, which is informative.
Start the Store application in the sos subfolder and then attach WinDbg to the application. Load SOS.
Dump information about the btnTransaction_Click method with the !name2ee command. Notice that the method has not been jitted yet, which means that the method has not been invoked. A method is jitted the first time it is invoked. Here is the code:
0:004> !name2ee store.exe Store.Form1.btnTransaction_Click
Module: 00d40c14 (Store.exe)
Token: 0x06000004
MethodDesc: 00d43968
Name: Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)
Not JITTED yet. Use !bpmd -md 00d43968 to break on run.
0:004> !u 00d43968
Not jitted yet
Restart the Store application from break mode using the g(o) command. Click Add Transactions. In WinDbg, press Ctrl+Break to interrupt the application. Dump information on the Store.Form1.btnTransaction_Click method again. This time, the method is shown as jitted, and the virtual address of the cached native binary is displayed:
0:004> !name2ee store.exe Store.Form1.btnTransaction_Click
Module: 00d40c14 (Store.exe)
Token: 0x06000004
MethodDesc: 00d43968
Name: Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)
JITTED Code Address: 00de07c0
The !u command displays the assembly code of a jitted method. Execute the !u command on the btnTransaction_Click method using the address shown for the method descriptor (Method Desc) by the !name2ee command:
0:004> !u 00d43968
Normal JIT generated code
Store.Form1.btnTransaction_Click(System.Object, System.EventArgs)
Begin 00de07c0, size 3e9
00de07c0 55 push ebp
00de07c1 8bec mov ebp,esp
00de07c3 57 push edi
00de07c4 56 push esi
00de07c5 53 push ebx
00de07c6 83ec50 sub esp,0x50
00de07c9 33c0 xor eax,eax
00de07cb 8945d0 mov [ebp-0x30],eax
00de07ce 8945c4 mov [ebp-0x3c],eax
00de07d1 33c0 xor eax,eax
00de07d3 8945e8 mov [ebp-0x18],eax
00de07d6 894dc0 mov [ebp-0x40],ecx
00de07d9 8955dc mov [ebp-0x24],edx
00de07dc 833dc80dd40000 cmp dword ptr [00d40dc8],0x0
The next challenge is to list the MSIL code for the btnTransaction_Click method. The dumpil command shows the MSIL code of the method. Method descriptor is the only parameter, which also is provided by the !name2ee command:
0:004> !dumpil 00d43968
ilAddr = 0040247c
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: ldarg.0
IL_0003: ldfld Store.Form1::txtNumber
IL_0008: callvirt System.Windows.Forms.Control::get_Text
IL_000d: call System.Int32::Parse
IL_0012: stloc.0
IL_0013: nop
IL_0014: leave.s IL_001d
} // end .try
.catch
{
IL_0016: pop
IL_0017: nop
IL_0018: ldc.i4.1
IL_0019: stloc.0
IL_001a: nop
IL_001b: leave.s IL_001d
} // end .catch
The final task is to display the source code. Set the source code path in WinDbg. From the File menu, choose the Source File Path command and then enter the source code path. This should be the path for the store.exe source code in the sos subfolder. Next, enter the lsf command to set form1.cs as the current source code file. List the source with the ls command. For this example, 40 lines are displayed, beginning with line 10. You now have displayed the source, intermediate language, and assembly code for a function:
0:004> lsf form1.cs 0:004> ls 10, 40 22: 23: private void btnTransaction_Click(object sender, EventArgs e) 24: { 25: int numofTransactions; 26: try 27: { 28: numofTransactions= int.Parse(txtNumber.Text); 29: } 30: catch 31: { 32: numofTransactions = 1; 33: } 34: for (int count = 0; count < numofTransactions; ++count) 35: { 36: int itemTotal=0;
18.223.196.146