Skip to content

Commit

Permalink
[DRWTSN32] Implement basic crash report functionality
Browse files Browse the repository at this point in the history
On application crash, drwtsn32 will attach to the application and try to get a dump, consisting of:
- List of loaded modules
- List of loaded threads
- Per thread, a stacktrace
- Per thread, a small hexdump from the stack
- Per thread, a dump of the most common registers

This dump is saved to the desktop, and the user is notified of the dump being dropped there.

CORE-14180
reactos#145
  • Loading branch information
learn-more authored and dfbag7 committed Jan 14, 2018
1 parent 8850233 commit b90f99a
Show file tree
Hide file tree
Showing 8 changed files with 749 additions and 0 deletions.
1 change: 1 addition & 0 deletions base/applications/CMakeLists.txt
Expand Up @@ -6,6 +6,7 @@ add_subdirectory(charmap)
add_subdirectory(clipbrd)
add_subdirectory(cmdutils)
add_subdirectory(control)
add_subdirectory(drwtsn32)
add_subdirectory(dxdiag)
add_subdirectory(extrac32)
add_subdirectory(findstr)
Expand Down
18 changes: 18 additions & 0 deletions base/applications/drwtsn32/CMakeLists.txt
@@ -0,0 +1,18 @@

PROJECT(drwtsn32)

set_cpp(WITH_RUNTIME WITH_EXCEPTIONS WITH_STL)

list(APPEND CPP_SOURCE
drwtsn32.cpp
main.cpp
stacktrace.cpp
sysinfo.cpp
drwtsn32.h
precomp.h)

add_executable(drwtsn32 ${CPP_SOURCE})
add_pch(drwtsn32 precomp.h CPP_SOURCE)
set_module_type(drwtsn32 win32gui)
add_importlibs(drwtsn32 dbghelp psapi advapi32 shell32 msvcrt user32 kernel32 ntdll)
add_cd_file(TARGET drwtsn32 DESTINATION reactos/system32 FOR all)
158 changes: 158 additions & 0 deletions base/applications/drwtsn32/drwtsn32.cpp
@@ -0,0 +1,158 @@
/*
* PROJECT: Dr. Watson crash reporter
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Debug loop
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
*/

#include "precomp.h"
#include <psapi.h>

#define MS_VC_EXCEPTION_THREAD_NAME 0x406d1388

ModuleData::ModuleData(void* addr)
{
BaseAddress = addr;
Size = 0;
Unloaded = false;
}

void ModuleData::Update(HANDLE hProcess)
{
MODULEINFO mi = {0};
GetModuleInformation(hProcess, (HMODULE)BaseAddress, &mi, sizeof(mi));
assert(BaseAddress == mi.lpBaseOfDll);
Size = mi.SizeOfImage;

ModuleName.resize(MAX_PATH);
DWORD dwLen = GetModuleFileNameExA(hProcess, (HMODULE)BaseAddress, &ModuleName[0], ModuleName.size());
ModuleName.resize(dwLen);
}


ThreadData::ThreadData(HANDLE handle)
: Handle(handle)
{
memset(&Context, 0, sizeof(Context));
}

void ThreadData::Update()
{
Context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_DEBUG_REGISTERS;
GetThreadContext(Handle, &Context);
}

DumpData::DumpData()
:ProcessID(0)
,ThreadID(0)
,ProcessHandle(NULL)
,Event(NULL)
,FirstBPHit(false)
{
memset(&ExceptionInfo, 0, sizeof(ExceptionInfo));
}


