Extract the call stack from the minidump file and display the call stack if PDB files are available
This commit is contained in:
parent
d69d190dc3
commit
a5099699e8
5 changed files with 140 additions and 3 deletions
|
|
@ -195,3 +195,6 @@ void I_OpenShellFolder(const char* folder)
|
|||
[filemgr changeCurrentDirectoryPath:currentpath];
|
||||
}
|
||||
|
||||
void I_AddMinidumpCallstack(const FString& minidumpFilename, FString& text, FString& logText)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,3 +388,6 @@ void I_OpenShellFolder(const char* infolder)
|
|||
free(curdir);
|
||||
}
|
||||
|
||||
void I_AddMinidumpCallstack(const FString& minidumpFilename, FString& text, FString& logText)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#ifdef _MSC_VER
|
||||
#include <dbghelp.h>
|
||||
#include <signal.h>
|
||||
#include <Dbgeng.h>
|
||||
|
||||
#pragma comment(lib, "dbgeng.lib")
|
||||
|
||||
class CrashReporter
|
||||
{
|
||||
|
|
@ -404,3 +407,123 @@ const BYTE CrashReporter::patch_bytes[5] = { 0x33, 0xC0, 0xC2, 0x04, 0x00 };
|
|||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
class DbgPtr
|
||||
{
|
||||
public:
|
||||
DbgPtr() { Ptr = nullptr; }
|
||||
DbgPtr(const DbgPtr& other) { Ptr = other.Ptr; if (Ptr) Ptr->AddRef(); }
|
||||
DbgPtr(DbgPtr&& move) { Ptr = move.Ptr; move.Ptr = nullptr; }
|
||||
~DbgPtr() { reset(); }
|
||||
|
||||
void reset() { if (Ptr) Ptr->Release(); Ptr = nullptr; }
|
||||
T* get() { return Ptr; }
|
||||
|
||||
static IID GetIID() { return __uuidof(T); }
|
||||
|
||||
void** InitPtr() { return (void**)TypedInitPtr(); }
|
||||
T** TypedInitPtr() { reset(); return &Ptr; }
|
||||
|
||||
DbgPtr& operator=(const DbgPtr& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (Ptr)
|
||||
Ptr->Release();
|
||||
Ptr = other.Ptr;
|
||||
if (Ptr)
|
||||
Ptr->AddRef();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T* () const { return Ptr; }
|
||||
T* operator ->() const { return Ptr; }
|
||||
|
||||
T* Ptr;
|
||||
};
|
||||
|
||||
void I_AddMinidumpCallstack(const FString& minidumpFilename, FString& text, FString& logText)
|
||||
{
|
||||
DbgPtr<IDebugClient5> client;
|
||||
HRESULT result = DebugCreate(client.GetIID(), client.InitPtr());
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
DbgPtr<IDebugControl> control;
|
||||
result = client->QueryInterface(control.GetIID(), control.InitPtr());
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
DbgPtr<IDebugSymbols3> symbols;
|
||||
result = client->QueryInterface(symbols.GetIID(), symbols.InitPtr());
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
result = client->OpenDumpFileWide(minidumpFilename.WideString().c_str(), 0);
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
result = control->WaitForEvent(0, INFINITE);
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
ULONG eventType, processId = 0, threadId = 0, descriptionSize = 0;
|
||||
char descriptionText[1024] = {};
|
||||
result = control->GetLastEventInformation(&eventType, &processId, &threadId, nullptr, 0, nullptr, descriptionText, 1024, &descriptionSize);
|
||||
if (SUCCEEDED(result) && descriptionSize > 0)
|
||||
{
|
||||
std::string description(descriptionText, descriptionSize - 1);
|
||||
text = description;
|
||||
logText.AppendFormat("\n%s\n", description.c_str());
|
||||
}
|
||||
|
||||
DEBUG_STACK_FRAME frames[20] = {};
|
||||
ULONG filled = 0;
|
||||
result = control->GetStackTrace(0, 0, 0, frames, 20, &filled);
|
||||
if (FAILED(result))
|
||||
return;
|
||||
|
||||
for (ULONG i = 0; i < filled; i++)
|
||||
{
|
||||
char nameBuffer[1024] = {};
|
||||
ULONG nameSize = 0;
|
||||
ULONG64 displacement = 0;
|
||||
result = symbols->GetNameByOffset(frames[i].InstructionOffset, nameBuffer, 1024, &nameSize, &displacement);
|
||||
if (SUCCEEDED(result) && nameSize > 0)
|
||||
{
|
||||
std::string name(nameBuffer, nameSize - 1);
|
||||
std::string module;
|
||||
size_t moduleend = name.find('!');
|
||||
if (moduleend != std::string::npos)
|
||||
{
|
||||
module = name.substr(0, moduleend);
|
||||
name = name.substr(moduleend + 1);
|
||||
}
|
||||
|
||||
ULONG line = 0;
|
||||
char fileBuffer[1024] = {};
|
||||
ULONG fileSize = 0;
|
||||
ULONG64 displacement = 0;
|
||||
result = symbols->GetLineByOffset(frames[i].InstructionOffset, &line, fileBuffer, 1024, &fileSize, &displacement);
|
||||
if (SUCCEEDED(result) && fileSize > 0)
|
||||
{
|
||||
std::string file(fileBuffer, fileSize - 1);
|
||||
size_t lastpart = file.find_last_of("/\\");
|
||||
if (lastpart != std::string::npos)
|
||||
file = file.substr(lastpart + 1);
|
||||
|
||||
logText.AppendFormat("Called from %s at %s, line %d\n", name.c_str(), file.c_str(), line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// logText.AppendFormat("Called from %s in module %s\n", name.c_str(), module.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// logText.AppendFormat("Called from %d\n", frames[i].InstructionOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,3 +84,5 @@ FString I_GetCWD();
|
|||
bool I_ChDir(const char* path);
|
||||
|
||||
#endif
|
||||
|
||||
void I_AddMinidumpCallstack(const FString& minidumpFilename, FString& text, FString& logText);
|
||||
|
|
|
|||
|
|
@ -3745,6 +3745,9 @@ static int D_DoomMain_Internal (void)
|
|||
|
||||
if (Args->CheckParm("-showcrashreport"))
|
||||
{
|
||||
FString text;
|
||||
text.Format("%s has performed an illegal operation", GAMENAME);
|
||||
|
||||
FString minidumpFilename = Args->GetArg(2);
|
||||
FString logFilename = Args->GetArg(3);
|
||||
|
||||
|
|
@ -3766,15 +3769,18 @@ static int D_DoomMain_Internal (void)
|
|||
if (fr.OpenFile(minidumpFilename.GetChars()))
|
||||
{
|
||||
minidump.resize(fr.GetLength());
|
||||
if (fr.Read(minidump.data(), minidump.size()) != (FileReader::Size)minidump.size())
|
||||
if (fr.Read(minidump.data(), minidump.size()) == (FileReader::Size)minidump.size())
|
||||
{
|
||||
fr.Close();
|
||||
I_AddMinidumpCallstack(minidumpFilename, text, logText);
|
||||
}
|
||||
else
|
||||
{
|
||||
minidump.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FString text;
|
||||
text.Format("%s fatally crashed!", GAMENAME);
|
||||
ErrorWindow::ExecModal(text.GetChars(), logText.GetChars(), std::move(minidump));
|
||||
|
||||
// Crash reporter only uses -showcrashreport on Windows at the moment and there seems to be no abstraction available
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue