1. 通过 Windows Store 安装 WinDbg

打开 Windows Store, 在搜索框中输入 WinDbg, 如果已经安装了,看到的是 Open,如果还没有安装,显式为 Get.

使用 Store 版的 WinDbg 调试 .NET 应用_API

直接安装即可。

2. 安装 SOS

SOS 调试扩展提供了一系列的扩展命令,通过 SOS 的扩展命令,可以直接查看 CLR 运行时的各类信息。

在 .NET 下,使用下面的命令首先安装 dotnet-sos 工具

PS > dotnet tool install --global dotnet-sos
You can invoke the tool using the following command: dotnet-sos
Tool 'dotnet-sos' (version '8.0.510501') was successfully installed.
  • 1.
  • 2.
  • 3.

在 dotnet-sos 工具成功安装之后,使用该工具安装 SOS.

PS > dotnet-sos install
Installing SOS to C:\Users\XXX\.dotnet\sos
Creating installation directory...
Copying files from C:\Users\XXX\.dotnet\tools\.store\dotnet-sos\8.0.510501\dotnet-sos\8.0.510501\tools\net6.0\any\win-x64
Copying files from C:\Users\XXX\.dotnet\tools\.store\dotnet-sos\8.0.510501\dotnet-sos\8.0.510501\tools\net6.0\any\lib
Execute '.load C:\Users\XXX\.dotnet\sos\sos.dll' to load SOS in your Windows debugger.
SOS install succeeded
PS >
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

注意输出的提示,可以通过在 WinDbg 中执行 .load C:\Users\XXX\.dotnet\sos\sos.dll 来加载 SOS 调试扩展。

注意,在 .NET 中,不再需要原来的 ~loadby sos corclr

见:  SOS installer

3. 连接到 .NET 进程

执行一个 .NET 程序,然后打开 WinDbg,

使用 Store 版的 WinDbg 调试 .NET 应用_API_02

通过文件菜单的 Attach to process 来选择目标的 .NET 进程,点击 Attach 进行连接。

注意左下角的自动检测,现在 WinDbg 支持自动检测。

使用 Store 版的 WinDbg 调试 .NET 应用_加载_03

4. 加载 SOS 调试扩展

在 Attach 上 .NET 应用之后,就可以加载 SOS 扩展了,执行前面提示的加载 SOS 的命令

.load C:\Users\XXX\.dotnet\sos\sos.dll
  • 1.

如果没有错误提示,说明成功加载。

使用 .chain 命令来检查加载的扩展,它的作用是列出当前加载的扩展,见: chain (List Debugger Extensions)

The .chain command lists all loaded debugger extensions in their default search order.

0:004> .load c:\user\XXXX\.dotnet\sos\sos.dll
0:004> .chain
Extension DLL search Path:
    C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\WINXP;C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext;C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\arcade;C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\pri;C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64;C:\Users\XXXX\AppData\Local\Dbg\EngineExtensions;C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\windows\System32\OpenSSH\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\;C:\Program Files\Microsoft SQL Server\150\Tools\Binn\;C:\Program Files\Git\cmd;C:\Program Files (x86)\Microsoft SQL Server\160\Tools\Binn\;C:\Program Files\Microsoft SQL Server\160\Tools\Binn\;C:\Program Files\Microsoft SQL Server\160\DTS\Binn\;C:\Program Files (x86)\Microsoft SQL Server\160\DTS\Binn\;C:\Program Files\Azure Data Studio\bin;C:\Program Files\Go\bin;C:\Program Files\dotnet\;C:\Program Files\nodejs\;C:\Program Files\RedHat\Podman\;C:\Users\XXXX\AppData\Local\Microsoft\WindowsApps;C:\Users\XXXX\.dotnet\tools;C:\Users\XXXX\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\XXXX\AppData\Local\Programs\Fiddler;C:\Users\XXXX\go\bin;C:\Users\XXXX\.dotnet\tools;C:\Users\XXXX\AppData\Roaming\npm
