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

一:背景

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 程序就完成了。

115f224eae1adab52bdf626a2ecfd08d.png

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 大小。

de983be422b9dccdc7668340c79827d4.png

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

14fcaf547a2c8f56e32355be3b9e6f9c.png

从图中可以清晰的看到各种 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 目录下。如下图所示:

0ad8d822cb3dcdc68ef9ba614432a64a.png

4. AOT 的实现源码在哪里

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

47029b5a90fd84f6fbbbe900e9883da5.png

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

三:总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281201.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【PPT】适配器模式 和 桥接模式

【PPT】适配器模式 和 桥接模式目录【PPT】适配器模式 和 桥接模式一、PPT 截图1.0、封面和目录1.1、设计模式概述1.2、结构型模式特点1.3、适配器模式1.4、桥接模式二、参考资料及 PPT 获取方法独立观察员 2022 年 11 月 15 日为之前公司准备的分享PPT&#xff0c;后来没用上。…

Flask 【第七篇】Flask中的wtforms使用

一、简单介绍flask中的wtforms WTForms是一个支持多个web框架的form组件&#xff0c;主要用于对用户请求数据进行验证。 安装&#xff1a; pip3 install wtforms 二、简单使用wtforms组件 1、用户登录 具体代码&#xff1a; from flask import Flask,render_template,request,…

为了避免内存攻击,美国国家安全局提倡Rust、C#、Go、Java、Ruby 和 Swift,但将 C 和 C++ 置于一边...

本文翻译自两篇文章&#xff0c;第一篇是对美国国家安全局在“软件内存安全”网络安全信息表的解读&#xff0c;第二篇是普及什么是内存安全&#xff0c;为什么它很重要&#xff1f;第一篇 为了避免内存攻击&#xff0c;美国国家安全局提倡Rust、C#、Go、Java、Ruby 和 Swift&a…

.NET周报【11月第2期 2022-11-15】

国内文章统一的开发平台.NET 7正式发布https://www.cnblogs.com/shanyou/archive/2022/11/09/16871945.html在 2020 年规划的.NET 5功能终于在.NET 7 完成了&#xff0c;为微软和社区一起为多年来将不同的开发产品统一起来的努力加冕&#xff0c;未来只有一个.NET, 回顾.NET 20…

chrome 悬停大图插件_Google Chrome浏览器的悬停卡:我不想要的我最喜欢的新东西

chrome 悬停大图插件If you only have a handful of open tabs in Google Chrome, it’s easy to tell what they are. But as you start to collect more tabs (or make the window smaller), it gets harder. That’s where Hover Cards come in. 如果您在Google Chrome浏览器…

GitHub Codespaces 安装 .NET 7

本文主要介绍如何在 GitHub Codespaces 这个云上 IDE 环境中安装 .NET 7背景GitHub 的 Codespaces 可以让我们随时随地编写代码&#xff0c;一些简单的修改也非常方便快捷。特别是 .NET 7 发布后&#xff0c;一些可以直接升级的小项目只需要更改配置就可以了&#xff0c;我们可…

chrome怎么隐藏浏览器_如何使用Google Chrome的隐藏阅读器模式

chrome怎么隐藏浏览器Chrome 75 has a hidden “Reader” mode that strips web pages down to the bare minimum to make them easier to, well, read. But it’s not enabled by default—here’s how to get it now. Chrome 75具有隐藏的“阅读器”模式&#xff0c;可将网页…

angularjs中使用swiper时不起作用,最后出现空白位

controller.js中定义swipers指令&#xff1a; var moduleCtrl angular.module(newscontroller,[infinite-scroll,ngTouch,news.service]) .directive(swipers,swipers); swipers.$inject [$timeout]; function swipers($timeout) {return {restrict: "EA",scope: {…

使用Jupyter记事本记录和制作.NET可视化笔记

前言&#xff1a;对于记录笔记的工具特别多&#xff0c;不过对于程序员来说&#xff0c;记录笔记程序代码运行结果演示可以同时存在&#xff0c;无疑会极大增加我们的笔记的可读性和体验感。以前在写python的时候&#xff0c;使用jupyter的体验很好&#xff0c;所以此处做一个基…

