我想为特定应用程序的第一次机会异常生成转储,该应用程序每天以随机间隔启动几次,一次运行多个实例。
我试过什么
过程转储
要使用 procdump,我必须知道 PID 或等待进程启动。随着多个实例的启动,这将无法开始监控所有启动的实例
标志
使用 gflags 我可以附加一个调试器,但我不想手动继续每个进程,我不知道如何自动化该进程。我尝试在 gflags 中使用 procdump 作为调试器,但我不知道如何将进程传递给 procdump。
我想为特定应用程序的第一次机会异常生成转储,该应用程序每天以随机间隔启动几次,一次运行多个实例。
我试过什么
过程转储
要使用 procdump,我必须知道 PID 或等待进程启动。随着多个实例的启动,这将无法开始监控所有启动的实例
标志
使用 gflags 我可以附加一个调试器,但我不想手动继续每个进程,我不知道如何自动化该进程。我尝试在 gflags 中使用 procdump 作为调试器,但我不知道如何将进程传递给 procdump。
编写了一个简单的 powershell 脚本来枚举同一 exe 的多个实例的 pid,并在发生如下异常时将其转储
脚本
$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
在我的评论中,我将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 设置(影响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 将自动传递应用程序名称和参数,这可能是此处参数顺序奇怪的原因。
对 WinDbg 做同样的工作要多得多。您需要以正确的位数运行 WinDbg 以获得良好的结果,并且捕获所有第一次机会异常并不简单。
"E:\debug\x86\WinDbg.exe" -G -Q -c $$<e:\debug\dump.dbg
-G
应用程序终止时跳过最终断点(最小化用户交互)-Q
跳过“保存工作区”问题(最小化用户交互)-c $$<dump.dbg
运行脚本
该脚本将在初始断点处运行,因此不要使用该-g
选项(跳过初始断点)。相反,设置当时的东西并继续g
。脚本可能看起来像
sxe -c ".dump /ma /u e:\debug\dotnet.dmp;g" clr
g
但是,请注意,这仅涵盖 .NET 第一次机会异常,调试器将等待其他异常的输入。如果要完成此操作,则需要为所有类型的异常设置命令,这很不方便(另请参阅此答案)。