从 WinDbg 角度理解 .NET7 的AOT玩法

windbg,角度,理解,net7,aot,玩法 · 浏览次数 : 3715

小编点评

**1. AOT 的实现源码在哪里观察刚才的线程栈中的 D:\\a\\_work\\1\\s\\src\\coreclr\ativeaot\Bootstrap\main.cpp?** AOT 的实现代码位于 .NET 6 的 coreclr 源码中,其中新增了一个名为 nativeaot 的目录,这在 .NET 6 的 coreclr 源码中是没有的。 **2. AOT 目前还是一个雏形阶段,大家慎用吧,一旦出了问题,可不好事后调试哦,希望后续加强对 SOS 的支持。** AOT 目前还是一个雏形阶段,需要进一步加强和支持才能完全实现。 **3. AOT 目前还是一个雏形阶段,大家慎用吧,一旦出了问题,可不好事后调试哦,希望后续加强对 SOS 的支持。** AOT 目前仍处于一个雏形阶段,需要进一步加强和支持才能完全实现。 **4. AOT 的实现代码在哪里观察刚才的线程栈中的 D:\\a\\_work\\1\\s\\src\\coreclr\ativeaot\Bootstrap\main.cpp?** AOT 的实现代码位于 .NET 6 的 coreclr 源码中,其中新增了一个名为 nativeaot 的目录,这在 .NET 6 的 coreclr 源码中是没有的。

正文

一:背景

1.讲故事

前几天 B 站上有位朋友让我从高级调试的角度来解读下 .NET7 新出来的 AOT,毕竟这东西是新的,所以这一篇我就简单摸索一下。

二:AOT 的几个问题

1. 如何在 .NET7 中开启 AOT 功能

在 .NET7 中开启 AOT 非常方便,先来段测试代码。


    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("hello world!");
            Debugger.Break();
        }
    }

然后在项目配置上新增 <PublishAot>true</PublishAot> 节点,如下输出:


<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net7.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<PublishAot>true</PublishAot>
	</PropertyGroup>
</Project>

接下来在项目中右键选择 发布,选择一个输出地,这样一个 AOT 程序就完成了。

2. SOS 可以调试 AOT 程序吗

这是很多朋友关心的话题,我们都知道 SOS 是用来撬开 CoreCLR 的,只要能看到 CoreCLR.dll,那 SOS 就能用,接下来用 WinDbg 附加到 ConsoleApp2.exe 上,使用 lm 观察。


0:000> lm
start             end                 module name
00007ff6`11680000 00007ff6`1196f000   ConsoleApp2 C (private pdb symbols)  C:\test\ConsoleApp2.pdb
00007ffe`692b0000 00007ffe`692c3000   kernel_appcore   (deferred)             
00007ffe`6b3e0000 00007ffe`6b47d000   msvcp_win   (deferred)             
00007ffe`6b480000 00007ffe`6b4ff000   bcryptPrimitives   (deferred)             
00007ffe`6b660000 00007ffe`6b687000   bcrypt     (deferred)             
00007ffe`6b690000 00007ffe`6b6b2000   win32u     (deferred)             
00007ffe`6b720000 00007ffe`6b82a000   gdi32full   (deferred)             
00007ffe`6b830000 00007ffe`6b930000   ucrtbase   (deferred)             
00007ffe`6b9e0000 00007ffe`6bca7000   KERNELBASE   (deferred)             
00007ffe`6bcb0000 00007ffe`6bd5a000   ADVAPI32   (deferred)             
00007ffe`6be50000 00007ffe`6be7a000   GDI32      (deferred)             
00007ffe`6be80000 00007ffe`6bf1b000   sechost    (deferred)             
00007ffe`6c180000 00007ffe`6c2a3000   RPCRT4     (deferred)             
00007ffe`6c440000 00007ffe`6c470000   IMM32      (deferred)             
00007ffe`6c600000 00007ffe`6c729000   ole32      (deferred)             
00007ffe`6c730000 00007ffe`6c7ce000   msvcrt     (deferred)             
00007ffe`6cc50000 00007ffe`6cfa4000   combase    (deferred)             
00007ffe`6d160000 00007ffe`6d300000   USER32     (deferred)             
00007ffe`6d410000 00007ffe`6d4cd000   KERNEL32   (deferred)             
00007ffe`6dc50000 00007ffe`6de44000   ntdll      (pdb symbols)          c:\mysymbols\ntdll.pdb\63E12347526A46144B98F8CF61CDED791\ntdll.pdb

