使用 Windows 调试器调试托管代码

可以使用 Windows 调试器(WinDbg、CDB 和 NTSD)调试包含托管代码的目标应用程序。 若要调试托管代码,请将 !SOS 调试扩展 (sos.dll) 和数据访问组件 (mscordacwks.dll) 与 CLR 运行时结合使用。

Windows 调试器(如 WinDbg)与 Visual Studio 调试器相互独立。 有关 Windows 调试器与 Visual Studio 调试器之间的区别的信息,请参阅适用于 Windows 的调试工具

本文提供有关使用 Windows 调试器(WinDbg、CDB、NTSD)调试托管代码(包括 .NET Framework、.NET Core 和 .NET 5+ 应用程序)的说明。

注意

请确保使用最新版本的 Windows 调试器工具调试 .NET Framework、.NET Core 和 .NET 5+ 应用程序。 此外,请考虑使用 Visual Studio 或 Visual Studio Code 获得集成度更高的调试体验。 WinDbg 更加复杂,设置起来更加麻烦,并且通常在需要其他低级别信息时使用。

托管代码简介

托管代码与 Microsoft .NET 公共语言运行时 (CLR) 一起执行。 在托管代码应用程序中,编译器生成的二进制代码采用与平台无关的 Microsoft 中间语言 (MSIL)。

运行托管代码时,运行时将生成特定于平台的本机代码。 从 MSIL 生成本机代码的过程称为实时 (JIT) 编译。 在 JIT 编译器编译特定方法的 MSIL 后,该方法的本机代码将保留在内存中。 稍后调用此方法时,就会执行本机代码,并且不需要 JIT 编译器。

