news 2026/9/19 18:43:17

.NET Runtime(dotnet/runtime)CoreCLR 调试完全指南:Windows / Linux / macOS 下的原生与托管调试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
.NET Runtime(dotnet/runtime)CoreCLR 调试完全指南:Windows / Linux / macOS 下的原生与托管调试实战
  • 语言运行时
  • 标准库
  • JIT编译
  • 编译器

【免费下载链接】runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.

项目地址:https://gitcode.com/GitHub_Trending/runtime6/runtime
点击查看免费下载

本指南以 dotnet/runtime 仓库的 debugging-runtime.md 为骨架,系统讲解如何在 Windows(Visual Studio / VS Code / Windbg / Cdb)、Linux 与 macOS(lldb)上调试 CoreCLR 运行时,涵盖构建前的准备工作、SOS 插件获取与加载、AOT 编译器调试入口,以及托管代码(C#)调试的 VS Code / Visual Studio 配置。读完本文,你将能够独立搭建一套"自建 CoreCLR + 源码断点 + SOS 命令"的完整调试环境,并理解corerun宿主、EEStartupcoreclr_execute_assembly等关键符号在调试链路中的位置。

调试前的准备工作:构建 clr 子集

无论是哪个平台,调试 CoreCLR 的第一步都是先构建运行时本身。官方强烈建议至少以Debug 配置构建clr子集,这样才会生成符号文件等调试所需的工件(artifact)。

Windows 上执行:

.\build.cmd -s clr -c Debug

Linux / macOS 上执行:

./build.sh -s clr -c Debug

说明:-c Debug实际上是默认配置,省略该参数效果相同,文档中保留它只是为了语义清晰。由于当前仓库采用统一的构建脚本体系(根目录下的 build.cmd 与 build.sh,以及定义子集组合的 Subsets.props),这套命令在三种平台上的语义是一致的。

单独重建 System.Private.CoreLib

如果因为某种原因System.Private.CoreLib.dll缺失,不需要重跑整个构建,可以只重建 CoreLib 相关的两个子集:

.\build.cmd -s clr.corelib+clr.nativecorelib -c Debug
./build.sh -s clr.corelib+clr.nativecorelib -c Debug

重要注意:当使用CORE_LIBRARIES环境变量进行调试时,libs子集(托管库,如System.Runtime等)也必须在开始调试之前完成构建,否则运行真实应用程序时会因缺少程序集而失败。

在 Windows 上调试 CoreCLR

使用 Visual Studio(推荐方式)

Visual Studio 作为完整 IDE,能显著降低运行时调试的门槛。官方步骤分为两步:

0. 准备原生构建前置工具(只需一次):

.\build.cmd clr.nativeprereqs -a <architecture> -c <configuration>

这会构建原生编译所需的部分工具,只要不清理artifacts目录,此步骤只执行一次即可。

1. 打开 CoreCLR 解决方案(coreclr.slnx),有两种方法:

  • 方法一(推荐):用构建脚本直接生成并启动解决方案:
    .\build.cmd -vs coreclr.slnx -a <architecture> -c <configuration>

    默认架构与配置为x64 Debug

  • 方法二(手动):先以-msbuild标志构建仓库,然后在 Visual Studio 中打开:
    path\to\runtime\artifacts\obj\coreclr\windows.<architecture>.<configuration>\ide\CoreCLR.slnx

2. 配置 INSTALL 项目为启动项并设置调试参数:

  1. 右键INSTALL项目,选择Set as StartUp Project

  2. 打开 INSTALL 项目的属性页。

  3. 在左侧树中选择Configuration Properties -> Debugging

  4. 设置Command=$(SolutionDir)\..\..\..\..\bin\coreclr\windows.$(Platform).$(Configuration)\corerun.exe——指向构建好的运行时二进制目录。

  5. 设置Command Arguments=<managed app you wish to run>(例如HelloWorld.dll)。

  6. 设置Working Directory=$(SolutionDir)\..\..\..\..\bin\coreclr\windows.$(Platform).$(Configuration)——包含 CoreCLR 二进制文件的目录。

  7. 设置Environment=CORE_LIBRARIES=$(SolutionDir)\..\..\..\..\bin\runtime\<target-framework>-windows-$(Configuration)-$(Platform),其中<target-framework>是当前分支的目标框架(当前仓库为net11.0)。此变量的作用是:

    • 指向除System.Private.CoreLib之外的核心库所在目录;
    • 如果只调试仅引用System.Private.CoreLib的 CLR 测试,此步可跳过;但要调试引用任何其他程序集(包括System.Runtime)的真实应用,则必须配置。
  8. 右键INSTALL项目并选择Build,让 Visual Studio 从 CMake 中加载必要信息。

  9. F11corerunwmain开始单步调试,或在源码中设置断点后按F5。例如,在ceemain.cpp中的EEStartup()函数上设断点,即可在 CoreCLR 启动时中断进入。

步骤 1-9 只需做一次(只要仓库中的 CMake 文件没有变化),之后每次调试直接重复步骤 10 即可。官方建议使用 Visual Studio 2022 或 Visual Studio 2019。

从源码看,EEStartup()是运行时的核心启动函数,定义于 src/coreclr/vm/ceemain.cpp#L1129,它在PAL_TRY保护下调用EEStartupHelper()完成运行时初始化,是观察整个 CoreCLR 引导流程的最稳定切入点。

使用 Visual Studio 的 Open Folder + CMake 模式

  1. open folder功能打开 dotnet/runtime 仓库根目录,Visual Studio 会提示查找 CMake 文件,选择src\coreclr\CMakeLists.txt作为 CMake 工作区。
  2. corerun设为启动项目:在文件夹视图(而非 CMake targets 视图)下,右键coreclr\hosts\corerun\CMakeLists.txt设为启动项目,或从调试目标下拉框选择。
  3. 右键corerun项目打开Debug配置(也可通过主菜单Debug -> Debug and Launch Configuration)。
  4. 在打开的launch.vs.json中为corerun配置设置以下属性:
{ "type": "default", "project": "CMakeLists.txt", "projectTarget": "corerun.exe (hosts\\corerun\\corerun.exe)", "name": "corerun.exe (hosts\\corerun\\corerun.exe)", "environment": [ { "name": "CORE_ROOT", "value": "${cmake.installRoot}" }, { "name": "CORE_LIBRARIES", // for example net11.0-windows-debug-x64 "value": "${cmake.installRoot}\\..\\..\\runtime\\<tfm>-windows-<configuration>-<arch>\\" } ], "args": [ // path to a managed application to debug // remember to use double backslashes (\\) "HelloWorld.dll" ] }

注意:对于 Visual Studio 17.3,更改已启动可执行文件的位置不起作用,因此必须设置CORE_ROOT

  1. 在文件夹视图中右键 CoreCLR 项目或coreclr\CMakeLists.txt,执行Install命令。
  2. F10F11从 main 开始调试,或设置断点后按F5

每次修改 CoreCLR 源码后,记得重新执行Install命令,让修改生效到安装位置。

使用 Visual Studio 调试 CLI 构建的产物

Visual Studio 同样可以调试由命令行脚本构建的运行时:

  1. 按构建说明至少构建clrlibs子集。示例:
    .\build.cmd -subset clr+libs -configuration Release -runtimeConfiguration Debug
  2. 按测试说明构建 Core_Root,这会生成作为托管代码入口的corerun.exe,它与所需 dll 一起被放置在 core root 目录内。示例:
    .\src\tests\build.cmd generatelayoutonly
  3. 启动 Visual Studio 并选择打开现有项目/解决方案,选中artifacts\tests\coreclr\<OS>.<arch>.<configuration>\Tests\Core_Root\corerun.exe作为项目;或直接用命令行devenv /debugexe artifacts\tests\coreclr\<OS>.<arch>.<configuration>\Tests\Core_Root\corerun.exe启动。
  4. 在解决方案资源管理器中右键corerun,选择属性:将Debugger Type设为Native OnlyArguments填要调试的托管应用路径。
  5. 如需设置断点,可右键解决方案选择Add -> Existing Item添加运行时源文件。
  6. 设置断点后用F5运行开始调试。

.slnx文件可以保存,其中记录了corerun.exe路径、包含的文件和调试设置;只要路径不变,可重复复用。

使用 Visual Studio Code

文档说明 VS Code 的对应操作步骤"即将推出"(Visual Studio Code instructions coming soon)。就目前而言,在 Windows 上调试 CoreCLR 原生代码优先选择 Visual Studio 或 Windbg/Cdb;VS Code 更常用于托管代码调试,详见下文"使用 Visual Studio Code 调试托管代码"。

在 Windows 上使用 SOS 与 Windbg / Cdb

正常情况下列表 SOS 会随 Windbg 一起分发,无需额外安装。但如果你的 Windbg 中没有 SOS、需要使用其他版本,或出于任何原因需要单独/额外安装,可参考:

  • 微软官方 dotnet-sos 文档;
  • diagnostics 仓库的 installing-sos-windows-instructions.md。

SOS 命令的详细参考见 diagnostics 仓库的 sos-debugging-extension-windows.md。

说明:SOS(Sonic Of Stacks,运行时调试扩展)目前不再随本仓库分发,其代码与安装/使用文档已迁移至独立的 dotnet/diagnostics 仓库,请在其新家获取。

在 Linux 和 macOS 上调试 CoreCLR

与 Windows 类似,Linux/macOS 也需要至少构建clr子集(最好为 Debug 配置):

./build.sh -s clr -c Debug

System.Private.CoreLib.dll缺失时同样可以单独重建:

./build.sh -s clr.corelib+clr.nativecorelib -c Debug

同样地,使用CORE_LIBRARIES调试时须先构建libs子集。

Unix 上的 SOS

与 Windows 的 Windbg 不同,Linux/macOS 需要自行安装 SOS,安装说明见:

  • 微软官方 dotnet-sos 文档;
  • diagnostics 仓库的 installing-sos-instructions.md。

如果你的场景需要 SOS 的最新改动,或你正在使用官方未正式支持但实际上可用的环境(最常见的是macOS Arm64),则需要从 diagnostics 仓库自行构建 SOS,然后将其加载到lldb中,具体见下一节。

使用 lldb 调试 CoreCLR

注意:只有lldb被支持与 SOS 配合使用。你也可以使用gdbcgdb或其他调试器,但可能无法使用 SOS。

  1. 先构建 runtime 仓库的clr子集。
  2. 启动 lldb,传入corerun、要运行的应用(如HelloWorld.dll)以及该应用需要的任何参数:
    lldb -- /path/to/corerun /path/to/app.dll <app args go here>
  3. 如果使用已安装版本的 SOS,可跳过此步;如果是手动构建的 SOS,则需在调试会话开始前加载它:
    plugin load /path/to/built/sos/libsosplugin.so

    注意.so用于 Linux,macOS 使用.dylib。更多信息见 diagnostics 仓库的 using-sos-private-build.md。

  4. 启动程序:
    process launch -s
  5. 停止在运行时使用的SIGUSR1信号上中断:
    process handle -s false SIGUSR1
  6. 在 CoreCLR 初始化处设置断点——这是开始调试最稳定的点:
    breakpoint set -n coreclr_execute_assembly
  7. 设置断点后执行process continue运行到该点。
  8. 现在即可开始调试会话:设置断点,或运行 SOS 命令如clrstacksos VerifyHeap。注意SOS 命令名区分大小写

关于第 6 步的断点符号:coreclr_execute_assembly是 CoreCLR 宿主 API 的导出符号,由 src/coreclr/hosts/corerun/corerun.cpp 通过try_get_export(coreclr_mod, "coreclr_execute_assembly", ...)从运行时库解析并调用(该文件还解析了coreclr_initializecoreclr_shutdown_2等导出符号)。因此在此符号上设断点,恰好命中的是"宿主把托管程序集交给运行时执行"的时刻,是观察托管代码进入执行阶段的最佳位置。而corerun宿主本身则通过读取CORE_ROOTCORE_LIBRARIES等环境变量来定位运行时二进制与核心库目录(见 src/coreclr/hosts/corerun/corerun.cpp 中相关代码),这也是为什么文档中反复强调这两个变量配置的重要性。

禁用托管附加/调试

环境变量DOTNET_EnableDiagnostics可用于禁用托管调试,这可以阻止运行时创建用于调试的各种操作系统工件(如 Linux/macOS 上的命名管道和信号量):

export DOTNET_EnableDiagnostics=0

使用 lldb 调试 core dump

关于 core dump 的调试,diagnostics 仓库提供了非常详尽的指南:debugging-coredump.md。

调试 AOT 编译器

AOT 编译器的调试方式见其专属文档 debugging-aot-compilers.md。本文档只提供指引入口,不展开具体步骤。

调试托管代码(Managed Code)

CoreCLR 并不只有原生 C++ 代码,如今有大量值得调试的内容位于更上层的 C# 托管代码层面。

使用 Visual Studio Code 调试托管代码

  1. 安装 C# 扩展。
  2. 在 VS Code 中打开包含要调试源码的文件夹。
  3. 打开调试窗口:ctrl-shift-D/cmd-shift-D,或点击左侧的调试按钮。
  4. 点击顶部的齿轮按钮创建 launch 配置,并在下拉列表中选择.NET 5+ and .NET Core
  5. 它会生成一个launch.json文件,可在其中配置调试目标与方式。基础模板如下:
{ "version": "0.2.0", "configurations": [ { "name": "My Configuration", // Any identifiable name you might like. "type": "coreclr", // We want to debug a CoreCLR app. "request": "launch", // Start the app with the debugger attached. "program": "/path/to/corerun", // Point to your 'corerun', in order to run the app using your build. "args": ["app-to-debug.dll", "app arg1", "app arg2"], // First argument is your app, second and on are the app's arguments. "cwd": "/path/to/app-to-debug", // Can be anywhere. For simplicity, choose where your app is stationed. Otherwise, you have to adjust paths in the other parameters. "stopAtEntry": true, // This can be either. Keeping it to 'true' allows you to see when the debugger is ready. "console": "internalConsole", // Use VSCode's internal console instead of launching more terminals. "justMyCode": false, // Be able to debug into native assemblies. "enableStepFiltering": false, // Be able to debug into class initializations, field accessors, etc. } ] }
  1. 设置断点并启动调试器,即可检查变量与调用堆栈。

使用 Visual Studio 调试托管代码

  1. 使用File -> Open Project(注意不是 open file),选择要用作宿主(host)的二进制文件(通常是dotnet.execorerun.exe)。
  2. 打开刚创建项目的属性,设置以下项:
    • Arguments:与命令行中使用的参数一致。例如命令行运行dotnet.exe exec Foo.dll,则设置arguments = "exec Foo.dll"注意:务必使用dotnet exec而不是dotnet run,因为 run 动词会以子进程方式启动应用,调试器无法附加到子进程。
    • Working Directory:与命令行中使用的工作目录一致。
    • Debugger Type:设为Managed (.NET Core, .NET 5+);若要调试原生 C++ 代码,则选择Native Only
    • Environment:添加命令行中的环境变量。可考虑添加DOTNET_ReadyToRun=0,它禁用 R2R 预编译并让 JIT 生成可调试代码,从而在运行时框架程序集内部获得更高质量的 C# 调试体验,代价是应用性能有所下降。
  3. 托管调试时,Debug -> OptionsDebugging -> General中还有几个有用的设置:
    • 取消勾选Just My Code:允许调试进入框架库。
    • 勾选Enable .NET Framework Source Stepping:让调试器自动为运行时框架二进制下载符号与源码。如果是自己构建的框架,可跳过此步。
    • 勾选Suppress JIT optimization on module load:让调试器指示 .NET 运行时 JIT 为即使未以 C# 编译器 Debug 配置编译的模块生成可调试代码。该代码运行较慢,但能提供更高保真度的断点、单步执行与局部变量访问——这与调试 .NET 应用时 Debug 项目配置与 Release 项目配置的差异是一样的。

解决 Visual Studio 中的签名验证错误

Visual Studio 2022 17.5 及更高版本会在加载前验证随 .NET Runtime 提供的调试库是否已签名。若未签名,Visual Studio 会显示类似如下错误:

Unable to attach to CoreCLR. Signature validation failed for a .NET Runtime Debugger library because the file is unsigned.

This error is expected if you are working with non-official releases of .NET (example: daily builds from https://github.com/dotnet/sdk). See https://aka.ms/vs/unsigned-dotnet-debugger-lib for more information.

该错误会在目标进程使用每日构建版或自行构建的 .NET Runtime 时出现。注意:使用微软官方发布的 .NET Runtime 版本时绝不会出现此错误;使用官方版本时不要禁用签名验证。

以下方法可配置 Visual Studio 禁用签名验证:

  1. VSDebugger_ValidateDotnetDebugLibSignatures环境变量(最简单且推荐用于临时禁用):
    • 在命令行执行set VSDebugger_ValidateDotnetDebugLibSignatures=0,然后从同一个命令提示符启动 Visual Studio(devenv.exe)。
    • 该设置仅对从设置该变量的命令提示符启动的那个 Visual Studio 实例生效。
  2. DOTNET_ROOT环境变量:如果从设置了DOTNET_ROOT的命令提示符启动 Visual Studio,它会忽略位于DOTNET_ROOT目录下的未签名 .NET 运行时调试库。
  3. (不推荐)ValidateDotnetDebugLibSignatures注册表键:若需更持久地禁用,可设置 VS 注册表键Common7\IDE\VsRegEdit.exe set local HKCU Debugger\EngineSwitches ValidateDotnetDebugLibSignatures dword 0。例如打开开发者命令提示符执行:
    Common7\IDE\VsRegEdit.exe set local HKCU Debugger\EngineSwitches ValidateDotnetDebugLibSignatures dword 0

调试实践小结

综合以上流程,一套完整的 CoreCLR 调试工作流可归纳为四个阶段:

  1. 构建:至少以 Debug 配置构建clr子集(.\build.cmd -s clr -c Debug./build.sh -s clr -c Debug);使用CORE_LIBRARIES时还需构建libs子集。
  2. 获取宿主与符号:通过corerun作为宿主进程(其源码见 src/coreclr/hosts/corerun/corerun.cpp),确认CORE_ROOTCORE_LIBRARIES指向正确的产物目录;在 Linux/macOS 上提前安装或构建 SOS 插件。
  3. 接入调试器:Windows 上选择 Visual Studio(INSTALL 项目 +EEStartup断点)、Open Folder 模式或 Windbg/Cdb;Linux/macOS 上使用 lldb 并在coreclr_execute_assembly上设断点,运行process handle -s false SIGUSR1屏蔽信号干扰。
  4. 托管层面:对框架库内部或应用自身的 C# 代码,使用 VS Code 的launch.json(type 为coreclr)或 Visual Studio 的 Managed 调试器,配合DOTNET_ReadyToRun=0、关闭 Just My Code 等设置获得最高调试保真度。

掌握这条链路后,无论是追踪运行时启动逻辑、排查 GC/JIT 行为,还是深入框架库实现细节,都能在源码级获得完整的可观测性。

  • 语言运行时
  • 标准库
  • JIT编译
  • 编译器

【免费下载链接】runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.

项目地址:https://gitcode.com/GitHub_Trending/runtime6/runtime
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 18:40:21

TikTok Shop API对接实战:PHP密钥获取与自动化开发指南

做跨境电商的&#xff0c;尤其是多店铺运营的老哥&#xff0c;一定对TikTok Shop后台的重复操作深有体会&#xff1a;商品上架、库存同步、订单整理、物流单号回填、退款单处理……每个店单独登后台翻来覆去点&#xff0c;时间全耗在机械劳动上。所以我一直建议团队尽早接入Tik…

作者头像 李华
网站建设 2026/9/19 18:40:02

如何快速定制 Matter ZAP 插件:面向新手的完整开发指南

如何快速定制 Matter ZAP 插件&#xff1a;面向新手的完整开发指南 【免费下载链接】connectedhomeip Matter (formerly Project CHIP) creates more connections between more objects, simplifying development for manufacturers and increasing compatibility for consumer…

作者头像 李华
网站建设 2026/9/19 18:37:14

华为2288H-V5装系统全指南:RAID配置与驱动加载实战排障

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 18:37:10

fsolve求解电力系统潮流计算:MATLAB实现与工程技巧

简介&#xff1a;电力系统分析中&#xff0c;潮流计算是网络规划与运行的基础&#xff0c;其本质是求解一组节点功率平衡的高阶非线性方程。MATLAB优化工具箱中的fsolve作为通用非线性方程组求根器&#xff0c;只需将节点导纳矩阵Ybus与PQ、PV、松弛节点的物理约束映射为F(x)0的…

作者头像 李华
网站建设 2026/9/19 18:36:57

Swoole 协程 sleep 阻塞,把 Codex 的 Base URL 改到 TaoToken 就能查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华