有没有办法知道另一个抛出异常的进程中的线程ID?

时间:2010-11-04 09:04:16

标签: debugging dump crash-dumps minidump

我正在尝试使用MiniDumpWriteDump()API从另一个进程A转储崩溃的进程B.我这样做是因为MSDN这样说:

  

应该调用MiniDumpWriteDump   如果有的话,从一个单独的过程   可能,而不是从内部   目标进程被抛弃。

MiniDumpWriteDump()定义如下:

BOOL WINAPI MiniDumpWriteDump(
  __in  HANDLE hProcess,
  __in  DWORD ProcessId,
  __in  HANDLE hFile,
  __in  MINIDUMP_TYPE DumpType,
  __in  PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  __in  PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  __in  PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

特别是,ExceptionParam的类型为 PMINIDUMP_EXCEPTION_INFORMATION ,其定义如下:

typedef struct _MINIDUMP_EXCEPTION_INFORMATION {
  DWORD               ThreadId;
  PEXCEPTION_POINTERS ExceptionPointers;
  BOOL                ClientPointers;
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION;

现在我想知道如何准备以下两个参数:

的ThreadId 抛出异常的线程的标识符。

ExceptionPointers 指向EXCEPTION_POINTERS结构的指针,指定异常时与异常和处理器上下文无关的计算机描述。

在进程A中运行时,如何在进程B中获取错误的线程id和异常指针?

感谢。

2 个答案:

答案 0 :(得分:2)

  

指向MINIDUMP_EXCEPTION_INFORMATION结构的指针,该结构描述导致生成minidump的客户端异常。如果此参数的值为NULL,则minidump文件中不包含任何异常信息。

尽管参数标记为__in而不是__in_opt,但您确实可以在此处传递NULL。要从目标流程首先获取该信息,您的流程无论如何都必须进行调试。

过程A如何以及何时采取过程B的小型转储?如果A确实在调试B,当WaitForDebugEvent返回EXCEPTION_DEBUG_EVENT时,信息在信息结构中可用。

如果A没有调试B,那么也许B通过一些IPC机制告诉A“嘿我正在崩溃,拿一个小型转储”。在这种情况下,B可以自己获取转储或通过相同的IPC mechansim将异常信息传递给A.再次,这是有问题的,因为在崩溃过程中调用MiniDumpWriteDump是有问题的,如果事情正在爆炸,那么事情可能已经爆炸的可能是你需要告诉A的事情。

可能有A对B进行转储的另一种机制是A安装为JIT调试器,在这种情况下,A将调试B,您可以使用调试API来获取异常信息。

如果A只是定期获取B的小型转储,那么就不一定会有任何异常,所以在这种情况下你只能传递NULL。

请注意,如果您打算执行类似

的操作
WaitForSingleObject(handleToProcessB, INFINITE);
MiniDumpWriteDump(handleToProcessB, ...)

这不起作用。操作系统保留了很少的东西,主要是进程的退出代码,而不是虚拟地址空间和你需要使用minidump的堆栈。

答案 1 :(得分:0)

要在特定进程名称的给定异常上创建自动转储,我的建议是使用DebugDiag或AdPlus。这些是您可以配置的外部(和免费!)软件。

如果您真的想自己编写转储,可以在进程B中执行:MSDN警告您这不是一个好主意,因为内存不足,堆栈溢出或堆栈损坏等令人讨厌的错误(列表不是详尽的)肯定会使用内存和堆栈,所以你可能最终没有转储(并且一个非常糟糕的进程崩溃)。根据我的经验,这是非常罕见的(我曾经在一个非常紧张的分布式C ++软件上工作)。 对于其他例外,应该没问题。在这种情况下,您可以使用异常转换器(请参阅_set_se_translator)或向量异常处理程序(请参阅AddVectoredContinueHandler)或函数GetExceptionInformation()来获取EXCEPTION_RECORD结构(可能还有其他方法我不知道)。 / p>

在进程B中的异常之后从进程A创建转储意味着您必须复制有关该异常的所有信息,并警告进程A它必须转储具有此异常的内容。这将消耗内存和堆栈,因此您将具有与之前解释相同的限制。

希望有所帮助