6

我正在尝试使用 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;

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

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

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

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

谢谢。

4

2 回答 2

2

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

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

已知进程 A 如何以及何时获取进程 B 的小型转储?如果 A 确实在调试 B,当 WaitForDebugEvent 返回一个 EXCEPTION_DEBUG_EVENT 时,该信息在 info 结构中可用。

如果 A 没有调试 B,那么可能 B 通过某种 IPC 机制告诉 A “嘿,我崩溃了,进行 minidump”。在这种情况下,B 可以自己进行转储,或者通过相同的 IPC 机制将异常信息传递给 A。尽管如此,这也是有问题的,原因与在崩溃过程中调用 MiniDumpWriteDump 有问题的原因相同,如果事情发生了爆炸,事情这可能是你需要告诉 A 的事情。

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

如果 A 只是定期对 B 进行小型转储,则不一定会有任何异常,因此在这种情况下您可以只传递 NULL。

请注意,如果您打算做类似的事情

WaitForSingleObject(handleToProcessB, INFINITE);
MiniDumpWriteDump(handleToProcessB, ...)

这是行不通的。操作系统保留了很少的东西,主要是进程的退出代码,而不是虚拟地址空间和您需要进行小型转储的堆栈。

于 2010-11-13T20:40:24.010 回答
0

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

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

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

希望这会有所帮助

于 2010-11-08T14:26:59.207 回答