2023年1月

在调试.NET应用程序中的转储文件时,有时我们可能会遇到这样的情况:我们希望得到引用RCW对象的System.__ComObject包装器引用的COM对象。
你可能会认为抛弃这个系统。也许你能给出答案,但事实并非如此。

如下例子

Name: System.__ComObject

MethodTable:
79307098EEClass: 790dfa34

Size:
16(0x10) bytes

GC Generation:
2(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)

Fields:

MT Field
Offset Type
VT Attr Value Name
79330740 400018a 4System.Object0 instance 00000000__identity79333178 400027e 8 ...ections.Hashtable 0 instance 00000000 m_ObjectToDataMap

什么是!dumpheap?

!dumpheap是来自SOS扩展的命令,用于转储托管堆的内容。您可以获得堆上当前活动的所有托管对象的所有地址和一些附加信息。
在WinDbg的最后两个版本中,SOS实际上被PSSCOR取代,它有一个很好的帮助系统。对于大多数命令,您只需键入“!help commandName”,例如,“!help dumpheap”,您将获得关于参数和如何使用的详细帮助。

!dumpheap 参数

  • -stat–只输出堆上所有类型对象的统计摘要、它们的计数和它们自己的大小(不带引用)
  • -nostrings–排除字符串的输出(不使用-stat时)。
  • -gen X–仅输出属于X代的对象,其中X可以具有以下值:对于1.1–0、1、2和3,对于大型对象(大于85Kb的对象,没有其引用)。对于1.0,除了使用-1而不是3。
  • -min X–忽略小于X的对象(其中X是字节数)。
  • -max X–忽略大于X的对象(其中X是字节数)。
  • -mt MethodTable–仅列出具有给定MethodTable的对象。
  • -type type–仅列出类型名为math类型的子字符串的对象。
  • -缓存–将对象保存在内部缓存中以供以后使用(有助于加快速度,而不是重新扫描堆)。
  • -lx–只打印每个堆中的X个项,而不是所有对象。
  • -short–只打印出对象地址。用于与.foreach命令组合使用。
  • -fix START END–使用给定的起始地址和结束地址,只扫描这些地址之间的堆。

注意:如果我没记错的话,-cache、-nostring和-short都是在最近两个版本的SOS(以前是PSSCOR)中添加的新命令,其余命令在大多数版本的SOS中都可以使用相当长的时间。

-short参数

你可以说,第二代的内容是如何打印的。在-short命令之前,你必须运行“!dumpheap-gen2“将输出复制到记事本,解析它,只留下对象地址,然后你就可以手动运行!do对每个地址执行操作,或将.foreach与/f命令一起使用。
现在,使用-short,您只需运行以下命令行:

.foreach ( obj { !dumpheap -gen 2 -short } ) { !do ${obj} }

 

!clrstack输出,如下所示:

0:019> !clrstack 
OS Thread Id: 0x5d0 (19) 
ESP      EIP 
0f31f340 7c80bef7 [HelperMethodFrame_1OBJ: 0f31f340] 
0f31f398 1449167a 
0f31f3c4 144915e6 
0f31f3f4 10d81b48 
0f31f4b4 793e25cf 
0f31f4bc 79366b3d 
0f31f4d4 793e2734 
0f31f4e8 793e26ac 
0f31f678 79e7c0e3 [GCFrame: 0f31f678]

需要做一些事情来解决这个问题。

正确版本的MSCORDACWKS.dll

你可以用两种方法得到这个

将符号路径设置为srv*c:\mycache*http://msdl.microsoft.com/download/symbols

或者

通过从获取转储的计算机上复制它,它将位于Framework\<version>目录中。这个mscordacwks.dll需要复制到您的符号路径,如果您使用多个版本,并区分它们,您可以将其命名为mscordacwks_x86_x86_2.0.50727.42.dll。在我的机器上,因为我使用的版本太多了,所以我有一个c:\dac\x86和一个c:\dac\x64目录来存储这些文件。

兼容版本的sos.dll

sos.dll可以在framework\<version>目录中找到,并且需要与转储中使用的框架的体系结构和主要版本相匹配。如果您的计算机上的框架的次要版本与您获取转储的计算机之间的差异太大,可以尝试复制机器上。也可以使用psscor2.dll。

 

有人在论坛上问过关于在混合模式下编辑并继续(EnC)的问题。不能在启用混合模式(interop)调试的情况下使用托管EnC。这是CLR调试服务的一个限制。互操作调试和EnC都是复杂的特性;将它们结合起来将是一个巨大的测试矩阵,而且成本非常高。因此,如果你有C和本地C++解决方案,你的选择是:

人们可以使用术语“模块时间戳”来表示文件时间戳和Image头时间戳。虽然他们通常非常接近,但他们是不同的,不会是相同的。下面是一个比较/对比:

File timestamp Image header timestamp
What is it? This is tracked by the file system, and includes several metrics such as when the file was created, when it was last modified, and when it was last accessed. Emitted by the compiler and stored in the image header. Thus, it's in the contents of the file and separate from the meta-information tracked by the filesystem.
Who normally sets it? The file system. The compiler (which then generally creates a file to persists the results to, thus the file and image timestamps are usually very close)
Underlying storage 64-bit FileTime structure 32-bit time_t structure.
Win32 exposure kernel32!GetFileTime IMAGE_FILE_HEADER, exposed via the ImageHelp library.Matt Pietrek has an excellent article about cracking the PE file to get information like this. (The PE file format is publicly specced).
.NET exposure In .NET, these are accessible as System.DateTime objects via File.GetCreationTime, File.GetLastAccessTime, File.GetLastWriteTime. I don't think there are any .Net APIs to get these. (does anybody want them?).  The Pdb2Xml writer in MDbg sample alludes to this a little.BradA tells how to convert time_t to a System.DateTime.    

映像时间戳是您在调试器下看到的。例如,windbg的“lmv”命令将时间戳显示为原始32位值,并将其转换为有用的值:

Image name: notepad.exe
Timestamp: Tue Aug 03 23:05:55 2004 (41107CC3)
CheckSum: 00014F7F

可以从资源管理器查看文件时间戳。右键单击该文件并显示属性。为了进行比较,来自同一文件的时间戳通过文件系统:

创建时间:2004年8月9日星期一上午11:11:33

修改日期:2004年8月4日星期三上午4:00:00

访问时间:今天,2007年1月18日,晚上7:22:56


映像时间戳(和其他相关数据)也是转储文件中捕获的内容(请参阅MINIDUMP_MODULE)。因此,当调试器希望将小型转储中的模块与磁盘上的实际模块关联时,它可以使用映像头中的时间戳和校验和。这与PDB匹配的工作原理类似。