gpt4 book ai didi

debugging - 我如何使用MiniDumpWriteDump获得有意义的堆栈跟踪

转载 作者:行者123 更新时间:2023-12-03 17:17:55 26 4
gpt4 key购买 nike

我正在尝试以编程方式生成堆栈跟踪。当我的用户崩溃时,尤其是随机崩溃时,很难说服他们完成转储的过程,这样我就可以解决问题。在过去,一旦他们向我发送了跟踪信息,我就会将其中的地址交叉引用到Intermediate / foo.map文件中,以找出问题出在哪里(这是最好的方法吗?)

我从网上发现的各种示例中构建了一个库,以输出一个小型转储文件,使我的工作更轻松。我上演了崩溃,但是从minidump文件中获得的堆栈跟踪与从附加windbg获得的实时堆栈跟踪完全不同。两者的示例如下:

MiniDump.dmp:

KERNELBASE.dll!76a6c42d()
[Frames below may be incorrect and/or missing, no symbols loaded for KERNELBASE.dll]
KERNELBASE.dll!76a6c42d()
kernel32.dll!75bd14bd()
game.exe!00759035()
game.exe!00575ba3()

WinDbg.exe:
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp @ 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp @ 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp @ 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp @ 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095

game.exe不是我的,并且我没有源代码/符号。 Main.dll被注入(inject)game.exe中,并且它提供了前端功能以从游戏中加载其他DLL。调试代码和临时崩溃位于Minidump.dll中。 Main.dll加载Minidump后,它将调用AfterLoad(),后者将设置异常过滤器,然后触发崩溃。相关的小型转储代码如下:

当我打开MiniDump.dmp时,我将其指向了我所有的符号文件(game.exe除外,我没有),而该部分似乎正在运行。我确实将其指向game.exe二进制文件,因为我已经知道了。我得到的堆栈跟踪信息实际上并没有帮助。我的最终目标是用户可以仅加载DLL,导致崩溃并通过电子邮件将转储文件发送给我。然后,我将附加符号文件和二进制文件,并能够为它们诊断问题。我是在做错事,还是无法得到我想要的东西。
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

LONG WINAPI WriteDumpFilter(struct _EXCEPTION_POINTERS *pExceptionPointers)
{
HANDLE hFile = NULL;
HMODULE hDll = NULL;
MINIDUMPWRITEDUMP pMiniDumpWriteDump = NULL;
_MINIDUMP_EXCEPTION_INFORMATION ExceptionInformation = {0};

//load MiniDumpWriteDump
hDll = LoadLibrary(TEXT("DbgHelp.dll"));
pMiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump");

//create output file
hFile = CreateFile( _T( "C:\\temp\\MiniDump.dmp"),
GENERIC_READ|GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

//bail if we don't have a file
if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
//get exception information
ExceptionInformation.ThreadId = GetCurrentThreadId();
ExceptionInformation.ExceptionPointers = pExceptionPointers;
ExceptionInformation.ClientPointers = TRUE;

//write the debug dump
pMiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpWithFullMemory, &ExceptionInformation,
NULL, NULL );


//close the debug output file
CloseHandle(hFile);
}

return EXCEPTION_EXECUTE_HANDLER;
}

VOID crashme() {int* foo = 0; *foo = 0;}

VOID AfterLoad(VOID)
{
SetUnhandledExceptionFilter(WriteDumpFilter);
crashme();
}

我试图从所有细节中去除一些赘肉,以简化问题,但如果需要,我可以更加明确。我在CodeProject上找到了不错的文章,并且尝试查找更多背景信息以帮助我理解问题,但是我发现的内容并不能帮助我理解它们只是逐步解决问题的方法。运行(已经是)。有人知道我在做什么错吗,或者可以将我指向相关的阅读文章?