从上面的输出中惊讶的发现,居然没有 clrjit.dllcoreclr.dll,前者没有很好理解,后者没有就很奇怪了。。。

既然没看到 coreclr.dll 这个动态链接库,那至少目前用 sos 肯定是无法调试的,即使你强制加载也会报错。


0:000> .load  C:\Users\Administrator\.dotnet\sos64\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

到这里我的个人结论是:目前SOS无法对这类程序进行调试,如果大家用在生产上出现各种内存暴涨CPU爆高问题,就要当心了。

3. AOT 真的没有 CoreCLR 吗

其实仔细想一想,这是不可能的,C# 的出发点就是作为一门托管语言而存在,再怎么发展也不会忘记这个初衷,所谓不忘初心,方得始终。

我们回过头看下 ConsoleApp.exe 这个程序,有没有发现,它居然有 3M 大小。

聪明的朋友应该猜到了,对,就是把 CoreCLR 打包到 exe 中了,这个太牛了,那怎么验证呢? 可以用 IDA 打开一下。

从图中可以清晰的看到各种 gc_heap 相关的函数,这也验证了为什么一个简简单单的 ConsoleApp.exe 有这么大Size的原因。

4. 真的无法调试 AOT 程序吗

在 Windows 平台上就没有 WinDbg 不能调试的程序,所以 AOT 程序自然不在话下,毕竟按托管不行,大不了按非托管调试,这里我们举一个 GC.Collect() 的源码调试吧。

  1. 一段简单的测试代码。

    internal class Program
    {
        static void Main(string[] args)
        {
            Debugger.Break();

            GC.Collect();
        }
    }

  1. 下断点

熟悉 GC 的朋友应该知道我只需用 bp coreclr!WKS::GCHeap::GarbageCollect 下一个断点就可以了,但刚才我也说了,内存中并没有 coreclr 模块,下面的 x 写法肯定会报错。


0:000> x coreclr!WKS::GCHeap::GarbageCollect
                ^ Couldn't resolve 'x coreclr'

那怎么下呢? 先输个 k 观察下调用栈有没有什么新发现。


0:000> k
 # Child-SP          RetAddr               Call Site