Extension DLL chain:
    DbgEngCoreDMExt: image 10.0.27553.1004, API 0.0.0, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\DbgEngCoreDMExt.dll]
    sos: image 8.0.510501, API 2.0.0, built Tue Feb  6 06:03:41 2024
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\sos\sos.dll]
    CLRComposition: image 10.0.27553.1004, API 0.0.0, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\CLRComposition.dll]
    dbghelp: image 10.0.27553.1004, API 10.0.6, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\dbghelp.dll]
    exts: image 10.0.27553.1004, API 1.0.0, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\WINXP\exts.dll]
    uext: image 10.0.27553.1004, API 1.0.0, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\winext\uext.dll]
    ntsdexts: image 10.0.27553.1004, API 1.0.0, 
        [path: C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\amd64\WINXP\ntsdexts.dll]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

扩展命令使用 ! 作为引导符号。

执行 !soshelp 来查看现在支持的 SOS 扩展命令

0:004> !soshelp
analyzeoom, AnalyzeOOM                                   Displays the info of the last OOM that occurred on an allocation request to the GC heap.
assemblies, clrmodules                                   Lists the managed assemblies in the process.
clrstack <arguments>                                     Provides a stack trace of managed code only.
clrthreads <arguments>                                   Lists the managed threads running.
comstate <arguments>                                     Lists the COM apartment model for each thread.
crashinfo                                                Displays the crash details that created the dump.
dbgout <arguments>                                       Enables/disables (-off) internal SOS logging.
dumpalc <arguments>                                      Displays details about a collectible AssemblyLoadContext into which the specified object is loaded.
dumparray <arguments>                                    Displays details about a managed array.
dumpassembly <arguments>                                 Displays details about an assembly.
dumpasync, DumpAsync                                     Displays information about async "stacks" on the garbage-collected heap.
dumpccw <arguments>                                      Displays information about a COM Callable Wrapper.
dumpclass <arguments>                                    Displays information about a EE class structure at the specified address.
dumpconcurrentdictionary, dcd <address>                  Displays concurrent dictionary content.
dumpconcurrentqueue, dcq <address>                       Displays concurrent queue content.
dumpdelegate <arguments>                                 Displays information about a delegate.
dumpdomain <arguments>                                   Displays the Microsoft intermediate language (MSIL) that's associated with a managed method.
dumpexceptions                                           Displays a list of all managed exceptions.
dumpgcdata <arguments>                                   Displays information about the GC data.
dumpgen, dg <generation>                                 Displays heap content for the specified generation.
dumpheap, DumpHeap <memoryrange>                         Displays a list of all managed objects.
dumpil <arguments>                                       Displays the Microsoft intermediate language (MSIL) that is associated with a managed method.
dumplog <arguments>                                      Writes the contents of an in-memory stress log to the specified file.
dumpmd <arguments>                                       Displays information about a MethodDesc structure at the specified address.
dumpmodule <arguments>                                   Displays information about a EE module structure at the specified address.
dumpmt <arguments>                                       Displays information about a method table at the specified address.
dumpobj, do <arguments>                                  Displays info about an object at the specified address.
dumpobjgcrefs <object>                                   A helper command to implement !dumpobj -refs
dumppermissionset <arguments>                            Displays a PermissionSet object (debug build only).
dumprcw <arguments>                                      Displays information about a Runtime Callable Wrapper.
dumpruntimetypes, DumpRuntimeTypes                       Finds all System.RuntimeType objects in the GC heap and prints the type name and MethodTable they refer too.
dumpsig <arguments>                                      Dumps the signature of a method or field specified by <sigaddr> <moduleaddr>.
dumpsigelem <arguments>                                  Dumps a single element of a signature object.
dumpstackobjects, dso, DumpStackObjects <stackbounds>    Displays all managed objects found within the bounds of the current stack.
dumpvc <arguments>                                       Displays info about the fields of a value class.
eeheap, EEHeap <memoryrange>                             Displays information about native memory that CLR has allocated.
eeversion <arguments>                                    Displays information about the runtime version.
ehinfo <arguments>                                       Displays the exception handling blocks in a JIT-ed method.
enummem <arguments>                                      ICLRDataEnumMemoryRegions.EnumMemoryRegions test command.
ephrefs                                                  Finds older generation objects which reference objects in the ephemeral segment.
ephtoloh                                                 Finds ephemeral objects which reference the large object heap.
finalizequeue, fq, FinalizeQueue                         Displays all objects registered for finalization.
findappdomain <arguments>                                Attempts to resolve the AppDomain of a GC object.
findpointersin <regions>                                 Finds pointers to the GC heap within the given memory regions.
gchandleleaks <arguments>                                Helps in tracking down GCHandle leaks.
gchandles <arguments>                                    Provides statistics about GCHandles in the process.
gcheapstat, GCHeapStat                                   Displays various GC heap stats.
gcinfo <arguments>                                       Displays JIT GC encoding for a method.
gcroot, GCRoot <target>                                  Displays info about references (or roots) to an object at the specified address.
gctonative <memorytypes>                                 Finds GC objects which point to the given native memory ranges.
gcwhere, GCWhere <address>                               Displays the location in the GC heap of the specified address.
help, soshelp <command>                                  Displays help for a command.
histclear <arguments>                                    Releases any resources used by the family of Hist commands.
histinit <arguments>                                     Initializes the SOS structures from the stress log saved in the debuggee.
histobj <arguments>                                      Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to  the address passed in as an argument.
histobjfind <arguments>                                  Displays all the log entries that reference an object at the specified address.
histroot <arguments>                                     Displays information related to both promotions and relocations of the specified root.
histstats <arguments>                                    Displays stress log stats.
ip2md <arguments>                                        Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.
listnearobj, lno, ListNearObj <address>                  Displays the object preceding and succeeding the specified address.
loadsymbols <url>                                        Loads symbols for all modules.
logclose <path>                                          Disables console file logging.
logging <path>                                           Enables/disables internal diagnostic logging.
logopen <path>                                           Enables console file logging.
maddress                                                 Displays a breakdown of the virtual address space.
modules, lm                                              Displays the native modules in the process.
name2ee <arguments>                                      Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.
notreachableinrange <start> <end>                        A helper command for !finalizerqueue
objsize, ObjSize <objectaddress>                         Lists the sizes of the all the objects found on managed threads.
parallelstacks, pstacks                                  Displays the merged threads stack similarly to the Visual Studio 'Parallel Stacks' panel.
pathto, PathTo <source> <target>                         Displays the GC path from <root> to <target>.
printexception, pe <arguments>                           Displays and formats fields of any object derived from the Exception class at the specified address.
registers, r                                             Displays the thread's registers.
runtimes <id>                                            Lists the runtimes in the target or changes the default runtime.
setclrpath <path>                                        Sets the path to load coreclr DAC/DBI files.
setsymbolserver, SetSymbolServer <url>                   Enables and sets symbol server support for symbols and module download.
sizestats                                                Size statistics for the GC heap.
sosflush                                                 Resets the internal cached state.
sosstatus                                                Displays internal status.
syncblk <arguments>                                      Displays the SyncBlock holder info.
taskstate, tks <address>                                 Displays a Task state in a human readable format.
threadpool, ThreadPool                                   Displays info about the runtime thread pool.
threadpoolqueue, tpq                                     Displays queued ThreadPool work items.
threads, setthread <thread>                              Displays threads or sets the current thread.
threadstate <arguments>                                  Pretty prints the meaning of a threads state.
timerinfo, ti                                            Displays information about running timers.
traverseheap, TraverseHeap <filename>                    Writes out heap information to a file in a format understood by the CLR Profiler.
verifyheap, VerifyHeap <memoryrange>                     Searches the managed heap for memory corruption..
verifyobj, VerifyObj <objectaddress>                     Checks the given object for signs of corruption.
watsonbuckets <arguments>                                Displays the Watson buckets.
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.

查看命令的详细使用,可以在 soshelp 后跟上相应的命令,例如查看 clrstack 扩展命令的详细使用。

0:000> !soshelp clrstack
clrstack:
  Provides a stack trace of managed code only.

Usage:
  >!sos clrstack [<arguments>...]

Arguments:
  <arguments>    Arguments to SOS command.

!ClrStack [-a] [-l] [-p] [-n] [-f] [-r] [-all]
!ClrStack [-a] [-l] [-p] [-i] [variable name] [frame]

ClrStack attempts to provide a true stack trace for managed code only. It is
handy for clean, simple traces when debugging straightforward managed 
programs. The -p parameter will show arguments to the managed function. The 
-l parameter can be used to show information on local variables in a frame.
SOS can't retrieve local names at this time, so the output for locals is in
the format <local address> = <value>. The -a (all) parameter is a short-cut
for -l and -p combined. 

The -f option (full mode) displays the native frames intermixing them with
the managed frames and the assembly name and function offset for the managed
frames.

The -r option dumps the registers for each stack frame.

The -all option dumps all the managed threads' stacks.

If the debugger has the option SYMOPT_LOAD_LINES specified (either by the
.lines or .symopt commands), SOS will look up the symbols for every managed 
frame and if successful will display the corresponding source file name and 
line number. The -n (No line numbers) parameter can be specified to disable 
this behavior.

