SOS.DLL、SOSEX.DLL这两个就是用来对.NET程序在Windows调试工具中起到翻译作用的调试器扩展。简单讲就是,这两个组件是.NET项目组专门开发出来用来对.NET应用程序进行方便调试用的,当然不用这两个扩展也能调试.NET程序,只不过就会很困难,会被很多细节束缚住。有了这个调试扩展之后,我们就可以让原生Windows调试器正确的翻译出.NET相关概念。
图1:(Windows调试工具执行流程)
所有对.NET程序发起的调试会话都要经过.NET调试扩展组件进行翻译才行,也就是要使用.NET调试扩展的调试命令来调试.NET程序。上图中,我们如果要想调试.NET程序就需要将.NET调试扩展组件加载到Windows调试工具中去,然后才能方便在Windows调试工具中使用。
.NET调试扩展包分为两个,一个是SOS.DLL,该扩展包是.NET平台的一部分,属于官方版本。而SOSEX.DLL是微软的一名叫“Steve Johnson”软件工程师开发,属于个人维护的,用来增强SOS.DLL功能的,在SOSEX.DLL有很多功能比较强大的扩展命令。
具体的帮助文档可以查看该工程师的博客来了解详情。这两个版本用来调试不同环境的程序的,如果你的程序是运行在32位环境下,就用32位的SOSEX,同理,用在64位下就用64位SOSEX。
而SOS.DLL扩展包是跟着.NETFramework一起安装的,地址位于:C:WindowsMicrosoft.NETFrameworkv4.0.30319。如果你是64位系统的话地址就是:
C:WindowsMicrosoft.NETFramework64v4.0.30319。在这两个地址下面都可以找到SOS.dll文件,不同的目录下对应于调试不同机器类型的.NET程序。
有了这两个扩展包之后就可以在WinDbg中对.NET程序进行分析了,具体使用我们后面会介绍。
2.3.调试系统的基本流程及架构(.NETDAC概念、mscordacwks.dll)
有一个很重要的原理我觉得很有必要讲一下,就是.NETDAC概念。
其实.NETDAC也就是.NET Data Access .NET数据访问层,这个是专门用来提供给SOS.DLLSOSEXDLL或者其他调试扩展包使用的,所有的调试扩展组件必须通过这个DAC才能访问到.NET运行时的数据,所以在初次使用SOS的时候会经常碰见加载错误的mscordacwks.dll文件,此文件就是DAC的物理文件。
这个文件和SOS扩展文件一样,都有这不同的版本,当加载不同类型的.NET程序时会使用到不同版本的mscordacwks.dll文件,当然大部分情况下此文件时自动加载的,只有出现你分析的文件与生成调试文件的环境不一致时才会出现头疼的问题。
图5:(mscordacwks.dll位置)
当你知道这个组件是工作于此位置时,当出现跟它相关的错误提示时你就不需要担心了,无非就是文件加载的位置或者版本不匹配而已。
SOS扩展也是可以和VisualStudio进行集成的,这样真的方便了我们调试一些性能要求比较高的程序,当程序运行一段时间后我们用VS附加到进程,然后查看一些重要的对象数据,但是此时我们看不到.NET运行时的一些数据,比如:对象的代龄,托管堆的大小,线程池的任务等。通过集成SOS扩展会让我们对程序的运行时有了一个更加方便的跟踪。
图10:(打开本地代码调试)
设置断点,然后在”即时窗口“(调试->窗口->即时)中加载扩展SOS.DLL。
图11:(在VisualStudio2012中加载SOS.dll扩展)
这样的便利性大大提高我们在调试程序内存方面、线程方面的好处,我们可以适当的做压力测试,然后Attach process,执行SOS扩展命名来查看内存问题,当需要调试程序逻辑时在单步调式C#代码,一举两得。
对.NET程序分析当然是需要加载SOS扩展了。加载SOS扩展有两个命令可以使用,第一个是.load C:WindowsMicrosoft.NETFrameworkv4.0.30319SOS.dll,.load命令是要给出sos.dll绝对路径的。第二个是.loadby sos modulename,.loadby 命令是可以根据已经加载的模块名称来加载SOS.dll扩展。使用第一个命令有一个问题就是,我们需要人工的判断当前环境到底是需要什么版本的SOS扩展,而使用.loadby是可以根据已经加载的模块来自动的查找对应的SOS扩展。
0:000> .load C:WindowsMicrosoft.NETFrameworkv4.0.30319SOS.dll
0:000> .loadby sos.dll clrjit
使用.loadby 命令很容易的就可以加载SOS扩展,而不需要自己去判断当前程序是.NET什么版本的。