可以使用由各种软件生成者制造的多个编译器来生成托管代码。 具体而言,Microsoft Visual Studio 可以从多种不同的语言(包括 C#、Visual Basic、JScript 和具有托管扩展的 C++)生成托管代码。

每次更新 .NET Framework 时,CLR 都不会更新。 例如,.NET Framework 的 2.0、3.0 和 3.5 版都使用 CLR 的 2.0 版。 有关 .NET 版本的详细信息,请参见 .NET Framework 版本和依赖关系。 有关确定 PC 上的 .NET 版本的信息,请参阅确定安装了哪些 .NET Framework 版本

调试托管代码

若要使用 !SOS 调试扩展调试托管代码,调试器必须加载各种组件。 用于不同 .NET Core 和原始 .NET Framework 的 !SOS 调试扩展和所需组件。 对于任一项,都将使用数据访问组件 (DAC) (mscordacwks.dll)。

.NET SDK 提供有助于调试 .NET 应用的工具。 有关详细信息,请参阅什么是 .NET SDK?

.NET Core

对于 .NET Core,有一个可用于安装 !sos.dll 的 dotnet CLI 工具。 有关详细信息,请参阅 SOS 安装程序 (dotnet-sos)

原始 .NET Framework。

获取 SOS 调试扩展 (sos.dll)

SOS 调试扩展 (sos.dll) 文件不包含在所有版本的 Windows 调试工具中。 如果 sos.dll 不可用,请参阅在 Windows 上安装 SOS

加载 SOS 调试扩展 (sos.dll)

若要调试 .NET Core 和 .NET 5+ 应用程序,需要加载适当的 SOS 调试扩展版本。

例如,对于调试器随附的包含在当前扩展搜索路径中的 !SOS 版本,将使用 .load 命令。

0:000> .load sos.dll

若要验证 SOS 调试扩展加载是否正确,请使用 .chain 命令并检查扩展 DLL 链

...
Extension DLL chain:
    C:\Windows\Microsoft.NET\Framework\v4.0.30319\SOS.dll: image 4.8.9275.0, API 1.0.0, built Wed Aug 28 14:43:27 2024
        [path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\SOS.dll]
    C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\8.0.8\coreclr.dll: image 8,0,824,36612 @Commit: 08338fcaa5c9b9a8190abb99222fed12aaba956c, built Tue Jul 16 11:10:19 2024
        [path: C:\Program Files (x86)\dotnet\shared\Microsoft.NETCore.App\8.0.8\coreclr.dll]

如果调试器版本不包含 sos.dll,则可能需要指定 SOS.dll 文件的完整路径。 通常可以在 .NET Core 或 .NET Framework 安装的运行时目录中找到 SOS.dll 文件。

0:000> .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll

加载特定版本的 sos.dll

加载 sos.dll 可能很复杂,因为依赖于 sos.dll 用来与 .NET 通信的其他 DLL。 此外,所需的 DLL 版本依赖于正在调试的应用的 .NET 版本,并且计算机上可能存在多个版本的 .NET。

加载依赖 DLL 的正确版本的一种策略是要求调试器使用 sx、sxd、sxe、sxi、sxn、sxr、sx- (Set Exceptions)[../debuggercmds/sx--sxd--sxe--sxi--sxn--sxr--sx---set-exceptions-.md] 命令在第一个 .NET clr 通知 (CLRN) 出现时中断操作。 附加到目标 .NET 应用程序后,将在第一次中断后使用此命令。

0:000> sxe CLRN

接下来继续执行并等待中断发生。

0:000> g

中断发生时,禁用 clr 通知中断,因为我们知道已加载 clr.dll(或 coreclr.dll)。

0:000> sxd CLRN

在此上下文中使用调试器时,使用 .loadby 从同一“附近”目录位置加载 !sos。

0:000> .loadby sos clr

另一个选项是使用 .cordll(控制 CLR 调试)通过提供目标框架位置的路径来加载 CLR 调试 DLL。

0:000> .cordll -ve -u -lp C:\Windows\Microsoft.NET\Framework\v4.0.30319\
CLRDLL: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll
Automatically loaded SOS Extension
CLR DLL status: Loaded DLL C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscordacwks.dll

使用 SOS 调试扩展

若要验证 SOS 调试扩展是否正确加载,请输入 .chain 命令。

0:000> .chain
Extension DLL search Path:
    C:\Program Files\Debugging Tools for Windows (x64);...
Extension DLL chain:
    C:\Windows\Microsoft.NET\Framework\v4.0.30319\SOS.dll: image 4.8.9275.0, API 1.0.0, built Wed Aug 28 14:43:27 2024
        [path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\SOS.dll]
...

.NET 符号文件

符号文件对于调试至关重要。 对于 .NET Framework、.NET Core 和 .NET 5+ 应用程序,可以从 Microsoft 的公共符号服务器检索必要的符号文件。 使用以下命令设置符号路径和回显符号加载。

.symfix

!sym noisy

.reload

测试 .NET Core !sos 扩展

若要测试 SOS 调试扩展,请输入 !sos.help

0:000> !sos.help
-------------------------------------------------------------------------------
SOS is a debugger extension DLL designed to aid in the debugging of managed
programs. Functions are listed by category, then roughly in order of
importance. Shortcut names for popular functions are listed in parenthesis.
Type "!help <functionname>" for detailed info on that function. 

Object Inspection                  Examining code and stacks
-----------------------------      -----------------------------
DumpObj (do)                       Threads
DumpArray (da)                     ThreadState
DumpStackObjects (dso)             IP2MD
DumpHeap                           U
DumpVC                             DumpStack
GCRoot                             EEStack
ObjSize                            CLRStack
FinalizeQueue                      GCInfo
PrintException (pe)                EHInfo
TraverseHeap                       BPMD 
                                   COMState

然后尝试 SOS 调试扩展提供的命令之一。 例如,可以尝试 .NET Core SOS 调试扩展提供的 !sos.DumpDomain!sos.Threads 命令。

0:000> !sos.DumpDomain
--------------------------------------
System Domain:      7565d980
LowFrequencyHeap:   7565dca4
HighFrequencyHeap:  7565dcf0
StubHeap:           7565dd3c
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      7565d620
LowFrequencyHeap:   7565dca4
HighFrequencyHeap:  7565dcf0
StubHeap:           7565dd3c
Stage:              OPEN
Name:               None
Assembly:           00fa5e78 [C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        00fa5f40
  Module Name
73571000    C:\WINDOWS\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

0:000> !sos.Threads
ThreadCount:      2
UnstartedThread:  0
BackgroundThread: 2
PendingThread:    0
DeadThread:       0
Hosted Runtime:   no
                                                                         Lock  
       ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception
   0    1 4538 00f91110     20220 Preemptive  02FE1238:00000000 00f58be0 1     Ukn 
   7    2 250c 00f9da88     21220 Cooperative 00000000:00000000 00f58be0 1     Ukn (Finalizer) 

测试 .NET Framework !sos 扩展

若要测试 SOS 调试扩展,请输入 !sos.help。 然后尝试 SOS 调试扩展提供的命令之一。 例如,可以尝试 !sos.sostatus!sos.threads 命令。

0:030> !soshelp
crashinfo                                 Displays the crash details that created the dump.
help, soshelp <command>                   Displays help for a command.
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.
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.
sosflush                                  Resets the internal cached state.
sosstatus                                 Displays internal status.
threads, setthread <thread>               Lists the threads in the target or sets the current thread.

备注

有时,托管代码应用程序会加载多个版本的 CLR。 在这种情况下,必须指定要加载的 DAC 版本。 有关详细信息,请参阅 .cordllClrver.exe(CLR 版本工具)。