刚刚在DebugInfo.com上看完了Effective minidumps系列文章,看得是相当的亢奋。想到其中很多知识点在工作中可以用到,以提高咱CER系统的效率,就感到一阵兴奋。原来MiniDumpWriteDump API还可以这样来使用的。
首先是用户数据流(User Date Streams),这个功能对于自定义Dump文件内容相当有用。Dump文件一般提取的信息都是Executable的进程内部的一些状态,但是如果能够加上一些诸如:应用程序的配置文件,应用程序所访问的注册表,等信息的话,就会对我们的调式提供更多有帮助的信息。实现起来也很方便,几乎就是对几个Struct进行填充:
char Message1[] = "This is the first data stream…"; // 这个就是要写入到Dump文件中的用户信息
const ULONG32 cFirstStreamID = LastReservedStream + 1;
MINIDUMP_USER_STREAM UserStreams[1];
const ULONG32 cFirstStreamID = LastReservedStream + 1;
MINIDUMP_USER_STREAM UserStreams[1];
UserStreams[0].Type = cFirstStreamID;
UserStreams[0].Buffer = Message1;
UserStreams[0].BufferSize = sizeof(Message1);
UserStreams[0].Buffer = Message1;
UserStreams[0].BufferSize = sizeof(Message1);
MINIDUMP_USER_STREAM_INFORMATION musi;
musi.UserStreamCount = 2;
musi.UserStreamArray = UserStreams;
musi.UserStreamArray = UserStreams;
BOOL rv = MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), hFile, mdt, (pep != 0) ? &mdei : 0, &musi, 0 );
不过这些信息貌似并不是在调式器中可见的,而且我还没有发现有什么命令可以提取出这个我们插进去的数据。一般还是通过MiniDumpReadDumpStream函数来获取。尽管不是很方便,但是至少也提供了一些让我们在Dump文件中添加额外信息的一种方法。
其次就是关于策略的问题。这个问题相对还是比较重要的,因为它直接影响到了我们开发人员对于Dump文件的分析。这让我联想到最近我在做的一个CER bucket: 920861,出错的原因可以很容易地分析出来是一个heap corruption,但是由于我们的CER都没有抓取heap上的内存内容,所以就无法察看到底是什么样的一个heap结构,破坏这个堆的是哪种类型的数据对象。郁闷了半天,还是没办法解决。另外一个关于dll和symbol文件不匹配的处理方式,以后我会在这里share一些。
对于Dump文件的抓取策略,主要是在文件的内容是否充足和文件的大小进行折中,不同的应用程序一般应该选择不同的策略来满足开发以及日后产品发布后的排错工作
。
共有4种常用的类型:
1. TinyDump:是使文件尺寸最小的一种策略。
Type:MiniDumpNormal;
Callback:IncludeThreadCallback,去除了所有的线程信息;IncludeModuleCallback,去除了所有的模块信息。
所以这种Dump文件尺寸极端的小,使用debugger是无法打开的。一般使用MiniDumpReadDumpStream来获取信息。
2. MiniDump:不是普通意义上的minidump,它还包含了一部分对于Heap的内存信息。通常是异常栈中每个函数帧中,某一指针所指向的内存区域会被Dump下来,这样就可以解决我上面题到的那种heap corruption的错误。所以我觉得这个对于我们的CER特别有用,也许我该和boss提起这方面的事情。
3. MidiDump:提供的内存信息更多,甚至会包含进一些代码段中的内容。不过这个对CER作用提高不是很明显,因为许多模块以及它对应的Symbol文件我们都可以去微软的Symbol Server上去下载。
4. MaxiDump:这个几乎就是包含了该有的一切,所以产生的Dump文件非常大,虽然对于调试帮助很明显,但是不便于在网络上传输。客户如果发现一个Dump文件的发送要那么长时间,估计肯定就Cancel操作了。
OK,就总结这么多。懒得结尾|||