J'essaie de générer une trace de pile par programmation. Quand mes utilisateurs ont un crash, en particulier un accident, il est difficile de leur parler à travers le processus d'obtenir un vidage afin que je puisse résoudre le problème. Dans le passé, une fois qu'ils m'enverraient la trace, je croisais les adresses dans le fichier Intermediate/foo.map pour déterminer quelle fonction était le problème (est-ce le meilleur moyen?)Comment obtenir une pile-trace significative en utilisant MiniDumpWriteDump
J'ai construit une bibliothèque de divers exemples j'ai trouvé autour du filet, pour produire un minidump pour faciliter mon travail. J'ai mis en scène un crash, mais la trace de pile que je reçois du fichier minidump est très différente d'une trace de pile en direct que j'obtiens en attachant windbg. Des exemples de deux ci-dessous:
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 est pas à moi, et je n'ai pas source/symboles. Le Main.dll est injecté dans game.exe et fournit des fonctionnalités frontales pour charger des DLL supplémentaires depuis le jeu. Le code de débogage et le plantage par étapes se trouvent dans Minidump.dll. Après que Main.dll charge Minidump, il appelle AfterLoad(), qui définit le filtre d'exception, puis déclenche le blocage. Le code minidump pertinent est ci-dessous:
Lorsque j'ai ouvert le MiniDump.dmp je l'ai pointé vers tous mes fichiers de symboles (à l'exception de game.exe, que je n'ai pas) et cette partie semble fonctionner . Je le pointe vers le binaire game.exe depuis que j'ai ça. La trace de pile que j'en retire n'est vraiment pas utile. Mon but ultime est que l'utilisateur puisse simplement charger la DLL, provoquer le plantage et m'envoyer le fichier de vidage par courrier électronique. Ensuite, je vais attacher les fichiers de symboles et les binaires et être en mesure de diagnostiquer le problème pour eux. Est-ce que je fais quelque chose de mal, ou est-ce que ce n'est pas possible d'obtenir ce que je veux?
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();
}
J'ai essayé de couper une partie de la graisse de tous les détails pour simplifier le problème, mais je peux être plus explicite si nécessaire. J'ai trouvé le bon article sur CodeProject, et j'ai essayé de trouver plus d'informations de base à lire pour m'aider à comprendre le problème, mais ce que j'ai pu trouver ne m'a pas aidé à comprendre qu'ils étaient juste étape par étape pour l'obtenir en cours d'exécution (ce qui est déjà fait). Quelqu'un at-il une idée de ce que je fais de mal, ou peut-être me diriger vers une lecture pertinente?
Après la suggestion de Sergei j'ai fait .ecxr en windbg et a obtenu un meilleur rendement, mais il ne correspond toujours pas la trace que je reçois quand je droit accroche windbg jusqu'à processus et déclencher l'accident. Voici la trace minidump;
*** 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
et la trace d'attacher le débogueur au processus
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
Je ne suis pas la source de game.exe (je l'ai pour les DLL qui est l'endroit où l'erreur est), mais j'ai décompilé game.exe et voici ce qui est au jeu + 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 [email protected] 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 [email protected] endp
Mon erreur que je suis le déclenchement est en Minidump.dll, mais ce code en haut de la pile est en game.exe. Il pourrait y avoir beaucoup de choses à l'intérieur du game.exe que je ne connais pas, pourrait-il être détournant l'erreur que je déclenche en quelque sorte? I.E., je déclenche l'erreur dans la DLL, mais quelque chose d'installation dans le jeu.exe capture le flux du programme avant que le filtre d'exception qui écrit le minidump est appelé? Si c'est le cas, lorsque j'attache le débogueur au processus, déclenche l'erreur et obtiens la bonne sortie qui indique que l'erreur est dans ma DLL, cela signifie que game.exe ne capture pas le flux du programme avant le débogueur peut faire la trace. Comment pourrais-je faire en sorte que mon code minidump se comporte de la même façon ... C'est entrer dans un territoire avec lequel je ne suis pas très familier. Des idées?
Je pourchassé plus en arrière, et la fonction d'appel que l'on, a cette ligne en elle:
.text:00575A8D mov esi, offset aCrashDumpTooLa ; "Crash dump too large to send.\n"
Donc, je pense que game.exe est Détournement l'exception de le faire de son propre décharge avant mon le code essaie d'obtenir le vidage. Et puis ma trace de décharges est juste une trace du processus de vidage de game.exe ...
Réponse
Je l'ai compris. Je ne suis pas sûr de savoir comment répondre à mon propre message, alors voici l'affaire.
.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
Ceci est issu de game.exe. Il se trouve que game.exe fait son propre minidump. Mon minidump se déclenchait après le leur, alors ce que je voyais dans ma trace de pile était une trace de leur processus de vidage. J'ai trouvé un fichier dmp dans le répertoire d'installation du jeu et une fois que j'ai chargé mes symboles, il montrait la sortie correcte que je recherchais.
Donc, c'est beaucoup plus proche; il fait en sorte que l'interprétation des windbgs ressemble plus au débogueur VS, mais elle ne correspond pas au débogage en direct que j'obtiens en accroissant le windbg directement au processus. Ajout des nouveaux détails au post ci-dessus. – Kmus
Hehe, j'ai presque oublié: Merci d'avoir aidé. – Kmus