火狐上如何使用谷歌翻译插件_将Google翻译功能添加到Firefox

火狐上如何使用谷歌翻译插件Are you looking for a quick no-fuss way to translate webpages? Then you will want to take a good look at the Translate extension for Firefox. 您是否正在寻找一种快速简便的方法来翻译网页&#xff1f; 然后&#xff0c;您将需要很好地了…

桌面显示激活windows_愚蠢的怪胎技巧:如何在桌面上显示Windows版本

桌面显示激活windowsHave you ever noticed during all the beta releases of Windows, there’s always a Windows version on the desktop in the lower right-hand corner? Here’s how that “feature” is enabled or disabled. 您是否曾经在Windows的所有beta版本中都注…

怎样取消outlook约会_快速提示:在Outlook 2010中设置和取消约会

怎样取消outlook约会Getting everyone in one place at the same time for appointments can be daunting at times. Outlook makes it easy to setup appointments and invite attendees as well, and here we look at doing it in Outlook 2010. 同时让每个人都集中在一个地方…

重视和解决 ABP 分布式事件乱序问题

ABP Framework 5.0 实现了单体应用场景下&#xff0c;收件箱和发件箱的事件严格顺序性。但在微服务或多数据库场景下&#xff0c;由于网络时延和设施效率的限制&#xff0c; 分布式事件将不再是 Linearizability [1] 的&#xff0c;因此必然会存在物理时间上的收件乱序。借用 D…

个人博客建站方案推荐

1.服务器选择 正值双十一来临之际各大服务器提供商又大量的优惠活动&#xff0c;各位要步入个人站长行列的小哥们时机要把握好了&#xff0c;我个人使用过阿里云的服务器&#xff0c;腾讯云的服务器&#xff0c;华为云的服务器。其实&#xff0c;个人感觉就放个博客&#xff0c…

android启用hdcp_如何在Android上启用优先收件箱(和设置仅重要通知)

android启用hdcpYesterday Google released an updated Gmail application for Android 2.2 phones that supports the Priority Inbox feature—and more importantly, allows you to change your notifications to only alert you for important email. Let’s take a look. …

.Net CLR GC plan_phase二叉树和Brick_table

楔子Plan_Phase(GC的计划阶段)很早就接触了&#xff0c;但是后面一直没用到&#xff0c;忘记了&#xff0c;此次又用到了&#xff0c;几乎忘光了&#xff0c;费了很大力气理解它&#xff0c;记录下&#xff0c;以免又忘记了。主题计划阶段(plan_phase)主要就两个部分&#xff0…

scrapy爬虫启示录-小伙子老夫看你血气方刚这本《爬虫秘录》就传给你了

文章来源&#xff1a; IT源点 第一章 误入歧途 每个学习爬虫的人都有一颗爱美的心&#xff0c;俺也是一样的。那么多的美眉图片&#xff0c;不薅下来&#xff0c;没了谁负责。于是夜里孤枕难眠的老男孩开始了他的撸码之旅。从此在学习爬虫&#xff0c;学习Python的道路上越走…

自己设置假期的日历控件_在假期旅行时使用PC娱乐自己

自己设置假期的日历控件Staying connected may be hard no matter what network you are on, and in flight Wi-Fi isn’t pervasive enough to count on. Here are tips and tricks to keep yourself entertained when unplugged and traveling. 无论您使用什么网络&#xff0…

.Net CLR异常和windows C++ 异常调用栈简析

楔子前面一篇研究了下C异常的&#xff0c;这篇来看下&#xff0c;CLR的异常内存模型&#xff0c;实际上都是一个模型&#xff0c;承继自windows异常处理机制。不同的是&#xff0c;有VC编译器(vcruntime.dll&#xff09;接管的部分&#xff0c;被CLR里面的函数ProcessCLRExcept…

Codeforces936C. Lock Puzzle

给个串&#xff0c;只能用操作shift x表示把后面x个字符翻转后放到串的前面。问s串怎么操作能变t串。n<2000&#xff0c;操作次数<6100。 打VP时这转来转去的有点晕。。。 可以想一种逐步构造的方法&#xff0c;即从一个小的完成构造的部分通过一顿操作&#xff0c;在不影…