bool UpdateFromEvent(DEBUG_EVENT& evt, DumpData& data)
{
switch(evt.dwDebugEventCode)
{
case CREATE_PROCESS_DEBUG_EVENT:
{
data.ProcessPath.resize(MAX_PATH);
DWORD len = GetModuleFileNameExA(evt.u.CreateProcessInfo.hProcess, NULL, &data.ProcessPath[0], data.ProcessPath.size());
if (len)
{
data.ProcessPath.resize(len);
std::string::size_type pos = data.ProcessPath.find_last_of("\\/");
if (pos != std::string::npos)
data.ProcessName = data.ProcessPath.substr(pos+1);
}
else
{
data.ProcessPath = "??";
}
if (data.ProcessName.empty())
data.ProcessName = data.ProcessPath;

CloseHandle(evt.u.CreateProcessInfo.hFile);
data.ProcessID = evt.dwProcessId;
data.ProcessHandle = evt.u.CreateProcessInfo.hProcess;
data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateProcessInfo.hThread);
}
break;
case CREATE_THREAD_DEBUG_EVENT:
data.Threads[evt.dwThreadId] = ThreadData(evt.u.CreateThread.hThread);
break;
case EXIT_THREAD_DEBUG_EVENT:
{
ThreadMap::iterator it = data.Threads.find(evt.dwThreadId);
if (it != data.Threads.end())
{
data.Threads.erase(it);
}
}
break;
case LOAD_DLL_DEBUG_EVENT:
CloseHandle(evt.u.LoadDll.hFile);
for (size_t n = 0; n < data.Modules.size(); ++n)
{
if (data.Modules[n].BaseAddress == evt.u.LoadDll.lpBaseOfDll)
{
data.Modules[n].Unloaded = false;
return true;
}
}
data.Modules.push_back(ModuleData(evt.u.LoadDll.lpBaseOfDll));
break;
case UNLOAD_DLL_DEBUG_EVENT:
for (size_t n = 0; n < data.Modules.size(); ++n)
{
if (data.Modules[n].BaseAddress == evt.u.UnloadDll.lpBaseOfDll)
data.Modules[n].Unloaded = true;
}
break;
case OUTPUT_DEBUG_STRING_EVENT: // ignore
break;
case EXCEPTION_DEBUG_EVENT:
if (evt.u.Exception.dwFirstChance)
{
switch(evt.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_BREAKPOINT:
if (!data.FirstBPHit)
{
data.FirstBPHit = true;

if (data.Event)
{
SetEvent(data.Event);
CloseHandle(data.Event);
data.Event = NULL;
}
return true;
}
break;
case MS_VC_EXCEPTION_THREAD_NAME:
/* Thread name */
return true;
case DBG_CONTROL_C:
case DBG_CONTROL_BREAK:
return true;
}
}
data.ExceptionInfo = evt.u.Exception;
data.ThreadID = evt.dwThreadId;
return false;
case EXIT_PROCESS_DEBUG_EVENT:
//assert(FALSE);
return false;
case RIP_EVENT:
//assert(FALSE);
return false;
default:
assert(false);
}
return true;
}

68 changes: 68 additions & 0 deletions base/applications/drwtsn32/drwtsn32.h
@@ -0,0 +1,68 @@
/*
* PROJECT: Dr. Watson crash reporter
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: Project header
* COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org)
*/

#pragma once


struct ModuleData
{
std::string ModuleName;
void *BaseAddress;
DWORD Size;
bool Unloaded;


ModuleData(void* addr);
void Update(HANDLE hProcess);
};

struct ThreadData
{
HANDLE Handle;
CONTEXT Context;

ThreadData(HANDLE handle = NULL);

void Update();
};

typedef std::vector<ModuleData> ModuleList;
typedef std::map<DWORD, ThreadData> ThreadMap;

class DumpData
{
public:
std::string ProcessPath;
std::string ProcessName;
DWORD ProcessID;
DWORD ThreadID;
HANDLE ProcessHandle;
ModuleList Modules;
ThreadMap Threads;
EXCEPTION_DEBUG_INFO ExceptionInfo;
HANDLE Event;
bool FirstBPHit;

DumpData();
};

#define NEWLINE "\r\n"

/* main.cpp */
void xfprintf(FILE* stream, const char *fmt, ...);

/* drwtsn32.cpp */
bool UpdateFromEvent(DEBUG_EVENT& evt, DumpData& data);

/* sysinfo.cpp */
void PrintSystemInfo(FILE* output, DumpData& data);

/* stacktrace.cpp */
void BeginStackBacktrace(DumpData& data);
void PrintStackBacktrace(FILE* output, DumpData& data, ThreadData& thread);
void EndStackBacktrace(DumpData& data);

0 comments on commit b90f99a

Please sign in to comment.