When you see methods with the name "[Frame:...", that indicates a transition 
between managed and unmanaged code. You could run !IP2MD on the return 
addresses in the call stack to get more information on each managed method.

On x64 platforms, Transition Frames are not displayed at this time. To avoid
heavy optimization of parameters and locals one can request the JIT compiler
to not optimize functions in the managed app by creating a file myapp.ini 
(if your program is myapp.exe) in the same directory. Put the following lines
in myapp.ini and re-run:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

The -i option is a new EXPERIMENTAL addition to ClrStack and will use the ICorDebug
interfaces to display the managed stack and variables. With this option you can also 
view and expand arrays and fields for managed variables. If a stack frame number is 
specified in the command line, ClrStack will show you the parameters and/or locals 
only for that frame (provided you specify -l or -p or -a of course). If a variable 
name and a stack frame number are specified in the command line, ClrStack will show 
you the parameters and/or locals for that frame, and will also show you the fields 
for that variable name you specified. Here are some examples: 
   !ClrStack -i -a           : This will show you all parameters and locals for all frames
   !ClrStack -i -a 3         : This will show you all parameters and locals, for frame 3
   !ClrStack -i var1 0       : This will show you the fields of 'var1' for frame 0
   !ClrStack -i var1.abc 2   : This will show you the fields of 'var1', and expand
                               'var1.abc' to show you the fields of the 'abc' field,
                               for frame 2.
   !ClrStack -i var1.[basetype] 0   : This will show you the fields of 'var1', and
                                      expand the base type of 'var1' to show you its
                                      fields.
   !ClrStack -i var1.[6] 0   : If 'var1' is an array, this will show you the element
                               at index 6 in the array, along with its fields
The -i options uses DML output for a better debugging experience, so typically you
should only need to execute "!ClrStack -i", and from there, click on the DML 
hyperlinks to inspect the different managed stack frames and managed variables.
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.

详见: SOS debugging extension

5. 使用 SOS

使用上面提示的 !threads 命令查看当前的线程列表。可以看到当前有 2 个线程。

0:000> !clrthreads
ThreadCount:      2
UnstartedThread:  0
BackgroundThread: 1
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                                                            Lock  
 DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1     c754 000001BC7A454AB0    2a020 Preemptive  000001BC7ECC0848:000001BC7ECC1080 000001bc7a3ff670 -00001 MTA 
   3    2     5e9c 000001BC7A4C0090    21220 Preemptive  0000000000000000:0000000000000000 000001bc7a3ff670 -00001 Ukn (Finalizer)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

