在应用程序的多个实例的第一次机会异常时生成转储

Generate dumps on first chance exceptions of multiple instances of an application

我想为每天多次随机启动的特定应用程序的第一次机会异常生成转储,运行 一次有多个实例。

我尝试了什么

Procdump

要使用 procdump,我必须知道 PID 或等待进程启动。由于启动了多个实例,这将无法开始监视所有已启动的实例

gflags

我可以使用 gflags 附加调试器,但我不想手动继续每个进程,而且我不知道如何自动执行该进程。我尝试在 gflags 中使用 procdump 作为调试器,但我不知道如何将进程传递给 procdump。

在我的评论中,我将 AeDebug 注册表设置中的 %ld 参数与 GFlags 的参数混淆了。但是,AeDebug 在这里没有用,因为它只在应用程序崩溃时起作用,而这里不是这种情况。

我正在使用以下演示应用程序来生成一些第一次机会异常:

using System;    
namespace ThrowSomeFirstChance
{
    static class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(args[0]);
            try
            {
                throw new ApplicationException("Exception 1");
            }
            catch (Exception){}
            try
            {
                throw new ApplicationException("Exception 2");
            }
            catch (Exception){}
            Console.ReadLine();
        }
    }
}

GFlags + ProcDump

GFlags 设置(影响 Image File Execution Options 注册表项)的整个想法是 运行 调试器下的应用程序从应用程序一开始就真正调试各种事情.因此,如果您使用 GFlags 设置,则无法传递进程 ID,因为此时进程尚未启动。该进程必须由调试器启动。

使用以下 GFlags 设置,ProcDump 适合我:

E:\debug\procdump.exe -ma -e 1 -n 4 -x e:\debug\dumps

哪里

  • -ma获取全内存,对.NET有用
  • -e 1 捕获第一次机会异常
  • -n 4 指定要生成的最大转储数量(某些应用程序可能会生成数百个异常)
  • -x <dump folder> <application> <arguments> 指定要启动的可执行文件

    请注意 -x 选项似乎不完整,但这没关系,因为 Windows 将自动传递应用程序名称和参数,这可能是此处参数顺序奇怪的原因。

GFlags + WinDbg

对 WinDbg 做同样的工作要多得多。您需要 运行 以正确的位数运行 WinDbg 以获得良好的结果,并且捕获所有第一次机会异常并不简单。

"E:\debug\x86\WinDbg.exe"  -G -Q -c $$<e:\debug\dump.dbg 
  • -G 应用程序终止时跳过最终断点(最小化用户交互)
  • -Q 跳过 "Save workspace" 问题(尽量减少用户交互)
  • -c $$<dump.dbg运行一个脚本

    脚本将在初始断点处 运行,所以不要使用 -g 选项(跳过初始断点)。相反,设置当时的东西并继续 g。脚本可能看起来像

    sxe -c ".dump /ma /u e:\debug\dotnet.dmp;g" clr
    g
    

    但是请注意,这仅涵盖 .NET 第一次机会异常,调试器将等待其他异常的输入。如果你想完成这个,你需要为所有类型的异常设置命令,这很不方便(另见 this answer)。

编写了一个简单的 powershell 脚本来枚举同一 exe 的多个实例的 pids 并在出现如下异常时转储它

脚本

$b=($a= Get-Process fkiss).count
0..($b-1)|%{$c = ("-e 1 -n 10 {0}" -f $a[$_].Id);Start-Process procdump $c}  

编译并双击此代码两次

#include <stdio.h>
#include <windows.h>
void main (void){
    int i=0,a=2,b=0;
    while (i < 20) {
    __try {
        Sleep(6000);
        printf("%d\n",a/b);
    }__except(EXCEPTION_EXECUTE_HANDLER) {
        b=2;
        printf("%d\n",a/b);
        Sleep(6000);
    }
    i++;
    b=0;
    }
}

目录中有 20 个转储

powershell -c (get-childitem *.dmp).count
20

它们确实反映了这两种情况 使用

for %I in (dir *.dmp) do dumpchk %I | grep -i "-e 1 -n "

产出

>dumpchk fkiss.exe_160126_045712.dmp   | grep -i "-e 1 -n "
Loading dump file fkiss.exe_160126_045712.dmp
*** "E:\sysint\procdump.exe" -e 1 -n 10 3084
*** "E:\sysint\procdump.exe" -e 1 -n 10 3084

>dumpchk fkiss.exe_160126_045714.dmp   | grep -i "-e 1 -n "
Loading dump file fkiss.exe_160126_045714.dmp
*** "E:\sysint\procdump.exe" -e 1 -n 10 3108
*** "E:\sysint\procdump.exe" -e 1 -n 10 3108

>dumpchk fkiss.exe_160126_045724.dmp   | grep -i "-e 1 -n "
Loading dump file fkiss.exe_160126_045724.dmp
*** "E:\sysint\procdump.exe" -e 1 -n 10 3084
*** "E:\sysint\procdump.exe" -e 1 -n 10 3084