New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DRWTSN32] Initial rough implementation #145
Changes from 6 commits
0c7af50
18226eb
ffc7010
3188b5c
c3c955a
d8c93c7
54e275e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* | ||
* 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> | ||
|
||
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()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about using UNICODE everywhere? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Eventually I want to print this to a file instead of stdout, and then UNICODE is not really convenient. |
||
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 0x406d1388: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Magic value There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough :) |
||
/* 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; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing code source copyright header.