查看调用堆栈

0:000> !clrstack
OS Thread Id: 0xc754 (0)
        Child SP               IP Call Site
0000008C9657E320 00007ffb71eed174 [InlinedCallFrame: 0000008c9657e320] 
0000008C9657E320 00007ffb336276eb [InlinedCallFrame: 0000008c9657e320] 
0000008C9657E2F0 00007ffb336276eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 412]
0000008C9657E3E0 00007ffb3362c9c0 System.ConsolePal+WindowsConsoleStream.ReadFileNative(IntPtr, System.Span`1, Boolean, Int32 ByRef, Boolean) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1150]
0000008C9657E440 00007ffb3362c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/System.Console/src/System/ConsolePal.Windows.cs @ 1108]
0000008C9657E480 00007ffb3362fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/System.Console/src/System/IO/ConsoleStream.cs @ 34]
0000008C9657E4F0 00007ffb08298aa1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 613]
0000008C9657E540 00007ffb08299184 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs @ 802]
0000008C9657E5F0 00007ffb3363005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
0000008C9657E640 00007ffb33629319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
0000008C9657E670 00007ffaa90f3688 Program.$(System.String[]) [C:\research\dotnet\windbg_sample\Program.cs @ 6]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

显式当前的运行时信息

0:000> !runtimes
#0 .NET Core runtime 8.0.624.26715 at 00007FFB08B20000 size 004E6000 index 66479681 004E6000
    Runtime module path: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\coreclr.dll
    DAC: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\mscordaccore.dll
    Libraries:
        Dac C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\mscordaccore.dll WINDOWS X64 Coreclr 66479681 004E6000
        Dac mscordaccore.dll WINDOWS X64 Self 66479650 0014A000
        Dac mscordaccore_amd64_amd64_8.0.624.26715.dll WINDOWS X64 Coreclr 66479681 004E6000
        Dbi mscordbi.dll WINDOWS X64 Self 66479629 00133000
        Dbi mscordbi.dll WINDOWS X64 Coreclr 66479681 004E6000
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

当前的 SOS 状态信息

0:000> !sosstatus
Target OS: WINDOWS Architecture: X64 ProcessId: 35864 (0x8C18)
#0 .NET Core runtime 8.0.624.26715 at 00007FFB08B20000 size 004E6000 index 66479681 004E6000
    Runtime module path: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\coreclr.dll
    DAC: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\mscordaccore.dll

Current symbol store settings:
-> Cache: C:\ProgramData\dbg\sym
-> Server: https://msdl.microsoft.com/download/symbols/ Timeout: 4 RetryCount: 0
GC memory usage for managed SOS components: 1,631,616 bytes
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

6. 自动加载 SOS

每次启动都手动加载 SOS 也很麻烦,这个问题可以通过配置 WinDbg 在启动后自动加载它。

在 WinDbg 的 Settings -> Debugging settings -> Startup 中,可以配置在开始一个调试会话后,自动执行的命令。将加载 sos.dll 的命令填到这个命令框中。

使用 Store 版的 WinDbg 调试 .NET 应用_API_04

此时,在命令窗口中,就可以看到已经自动执行了加载 SOS.dll 的命令。

需要注意的是,刚加载的 .NET 应用在启动之前还没有加载相应的运行时,所以,直接使用 SOS 命令会报错,找不到运行时 module,如下所示:

0:000> .load C:\Users\XXXX\.dotnet\sos\sos.dll
0:000> !t
Failed to find runtime module (coreclr.dll or clr.dll or libcoreclr.so), 0x80004002
Extension commands need it in order to have something to do.
For more information see https://go.microsoft.com/fwlink/?linkid=2135652
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

需要继续执行程序,以便 .NET 加载 corclr.dll,在此之后,就可以使用 SOS 命令了。

0:000> .load C:\Users\XXXX\.dotnet\sos\sos.dll
0:000> !t
Failed to find runtime module (coreclr.dll or clr.dll or libcoreclr.so), 0x80004002
Extension commands need it in order to have something to do.
For more information see https://go.microsoft.com/fwlink/?linkid=2135652
0:000> g
ModLoad: 00007ffb`70fe0000 00007ffb`71012000   C:\windows\System32\IMM32.DLL
ModLoad: 00007ffb`259c0000 00007ffb`25a19000   C:\Program Files\dotnet\host\fxr\8.0.6\hostfxr.dll
ModLoad: 00007ffb`253a0000 00007ffb`25404000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\hostpolicy.dll
ModLoad: 00007ffb`08b20000 00007ffb`09006000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\coreclr.dll
ModLoad: 00007ffb`70b60000 00007ffb`70c8b000   C:\windows\System32\ole32.dll
ModLoad: 00007ffb`71100000 00007ffb`71453000   C:\windows\System32\combase.dll
ModLoad: 00007ffb`70f10000 00007ffb`70fdd000   C:\windows\System32\OLEAUT32.dll
ModLoad: 00007ffb`6fd30000 00007ffb`6fdb2000   C:\windows\System32\bcryptPrimitives.dll
(b2a8.2c24): Unknown exception - code 04242420 (first chance)
ModLoad: 00007ffb`07e90000 00007ffb`08b1d000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Private.CoreLib.dll
ModLoad: 00007ffb`0d190000 00007ffb`0d349000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\clrjit.dll
ModLoad: 00007ffb`6d1d0000 00007ffb`6d1e2000   C:\windows\SYSTEM32\kernel.appcore.dll
ModLoad: 0000022e`6d2a0000 0000022e`6d2a8000   C:\research\dotnet\windbg_sample\bin\Debug\net8.0\windbg_sample.dll
ModLoad: 0000022e`6d2b0000 0000022e`6d2be000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Runtime.dll
ModLoad: 00007ffb`51dc0000 00007ffb`51fee000   C:\windows\SYSTEM32\icu.dll
ModLoad: 00007ffb`33620000 00007ffb`33648000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Console.dll
ModLoad: 00007ffb`3dd20000 00007ffb`3dd32000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Threading.dll
ModLoad: 0000022e`6d130000 0000022e`6d138000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Text.Encoding.Extensions.dll
ModLoad: 00007ffb`4bb40000 00007ffb`4bb55000   C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.6\System.Runtime.InteropServices.dll
(b2a8.4d28): Break instruction exception - code 80000003 (first chance)
ntdll!DbgBreakPoint:
00007ffb`71ef0be0 cc              int     3
0:005> !t
ThreadCount:      3
UnstartedThread:  0
BackgroundThread: 2
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                                                            Lock  
 DBG   ID     OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1     2c24 0000022E6D1AB720    2a020 Preemptive  0000022E71CC0848:0000022E71CC1080 0000022e6d1e9c20 -00001 MTA 
   3    2     c80c 0000022E6D253C40    21220 Preemptive  0000000000000000:0000000000000000 0000022e6d1e9c20 -00001 Ukn (Finalizer) 
   4    3     986c 0000022E6D1B6250    2b220 Preemptive  0000000000000000:0000000000000000 0000022e6d1e9c20 -00001 MTA
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.

7. Tips: 查看 .NET 异常的窍门

通过执行下面的命令

sxe -c "!pe;g" clr
  • 1.

它的作用是在 CLR 异常的时候停止运行,输出异常信息,然后继续 (g)

(c7ac.8f5c): CLR exception - code e0434352 (first chance)
Exception object: 00000276128c12c0
Exception type:   System.Exception
Message:          XXX
InnerException:   <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131500
(c7ac.8f5c): CLR exception - code e0434352 (!!! second chance !!!)
KERNELBASE!RaiseException+0x69:
00007ffb`6f9bba99 0f1f440000      nop     dword ptr [rax+rax]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

参考资料