在Sergei的建议下,我在windbg中执行了.ecxr并获得了更好的输出,但是当我将windbg直接挂接到进程并触发崩溃时,它仍然与我得到的跟踪不匹配。这是最小转储跟踪;
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0018e774 00759035 e06d7363 00000001 00000003 KERNELBASE!RaiseException+0x58
0018e7b4 00575ba3 00000000 00000000 00000001 game+0x359035
0018fc50 0057788a 009855ef 0018fdcb 00000001 game+0x175ba3
0018fc78 77b7e013 012d9230 002d91d0 002d9200 game+0x17788a
0018fc90 77ba9567 00290000 00000000 002d91d0 ntdll!RtlFreeHeap+0x7e
0018fd6c 0076ece2 0018ff78 007e1b7e ffffffff ntdll!LdrRemoveLoadAsDataTable+0x4e0
002bbc38 5c306174 61666544 00746c75 5d4c3055 game+0x36ece2
002bbc3c 61666544 00746c75 5d4c3055 8c000000 0x5c306174
002bbc40 00746c75 5d4c3055 8c000000 00000101 0x61666544
002bbc44 5d4c3055 8c000000 00000101 01000000 game+0x346c75
002bbc48 8c000000 00000101 01000000 00000000 0x5d4c3055
002bbc4c 00000000 01000000 00000000 0000006e 0x8c000000

以及将调试器附加到进程的跟踪
0:000:x86> kv
ChildEBP RetAddr Args to Child
00186f44 00bc8ea9 19460268 0018a9b7 03f70a28 Minidump!crashme+0x2 (FPO: [0,0,0]) (CONV: cdecl) [c:\project\debug\minidump.cpp @ 68]
0018795c 00b9ef31 0018796c 03f56c00 6532716d Main!LoadPlugin+0x339 (FPO: [1,642,4]) (CONV: cdecl) [c:\project\main\pluginloader.cpp @ 129]
00188968 00b9667d 19460268 0018a9ac 00000000 Main!Command+0x1f1 (FPO: [2,1024,4]) (CONV: cdecl) [c:\project\main\commands.cpp @ 2617]
*** WARNING: Unable to verify checksum for C:\Game\game.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Game\game.exe
0018b1a8 005b5095 19460268 0018beac 00000000 Main!Hook::Detour+0x52d (FPO: [2,2570,0]) (CONV: thiscall) [c:\project\main\hook.cpp @ 275]
WARNING: Stack unwind information not available. Following frames may be wrong.
0018b1b4 00000000 19495200 19495200 00000006 game+0x1b5095

我没有game.exe的源代码(我的错误源是DLL),但是我反编译了game.exe,这就是game + 0x359035的内容。
.text:00759001 ; =============== S U B R O U T I N E =======================================
.text:00759001
.text:00759001 ; Attributes: library function bp-based frame
.text:00759001
.text:00759001 ; __stdcall _CxxThrowException(x, x)
.text:00759001 __CxxThrowException@8 proc near ; CODE XREF: .text:0040100Fp
.text:00759001 ; sub_401640+98p ...
.text:00759001
.text:00759001 dwExceptionCode = dword ptr -20h
.text:00759001 dwExceptionFlags= dword ptr -1Ch
.text:00759001 nNumberOfArguments= dword ptr -10h
.text:00759001 Arguments = dword ptr -0Ch
.text:00759001 var_8 = dword ptr -8
.text:00759001 var_4 = dword ptr -4
.text:00759001 arg_0 = dword ptr 8
.text:00759001 arg_4 = dword ptr 0Ch
.text:00759001
.text:00759001 push ebp
.text:00759002 mov ebp, esp
.text:00759004 sub esp, 20h
.text:00759007 mov eax, [ebp+arg_0]
.text:0075900A push esi
.text:0075900B push edi
.text:0075900C push 8
.text:0075900E pop ecx
.text:0075900F mov esi, offset unk_853A3C
.text:00759014 lea edi, [ebp+dwExceptionCode]
.text:00759017 rep movsd
.text:00759019 mov [ebp+var_8], eax
.text:0075901C mov eax, [ebp+arg_4]
.text:0075901F mov [ebp+var_4], eax
.text:00759022 lea eax, [ebp+Arguments]
.text:00759025 push eax ; lpArguments
.text:00759026 push [ebp+nNumberOfArguments] ; nNumberOfArguments
.text:00759029 push [ebp+dwExceptionFlags] ; dwExceptionFlags
.text:0075902C push [ebp+dwExceptionCode] ; dwExceptionCode
.text:0075902F call ds:RaiseException
.text:00759035 pop edi
.text:00759036 pop esi
.text:00759037 leave
.text:00759038 retn 8
.text:00759038 __CxxThrowException@8 endp

我触发的错误是在Minidump.dll中,但堆栈顶部的这段代码在game.exe中。我可能不知道game.exe内部发生了很多事情,这可能是劫持了我以某种方式触发的错误吗?即,我触发了DLL中的错误,但是game.exe中的某些设置会在调用写入minidump的异常过滤器之前捕获程序流?

如果是这种情况,当我将调试器附加到进程时,触发错误并获得指向错误的正确输出,该错误指向我的DLL中的错误,这意味着game.exe在调试器可以执行之前没有捕获程序流。痕迹。我如何使我的minidump代码表现出相同的行为...这正在进入我并不十分熟悉的领域。有任何想法吗?

我往后追,调用该函数的函数包含以下内容:
.text:00575A8D                 mov     esi, offset aCrashDumpTooLa ; "Crash dump too large to send.\n"

因此,我认为game.exe在我的代码尝试获取转储之前,正在劫持异常以执行其自身的转储。然后我的转储跟踪只是game.exe的转储过程的跟踪...

回答

我知道了。我不确定如何回答自己的帖子,所以这很重要。
.text:0057494A                 push    offset aDbghelp_dll ; "DbgHelp.dll"
.text:0057494F call ds:LoadLibraryA
.text:00574955 test eax, eax
.text:00574957 jz short loc_5749C8
.text:00574959 push offset aMinidumpwrited ; "MiniDumpWriteDump"
.text:0057495E push eax ; hModule
.text:0057495F call ds:GetProcAddress
.text:00574965 mov edi, eax
.text:00574967 test edi, edi
.text:00574969 jz short loc_5749C8
.text:0057496B mov edx, lpFileName
.text:00574971 push 0 ; hTemplateFile
.text:00574973 push 80h ; dwFlagsAndAttributes
.text:00574978 push 2 ; dwCreationDisposition
.text:0057497A push 0 ; lpSecurityAttributes
.text:0057497C push 0 ; dwShareMode
.text:0057497E push 40000000h ; dwDesiredAccess
.text:00574983 push edx ; lpFileName
.text:00574984 call ds:CreateFileA
.text:0057498A mov esi, eax
.text:0057498C cmp esi, 0FFFFFFFFh
.text:0057498F jz short loc_5749C8
.text:00574991 call ds:GetCurrentThreadId
.text:00574997 push 0
.text:00574999 push 0
.text:0057499B mov [ebp+var_1C], eax
.text:0057499E lea eax, [ebp+var_1C]
.text:005749A1 push eax
.text:005749A2 push 0
.text:005749A4 push esi
.text:005749A5 mov [ebp+var_18], ebx
.text:005749A8 mov [ebp+var_14], 1
.text:005749AF call ds:__imp_GetCurrentProcessId
.text:005749B5 push eax
.text:005749B6 call ds:GetCurrentProcess
.text:005749BC push eax
.text:005749BD call edi
.text:005749BF push esi ; hObject
.text:005749C0 call ds:CloseHandle
.text:005749C6 jmp short loc_574A02

多数民众赞成从game.exe。事实证明game.exe确实是自己的小型转储。我的小型转储是在他们的转储之后触发的,因此我在堆栈跟踪中看到的是他们转储过程的跟踪。我在游戏的安装目录中找到了一个dmp文件,将符号加载到其中后,它会显示我想要的正确输出。

最佳答案

你还好吧当您打开生成的小型转储时,请在加载符号后执行

.ecxr

首先将上下文设置为保存在 ExceptionInformation参数 MiniDumpWriteDump()中的内容。然后,您将获得合法的堆栈跟踪。

在我工作的地方,我们使用了类似的转储生成机制。

虽然有一些 future 的陷阱。您想检查是否在诸如 abort()调用之类的事件上触发了转储捕获机制。

为此,请检查 _set_invalid_parameter_handler()signal(SIGABRT, ...)

关于debugging - 我如何使用MiniDumpWriteDump获得有意义的堆栈跟踪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35384873/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com