Skip to content
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

Merged
merged 7 commits into from Jan 6, 2018
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)
156 changes: 156 additions & 0 deletions base/applications/drwtsn32/drwtsn32.cpp
@@ -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"
Copy link
Contributor

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.

#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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about using UNICODE everywhere?
But then the STL stuff should be like std::wstring & co.
Unless you want to use ATL?

Copy link
Member Author

Choose a reason for hiding this comment

The 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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic value

Copy link
Member Author

Choose a reason for hiding this comment

The 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;
}

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);