mirror of
https://github.com/geode-sdk/geode.git
synced 2025-02-17 00:30:26 -05:00
addresses and crashlog
This commit is contained in:
parent
261851887c
commit
20f461305b
6 changed files with 188 additions and 76 deletions
|
@ -141,6 +141,8 @@ class cocos2d::CCDirector {
|
|||
auto convertToUI(cocos2d::CCPoint const&) = mac 0x24a340;
|
||||
auto drawScene() = mac 0x249690;
|
||||
auto willSwitchToScene(cocos2d::CCScene* scene);
|
||||
auto setOpenGLView(cocos2d::CCEGLView *pobOpenGLView) = mac 0x249be0;
|
||||
auto updateScreenScale(cocos2d::CCSize) = mac 0x249f10;
|
||||
|
||||
auto setNextScene() = mac 0x2498d0;
|
||||
auto showStats() = mac 0x2499e0;
|
||||
|
@ -238,6 +240,7 @@ class cocos2d::CCEGLViewProtocol {
|
|||
auto getViewPortRect() const = mac 0x29e2f0;
|
||||
auto getScaleX() const = mac 0x29e300;
|
||||
auto getScaleY() const = mac 0x29e310;
|
||||
auto setFrameSize(float, float) = mac 0x29d960;
|
||||
}
|
||||
|
||||
class cocos2d::CCFadeOut {
|
||||
|
|
|
@ -3002,7 +3002,7 @@ class GameManager : GManager {
|
|||
bool m_showedRateDiffDialog;
|
||||
bool m_showedRateStarDialog;
|
||||
bool m_showedLowDetailDialog;
|
||||
PAD = mac 0x30, win 0x30;
|
||||
PAD = mac 0x3c, win 0x30;
|
||||
int m_bootups;
|
||||
bool m_hasRatedGame;
|
||||
bool m_unk0;
|
||||
|
@ -4297,6 +4297,8 @@ class PlatformToolbox {
|
|||
return false;
|
||||
#endif
|
||||
}
|
||||
static void toggleFullScreen(bool fullscreen) = mac 0x27cf90;
|
||||
static void resizeWindow() = mac 0x27cfe0;
|
||||
}
|
||||
|
||||
class PlayLayer : GJBaseGameLayer, CCCircleWaveDelegate, CurrencyRewardDelegate, DialogDelegate {
|
||||
|
|
90
loader/src/internal/crashlog.cpp
Normal file
90
loader/src/internal/crashlog.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#include "crashlog.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
static std::string getDateString(bool filesafe) {
|
||||
auto const now = std::time(nullptr);
|
||||
auto const tm = *std::localtime(&now);
|
||||
std::ostringstream oss;
|
||||
if (filesafe) {
|
||||
oss << std::put_time(&tm, "%F_%H-%M-%S");
|
||||
}
|
||||
else {
|
||||
oss << std::put_time(&tm, "%FT%T%z"); // ISO 8601
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static void printGeodeInfo(std::stringstream& stream) {
|
||||
stream << "Loader Version: " << Loader::get()->getVersion().toString() << "\n"
|
||||
<< "Installed mods: " << Loader::get()->getAllMods().size() << "\n"
|
||||
<< "Failed mods: " << Loader::get()->getFailedMods().size() << "\n";
|
||||
}
|
||||
|
||||
static void printMods(std::stringstream& stream) {
|
||||
auto mods = Loader::get()->getAllMods();
|
||||
if (!mods.size()) {
|
||||
stream << "<None>\n";
|
||||
}
|
||||
for (auto& mod : mods) {
|
||||
stream << mod->getID() << " | " << mod->getDeveloper() << " | "
|
||||
<< mod->getVersion().toString() << " | "
|
||||
<< (mod->isEnabled() ? "Enabled" : "Disabled") << " | "
|
||||
<< (mod->isLoaded() ? "Loaded" : "Unloaded") << " | "
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void crashlog::writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers) {
|
||||
// make sure crashlog directory exists
|
||||
(void)utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
|
||||
// add a file to let Geode know on next launch that it crashed previously
|
||||
// this could also be done by saving a loader setting or smth but eh.
|
||||
(void)utils::file::writeBinary(crashlog::getCrashLogDirectory() / "last-crashed", {});
|
||||
|
||||
std::stringstream file;
|
||||
|
||||
file << getDateString(false) << "\n"
|
||||
<< std::showbase << "Whoopsies! An exception has occurred while running Geode.\n";
|
||||
|
||||
if (faultyMod) {
|
||||
file << "It appears that the crash occurred while executing code from "
|
||||
<< "the \"" << faultyMod->getID() << "\" mod. "
|
||||
<< "Please submit this crash report to its developer (" << faultyMod->getDeveloper()
|
||||
<< ") for assistance.\n";
|
||||
}
|
||||
|
||||
// geode info
|
||||
file << "\n== Geode Information ==\n";
|
||||
printGeodeInfo(file);
|
||||
|
||||
// exception info
|
||||
file << "\n== Exception Information ==\n";
|
||||
file << info;
|
||||
|
||||
// stack trace
|
||||
file << "\n== Stack Trace ==\n";
|
||||
file << stacktrace;
|
||||
|
||||
// registers
|
||||
file << "\n== Register States ==\n";
|
||||
file << registers;
|
||||
|
||||
// mods
|
||||
file << "\n== Installed Mods ==\n";
|
||||
printMods(file);
|
||||
|
||||
// show message box on debug mode
|
||||
#ifdef GEODE_DEBUG
|
||||
MessageBoxA(nullptr, file.str().c_str(), "Geode Crashed", MB_ICONERROR);
|
||||
#endif
|
||||
|
||||
// save actual file
|
||||
std::ofstream actualFile;
|
||||
actualFile.open(
|
||||
crashlog::getCrashLogDirectory() / (getDateString(true) + ".log"), std::ios::app
|
||||
);
|
||||
actualFile << file.rdbuf() << std::flush;
|
||||
actualFile.close();
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/DefaultInclude.hpp>
|
||||
#include <Geode/Loader.hpp>
|
||||
#include <ghc/fs_fwd.hpp>
|
||||
#include <string>
|
||||
|
||||
|
@ -24,4 +24,6 @@ namespace crashlog {
|
|||
* not support crash logs
|
||||
*/
|
||||
ghc::filesystem::path GEODE_DLL getCrashLogDirectory();
|
||||
|
||||
void GEODE_DLL writeCrashlog(geode::Mod* faultyMod, std::string const& info, std::string const& stacktrace, std::string const& registers);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,83 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// https://gist.github.com/jvranish/4441299
|
||||
|
||||
static std::string_view getSignalCodeString(int sig, siginfo_t* siginfo) {
|
||||
switch(sig) {
|
||||
case SIGSEGV: return "SIGSEGV: Segmentation Fault";
|
||||
case SIGINT: return "SIGINT: Interactive attention signal, (usually ctrl+c)";
|
||||
case SIGFPE:
|
||||
switch(siginfo->si_code) {
|
||||
case FPE_INTDIV: return "SIGFPE: (integer divide by zero)";
|
||||
case FPE_INTOVF: return "SIGFPE: (integer overflow)";
|
||||
case FPE_FLTDIV: return "SIGFPE: (floating-point divide by zero)";
|
||||
case FPE_FLTOVF: return "SIGFPE: (floating-point overflow)";
|
||||
case FPE_FLTUND: return "SIGFPE: (floating-point underflow)";
|
||||
case FPE_FLTRES: return "SIGFPE: (floating-point inexact result)";
|
||||
case FPE_FLTINV: return "SIGFPE: (floating-point invalid operation)";
|
||||
case FPE_FLTSUB: return "SIGFPE: (subscript out of range)";
|
||||
default: return "SIGFPE: Arithmetic Exception";
|
||||
}
|
||||
case SIGILL:
|
||||
switch(siginfo->si_code) {
|
||||
case ILL_ILLOPC: return "SIGILL: (illegal opcode)";
|
||||
case ILL_ILLOPN: return "SIGILL: (illegal operand)";
|
||||
case ILL_ILLADR: return "SIGILL: (illegal addressing mode)";
|
||||
case ILL_ILLTRP: return "SIGILL: (illegal trap)";
|
||||
case ILL_PRVOPC: return "SIGILL: (privileged opcode)";
|
||||
case ILL_PRVREG: return "SIGILL: (privileged register)";
|
||||
case ILL_COPROC: return "SIGILL: (coprocessor error)";
|
||||
case ILL_BADSTK: return "SIGILL: (internal stack error)";
|
||||
default: return "SIGILL: Illegal Instruction";
|
||||
}
|
||||
case SIGTERM: return "SIGTERM: a termination request was sent to the program";
|
||||
case SIGABRT: return "SIGABRT: usually caused by an abort() or assert()";
|
||||
default: return "Unknown signal code";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getInfo(int sig, siginfo_t* siginfo, ucontext_t* context, Mod* faultyMod) {
|
||||
std::stringstream stream;
|
||||
void* address = reinterpret_cast<void*>(context->uc_mcontext->__ss.__rip);
|
||||
stream // << "Faulty Lib: " << getModuleName(handleFromAddress(address), true) << "\n"
|
||||
<< "Faulty Mod: " << (faultyMod ? faultyMod->getID() : "<Unknown>") << "\n"
|
||||
<< "Signal Code: " << std::hex << sig << " (" << getSignalCodeString(sig, siginfo) << ")" << std::dec << "\n"
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
extern "C" void signalHandler(int signal, siginfo_t* signal_info, void* vcontext) {
|
||||
auto context = reinterpret_cast<ucontext_t*>(vcontext);
|
||||
|
||||
auto array = std::array<void*, 20>();
|
||||
auto size = backtrace(array.data(), 20);
|
||||
|
||||
#ifdef __APPLE__
|
||||
array[2] = reinterpret_cast<void*>(context->uc_mcontext->__ss.__rip);
|
||||
#else
|
||||
array[1] = reinterpret_cast<void*>(context->uc_mcontext.gregs[REG_RIP]);
|
||||
#endif
|
||||
|
||||
if (size < 20) {
|
||||
array[size] = nullptr;
|
||||
}
|
||||
|
||||
auto messages = backtrace_symbols(array.data(), size);
|
||||
if (size < 20) {
|
||||
messages[size] = nullptr;
|
||||
}
|
||||
|
||||
ServerLoop::get()->m_panicBacktrace.store(messages);
|
||||
|
||||
ServerLoop::get()->m_signalExit.notify();
|
||||
|
||||
ServerLoop::get()->m_signalFinish.wait();
|
||||
|
||||
free(messages);
|
||||
|
||||
std::abort();
|
||||
}
|
||||
|
||||
bool crashlog::setupPlatformHandler() {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -144,7 +144,8 @@ static void printAddr(std::ostream& stream, void const* addr, bool fullPath = tr
|
|||
}
|
||||
|
||||
// https://stackoverflow.com/a/50208684/9124836
|
||||
static void walkStack(std::ostream& stream, PCONTEXT context) {
|
||||
static std::string walkStack(PCONTEXT context) {
|
||||
std::stringstream stream;
|
||||
STACKFRAME64 stack;
|
||||
memset(&stack, 0, sizeof(STACKFRAME64));
|
||||
|
||||
|
@ -169,9 +170,11 @@ static void walkStack(std::ostream& stream, PCONTEXT context) {
|
|||
printAddr(stream, reinterpret_cast<void*>(stack.AddrPC.Offset));
|
||||
stream << std::endl;
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static void printRegisters(std::ostream& stream, PCONTEXT context) {
|
||||
static std::string getRegisters(PCONTEXT context) {
|
||||
std::stringstream stream;
|
||||
stream << std::hex << "EAX: " << context->Eax << "\n"
|
||||
<< "EBX: " << context->Ebx << "\n"
|
||||
<< "ECX: " << context->Ecx << "\n"
|
||||
|
@ -182,9 +185,11 @@ static void printRegisters(std::ostream& stream, PCONTEXT context) {
|
|||
<< "ESI: " << context->Esi << "\n"
|
||||
<< "EIP: " << context->Eip << "\n"
|
||||
<< std::dec;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static void printInfo(std::ostream& stream, LPEXCEPTION_POINTERS info, Mod* faultyMod) {
|
||||
static std::string getInfo(LPEXCEPTION_POINTERS info, Mod* faultyMod) {
|
||||
std::stringstream stream;
|
||||
stream << "Faulty Module: "
|
||||
<< getModuleName(handleFromAddress(info->ExceptionRecord->ExceptionAddress), true)
|
||||
<< "\n"
|
||||
|
@ -198,87 +203,20 @@ static void printInfo(std::ostream& stream, LPEXCEPTION_POINTERS info, Mod* faul
|
|||
stream << ")"
|
||||
<< "\n"
|
||||
<< "Number Parameters: " << info->ExceptionRecord->NumberParameters << "\n";
|
||||
}
|
||||
|
||||
static void printGeodeInfo(std::ostream& stream) {
|
||||
stream << "Loader Version: " << Loader::get()->getVersion().toString() << "\n"
|
||||
<< "Installed mods: " << Loader::get()->getAllMods().size() << "\n"
|
||||
<< "Failed mods: " << Loader::get()->getFailedMods().size() << "\n";
|
||||
}
|
||||
|
||||
static void printMods(std::ostream& stream) {
|
||||
auto mods = Loader::get()->getAllMods();
|
||||
if (!mods.size()) {
|
||||
stream << "<None>\n";
|
||||
}
|
||||
for (auto& mod : mods) {
|
||||
stream << mod->getID() << " | " << mod->getDeveloper() << " | "
|
||||
<< mod->getVersion().toString() << " | "
|
||||
<< (mod->isEnabled() ? "Enabled" : "Disabled") << " | "
|
||||
<< (mod->isLoaded() ? "Loaded" : "Unloaded") << " | "
|
||||
<< "\n";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static LONG WINAPI exceptionHandler(LPEXCEPTION_POINTERS info) {
|
||||
// make sure crashlog directory exists
|
||||
(void)utils::file::createDirectoryAll(crashlog::getCrashLogDirectory());
|
||||
|
||||
// add a file to let Geode know on next launch that it crashed previously
|
||||
// this could also be done by saving a loader setting or smth but eh.
|
||||
(void)utils::file::writeBinary(crashlog::getCrashLogDirectory() / "last-crashed", {});
|
||||
|
||||
|
||||
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
|
||||
|
||||
std::stringstream file;
|
||||
|
||||
// init symbols so we can get some juicy debug info
|
||||
g_symbolsInitialized = SymInitialize(static_cast<HMODULE>(GetCurrentProcess()), nullptr, true);
|
||||
|
||||
auto faultyMod = modFromAddress(info->ExceptionRecord->ExceptionAddress);
|
||||
|
||||
file << getDateString(false) << "\n"
|
||||
<< std::showbase << "Whoopsies! An exception has occurred while running Geode.\n";
|
||||
|
||||
if (faultyMod) {
|
||||
file << "It appears that the crash occurred while executing code from "
|
||||
<< "the \"" << faultyMod->getID() << "\" mod. "
|
||||
<< "Please submit this crash report to its developer (" << faultyMod->getDeveloper()
|
||||
<< ") for assistance.\n";
|
||||
}
|
||||
|
||||
// geode info
|
||||
file << "\n== Geode Information ==\n";
|
||||
printGeodeInfo(file);
|
||||
|
||||
// exception info
|
||||
file << "\n== Exception Information ==\n";
|
||||
printInfo(file, info, faultyMod);
|
||||
|
||||
// registers
|
||||
file << "\n== Register States ==\n";
|
||||
printRegisters(file, info->ContextRecord);
|
||||
|
||||
// stack trace
|
||||
file << "\n== Stack Trace ==\n";
|
||||
walkStack(file, info->ContextRecord);
|
||||
|
||||
// mods
|
||||
file << "\n== Installed Mods ==\n";
|
||||
printMods(file);
|
||||
|
||||
// show message box on debug mode
|
||||
#ifdef GEODE_DEBUG
|
||||
MessageBoxA(nullptr, file.str().c_str(), "Geode Crashed", MB_ICONERROR);
|
||||
#endif
|
||||
|
||||
// save actual file
|
||||
std::ofstream actualFile;
|
||||
actualFile.open(
|
||||
crashlog::getCrashLogDirectory() / (getDateString(true) + ".log"), std::ios::app
|
||||
);
|
||||
actualFile << file.rdbuf() << std::flush;
|
||||
actualFile.close();
|
||||
crashlog::writeCrashlog(faultyMod, getInfo(info, faultyMod), getStacktrace(info->ContextRecord), getRegisters(info->ContextRecord));
|
||||
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue