mirror of
https://github.com/sslab-gatech/winnie
synced 2026-06-08 17:35:47 +00:00
174 lines
4.6 KiB
C++
174 lines
4.6 KiB
C++
#include "pch.h"
|
|
#pragma warning(disable:4996)
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <tchar.h>
|
|
#include <pathcch.h>
|
|
|
|
#define dank_perror(msg) { \
|
|
LPCSTR _errorText = NULL; \
|
|
FormatMessageA( \
|
|
FORMAT_MESSAGE_FROM_SYSTEM \
|
|
| FORMAT_MESSAGE_ALLOCATE_BUFFER \
|
|
| FORMAT_MESSAGE_IGNORE_INSERTS, \
|
|
NULL, \
|
|
GetLastError(), \
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
|
|
(LPSTR)&_errorText, \
|
|
0, \
|
|
NULL); \
|
|
if (_errorText) \
|
|
{ \
|
|
printf(msg " failed: %s\n", _errorText); \
|
|
LocalFree((HLOCAL) _errorText); \
|
|
_errorText = NULL; \
|
|
} \
|
|
else \
|
|
{ \
|
|
printf(msg " failed\n"); \
|
|
} \
|
|
}
|
|
|
|
#define SafeCloseHandle(h) {if (h && h != INVALID_HANDLE_VALUE) CloseHandle(h); }
|
|
|
|
void handle_exception(DWORD pid, PMINIDUMP_EXCEPTION_STREAM ExceptionInfo, LPVOID pMinidump)
|
|
{
|
|
PCONTEXT ContextRecord = (CONTEXT*)(((LPBYTE)pMinidump) + ExceptionInfo->ThreadContext.Rva);
|
|
|
|
uint64_t faultAddress = NULL;
|
|
if (ExceptionInfo->ExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
|
{
|
|
// ExceptionInformation[0] is 1 for write fault, 0 for read fault.
|
|
faultAddress = ExceptionInfo->ExceptionRecord.ExceptionInformation[1];
|
|
}
|
|
printf("Process %d: Uncaught exception %08x at instruction %llx, referencing %llx\n",
|
|
pid,
|
|
ExceptionInfo->ExceptionRecord.ExceptionCode,
|
|
ExceptionInfo->ExceptionRecord.ExceptionAddress,
|
|
faultAddress
|
|
);
|
|
}
|
|
|
|
// mainly inspired by https://github.com/doo/CrashRpt/blob/master/trunk/processing/crashrptprobe/MinidumpReader.cpp
|
|
void parse_minidump(DWORD pid, LPCWSTR filename)
|
|
{
|
|
printf("Parsing minidump %ls (pid %d)\n", filename, pid);
|
|
|
|
HANDLE hFile = NULL, hMapping = NULL;
|
|
LPVOID pMinidump = NULL;
|
|
PMINIDUMP_EXCEPTION_STREAM pExceptionStream;
|
|
|
|
while ((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
if (GetLastError() == ERROR_SHARING_VIOLATION)
|
|
{
|
|
// File busy
|
|
Sleep(10);
|
|
continue;
|
|
}
|
|
dank_perror("CreateFile");
|
|
goto fail;
|
|
}
|
|
printf("hFile = %x\n", hFile);
|
|
|
|
hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
if (!hMapping)
|
|
{
|
|
dank_perror("CreateFileMapping");
|
|
goto fail;
|
|
}
|
|
printf("hMapping = %x\n", hMapping);
|
|
|
|
pMinidump = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
|
|
if (!pMinidump)
|
|
{
|
|
dank_perror("MapViewOfFile");
|
|
goto fail;
|
|
}
|
|
printf("Minidump mapped at = %p\n", pMinidump);
|
|
|
|
PMINIDUMP_DIRECTORY pmd;
|
|
LPVOID pStream;
|
|
ULONG streamSize;
|
|
if (!MiniDumpReadDumpStream(pMinidump, ExceptionStream, &pmd, &pStream, &streamSize))
|
|
{
|
|
dank_perror("MiniDumpReadDumpStream");
|
|
goto fail;
|
|
}
|
|
|
|
pExceptionStream = (MINIDUMP_EXCEPTION_STREAM*)pStream;
|
|
if (!pExceptionStream || streamSize < sizeof(MINIDUMP_EXCEPTION_STREAM))
|
|
{
|
|
printf("Corrupt minidump exception info\n");
|
|
goto fail;
|
|
}
|
|
|
|
handle_exception(pid, pExceptionStream, pMinidump);
|
|
|
|
fail:
|
|
if (pMinidump) UnmapViewOfFile(pMinidump);
|
|
SafeCloseHandle(hMapping);
|
|
SafeCloseHandle(hFile);
|
|
}
|
|
|
|
int parse_minidump_filename_pid(LPCWSTR filename)
|
|
{
|
|
WCHAR pid[MAX_PATH];
|
|
int len = wcslen(filename);
|
|
if (wcscmp(filename + len - 4, L".dmp")) return -1;
|
|
int i = len - 4;
|
|
while (i-->0 && filename[i] != L'.');
|
|
if (i < 0) return -1;
|
|
if (i == 0) return -1;
|
|
wcsncpy_s(pid, filename + i + 1, len - 5 - i);
|
|
return _wtoi(pid);
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
LPCSTR minidump_path = "C:\\sslab\\minidumps";
|
|
if (argc > 1)
|
|
{
|
|
minidump_path = argv[1];
|
|
}
|
|
|
|
WCHAR minidump_dir[MAX_PATH];
|
|
mbstowcs(minidump_dir, minidump_path, sizeof(minidump_dir));
|
|
|
|
HANDLE hDirectory = CreateFileW(minidump_dir, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
|
if (hDirectory == INVALID_HANDLE_VALUE)
|
|
{
|
|
dank_perror("CreateFile");
|
|
return 1;
|
|
}
|
|
|
|
printf("OK, listening for minidumps\n");
|
|
#define BUFFER_SIZE 0x400
|
|
BYTE* buffer = (BYTE*)HeapAlloc(GetProcessHeap(), 0, BUFFER_SIZE);
|
|
FILE_NOTIFY_INFORMATION* notif = (FILE_NOTIFY_INFORMATION*)buffer;
|
|
while (TRUE)
|
|
{
|
|
DWORD notifSize;
|
|
RtlZeroMemory(buffer, BUFFER_SIZE);
|
|
if (!ReadDirectoryChangesW(hDirectory, buffer, BUFFER_SIZE, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE, ¬ifSize, NULL, NULL) || notifSize < sizeof(FILE_NOTIFY_INFORMATION))
|
|
{
|
|
dank_perror("ReadDirectoryChangesW");
|
|
ExitProcess(GetLastError());
|
|
}
|
|
|
|
printf("%x %ls\n", notif->Action, notif->FileName);
|
|
if (notif->Action == FILE_ACTION_MODIFIED)
|
|
{
|
|
int pid = parse_minidump_filename_pid(notif->FileName);
|
|
if (pid <= 0)
|
|
{
|
|
printf("Couldn't parse pid from dump filename %ls\n", notif->FileName);
|
|
continue;
|
|
}
|
|
WCHAR path[MAX_PATH];
|
|
PathCchCombine(path, sizeof(path), minidump_dir, notif->FileName);
|
|
parse_minidump(pid, path);
|
|
}
|
|
}
|
|
}
|