00 00000011`5e52f628 00007ff6`7f288c5a     ConsoleApp2!RhDebugBreak+0x2 [D:\a\_work\1\s\src\coreclr\nativeaot\Runtime\MiscHelpers.cpp @ 45] 
01 00000011`5e52f630 00007ff6`7f2f0e28     ConsoleApp2!S_P_CoreLib_System_Diagnostics_Debugger__Break+0x3a [/_/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Diagnostics/Debugger.cs @ 17] 
02 00000011`5e52f6c0 00007ff6`7f1fe37e     ConsoleApp2!ConsoleApp2__Module___StartupCodeMain+0x118
03 00000011`5e52f720 00007ff6`7f1f9540     ConsoleApp2!wmain+0xae [D:\a\_work\1\s\src\coreclr\nativeaot\Bootstrap\main.cpp @ 205] 
04 (Inline Function) --------`--------     ConsoleApp2!invoke_main+0x22 [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 90] 
05 00000011`5e52f770 00007ffe`6d426fd4     ConsoleApp2!__scrt_common_main_seh+0x10c [D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl @ 288] 
06 00000011`5e52f7b0 00007ffe`6dc9cec1     KERNEL32!BaseThreadInitThunk+0x14
07 00000011`5e52f7e0 00000000`00000000     ntdll!RtlUserThreadStart+0x21

我去,int 3 函数也换了,成了 ConsoleApp2!RhDebugBreak+0x2,不过也能看出来,应该将 coreclr 改成 ConsoleApp2 即可,输出如下:


0:000> bp ConsoleApp2!WKS::GCHeap::GarbageCollect
breakpoint 0 redefined
0:000> g
Breakpoint 0 hit
ConsoleApp2!WKS::GCHeap::GarbageCollect:
00007ff6`7f1a9410 48894c2408      mov     qword ptr [rsp+8],rcx ss:00000011`5e52f5f0=0000000000000000

源码也看的清清楚楚,路径也是在 gc 目录下。如下图所示:

4. AOT 的实现源码在哪里

观察刚才的线程栈中的 D:\a\_work\1\s\src\coreclr\nativeaot\Bootstrap\main.cpp 可以发现,新增了一个名为 nativeaot 的目录,这在 .NET 6 的 coreclr 源码中是没有的。

如果有感兴趣的朋友,可以研究下源码。

三:总结

总的来说,AOT 目前还是一个雏形阶段,大家慎用吧,一旦出了问题,可不好事后调试哦,希望后续加强对 SOS 的支持。

图片名称

与从 WinDbg 角度理解 .NET7 的AOT玩法 相似的内容:

从 WinDbg 角度理解 .NET7 的AOT玩法

一:背景 1.讲故事 前几天 B 站上有位朋友让我从高级调试的角度来解读下 .NET7 新出来的 AOT,毕竟这东西是新的,所以这一篇我就简单摸索一下。 二:AOT 的几个问题 1. 如何在 .NET7 中开启 AOT 功能 在 .NET7 中开启 AOT 非常方便,先来段测试代码。 interna

记一次 .NET某工控视觉自动化系统 卡死分析

一:背景 1. 讲故事 今天分享的dump是训练营里一位学员的,从一个啥也不会到现在分析的有模有样,真的是看他成长起来的,调试技术学会了就是真真实实自己的,话不多说,上windbg说话。 二:WinDbg 分析 1. 为什么会卡死 这位学员是从事工控大类下的视觉自动化,也是目前.NET的主战场,这个

记一次 .NET某工业设计软件 崩溃分析

一:背景 1. 讲故事 前些天有位朋友找到我,说他的软件在客户那边不知道什么原因崩掉了,从windows事件日志看崩溃在 clr 里,让我能否帮忙定位下,dump 也抓到了,既然dump有了,接下来就上 windbg 分析吧。 二:WinDbg 分析 1. 为什么崩溃在 clr 一般来说崩溃在clr

从安装到配置,教你用Argo CD对接CCE集群完成测试、生产部署

本文使用两个CCE集群模拟测试及生产环境,使用gitlab仓库作为应用部署yaml文件存储仓库,通过Argo CD对接不同CCE集群完成测试、生产环境业务部署。

从PDF到OFD,国产化浪潮下多种文档格式导出的完美解决方案

前言 近年来,中国在信息技术领域持续追求自主创新和供应链安全,伴随信创上升为国家战略,一些行业也开始明确要求文件导出的格式必须为 OFD 格式。OFD 格式目前在政府、金融、税务、教育、医疗等需要文件开放、共享和长期保存的行业中广泛应用。这种趋势在未来几年内将进一步增强。 相较于 PDF,OFD 在

.net入行三年的感想回顾

从21年毕业到现在,还差几天就三年了 工作后才知道,工作年限分为1年以下 、3~5年、5~10年、晋升老板,每段都有每段的故事和总结 回顾下我的前三年工作心路,思考下未来发展之路(emmm,我是觉得我是干不了一辈子程序员的 我的工作地点不在大城市,因为我爸不让我出去,家里也不是很缺钱,所以薪资不会辣

嵌入式行业入行6年的一点小感想

从18年毕业到现在已经工作6年了。 熟悉招聘的人都知道,对于工作年限来说,工作开始的前3年是一个分水岭,3~5年是一个分水岭,5~10年又是一个分水岭。10年以上又是一个分水岭...... 我曾经以工作第3年为一个节点,做过一些小小的总结;现在又是3年了,我想借此机会简单概括一下这些年(21年到~2

从JDK8升级到JDK17

一、概述 鉴于JDK8已经是老古董,还有性能问题,兼且各个公司已经不再维护1.8的JDK,所以升级公司的核心产品之一的后端到JDK到17是相对要紧的事情。 通过升级到jdk17,具有以下好处: 不要在头疼同时适应两个jdk,放下适应JDK8的负担 在生产环境基本上只需要部署一个jdk即可 具有更好的

我的日常AI使用

从去年年初开始,AI技术真正走入了我们的日常生活。从OpenAI到如今字节跳动的coze,我们通过AI大模型可以做很多事情,工具和平台众多,如何选择和使用有必要总结一下。 编程和debug方面 尽管gpt-4和gpt-4o确实很强,但对于持续代码改进和代码调试方面,依然不够好,并且它对于非Plus会

从 Docker Hub 拉取镜像受阻?这些解决方案帮你轻松应对

最近一段时间 Docker 镜像一直是 Pull 不下来的状态,感觉除了挂,想直连 Docker Hub 是几乎不可能的。更糟糕的是,很多原本可靠的国内镜像站,例如一些大厂和高校运营的,也陆续关停了,这对我们这些个人开发者和中小企业来说是挺难受的。之前,通过这些镜像站,我们可以快速、方便地获取所