mirror of
https://github.com/geode-sdk/geode.git
synced 2025-04-01 07:40:18 -04:00
this handler sometimes doesnt work
This commit is contained in:
parent
a77c33974b
commit
66e36b3a38
3 changed files with 618 additions and 4 deletions
loader/src/platform/android
55
loader/src/platform/android/backtrace/ScopedFd.hpp
Normal file
55
loader/src/platform/android/backtrace/ScopedFd.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
class ScopedFd final {
|
||||
public:
|
||||
explicit ScopedFd(int fd) : fd_(fd) {
|
||||
}
|
||||
|
||||
ScopedFd() : fd_(-1) {
|
||||
}
|
||||
|
||||
~ScopedFd() {
|
||||
reset(-1);
|
||||
}
|
||||
|
||||
void reset(int fd = -1) {
|
||||
fd_ = fd;
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return fd_;
|
||||
}
|
||||
|
||||
private:
|
||||
int fd_;
|
||||
};
|
191
loader/src/platform/android/backtrace/execinfo.hpp
Normal file
191
loader/src/platform/android/backtrace/execinfo.hpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <execinfo.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/memfd.h>
|
||||
|
||||
#include "ScopedFd.hpp"
|
||||
|
||||
struct StackState {
|
||||
void** frames;
|
||||
int frame_count;
|
||||
int cur_frame = 0;
|
||||
|
||||
StackState(void** frames, int frame_count) : frames(frames), frame_count(frame_count) {}
|
||||
};
|
||||
|
||||
static _Unwind_Reason_Code TraceFunction(_Unwind_Context* context, void* arg) {
|
||||
// The instruction pointer is pointing at the instruction after the return
|
||||
// call on all architectures.
|
||||
// Modify the pc to point at the real function.
|
||||
uintptr_t ip = _Unwind_GetIP(context);
|
||||
if (ip != 0) {
|
||||
#if defined(__arm__)
|
||||
// If the ip is suspiciously low, do nothing to avoid a segfault trying
|
||||
// to access this memory.
|
||||
if (ip >= 4096) {
|
||||
// Check bits [15:11] of the first halfword assuming the instruction
|
||||
// is 32 bits long. If the bits are any of these values, then our
|
||||
// assumption was correct:
|
||||
// b11101
|
||||
// b11110
|
||||
// b11111
|
||||
// Otherwise, this is a 16 bit instruction.
|
||||
uint16_t value = (*reinterpret_cast<uint16_t*>(ip - 2)) >> 11;
|
||||
if (value == 0x1f || value == 0x1e || value == 0x1d) {
|
||||
ip -= 4;
|
||||
} else {
|
||||
ip -= 2;
|
||||
}
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
// All instructions are 4 bytes long, skip back one instruction.
|
||||
ip -= 4;
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
// It's difficult to decode exactly where the previous instruction is,
|
||||
// so subtract 1 to estimate where the instruction lives.
|
||||
ip--;
|
||||
#endif
|
||||
}
|
||||
|
||||
StackState* state = static_cast<StackState*>(arg);
|
||||
state->frames[state->cur_frame++] = reinterpret_cast<void*>(ip);
|
||||
return (state->cur_frame >= state->frame_count) ? _URC_END_OF_STACK : _URC_NO_REASON;
|
||||
}
|
||||
|
||||
int backtrace(void** buffer, int size) {
|
||||
if (size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
StackState state(buffer, size);
|
||||
_Unwind_Backtrace(TraceFunction, &state);
|
||||
return state.cur_frame;
|
||||
}
|
||||
|
||||
void backtrace_symbols_fd(void* const* buffer, int size, int fd);
|
||||
|
||||
char** backtrace_symbols(void* const* buffer, int size) {
|
||||
if (size <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
// Do this calculation first in case the user passes in a bad value.
|
||||
size_t ptr_size;
|
||||
if (__builtin_mul_overflow(sizeof(char*), size, &ptr_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
ScopedFd fd(syscall(SYS_memfd_create, "backtrace_symbols_fd", MFD_CLOEXEC));
|
||||
// ScopedFd fd(memfd_create("backtrace_symbols_fd", MFD_CLOEXEC));
|
||||
if (fd.get() == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
backtrace_symbols_fd(buffer, size, fd.get());
|
||||
|
||||
// Get the size of the file.
|
||||
off_t file_size = lseek(fd.get(), 0, SEEK_END);
|
||||
if (file_size <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// The interface for backtrace_symbols indicates that only the single
|
||||
// returned pointer must be freed by the caller. Therefore, allocate a
|
||||
// buffer that includes the memory for the strings and all of the pointers.
|
||||
// Add one byte at the end just in case the file didn't end with a '\n'.
|
||||
size_t symbol_data_size;
|
||||
if (__builtin_add_overflow(ptr_size, file_size, &symbol_data_size) ||
|
||||
__builtin_add_overflow(symbol_data_size, 1, &symbol_data_size)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8_t* symbol_data = reinterpret_cast<uint8_t*>(malloc(symbol_data_size));
|
||||
if (symbol_data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Copy the string data into the buffer.
|
||||
char* cur_string = reinterpret_cast<char*>(&symbol_data[ptr_size]);
|
||||
// If this fails, the read won't read back the correct number of bytes.
|
||||
lseek(fd.get(), 0, SEEK_SET);
|
||||
ssize_t num_read = read(fd.get(), cur_string, file_size);
|
||||
fd.reset(-1);
|
||||
if (num_read != file_size) {
|
||||
free(symbol_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure the last character in the file is '\n'.
|
||||
if (cur_string[file_size] != '\n') {
|
||||
cur_string[file_size++] = '\n';
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
(reinterpret_cast<char**>(symbol_data))[i] = cur_string;
|
||||
cur_string = strchr(cur_string, '\n');
|
||||
if (cur_string == nullptr) {
|
||||
free(symbol_data);
|
||||
return nullptr;
|
||||
}
|
||||
cur_string[0] = '\0';
|
||||
cur_string++;
|
||||
}
|
||||
return reinterpret_cast<char**>(symbol_data);
|
||||
}
|
||||
|
||||
// This function should do no allocations if possible.
|
||||
void backtrace_symbols_fd(void* const* buffer, int size, int fd) {
|
||||
if (size <= 0 || fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int frame_num = 0; frame_num < size; frame_num++) {
|
||||
void* address = buffer[frame_num];
|
||||
Dl_info info;
|
||||
if (dladdr(address, &info) != 0) {
|
||||
if (info.dli_fname != nullptr) {
|
||||
write(fd, info.dli_fname, strlen(info.dli_fname));
|
||||
}
|
||||
if (info.dli_sname != nullptr) {
|
||||
dprintf(fd, "(%s+0x%" PRIxPTR ") ", info.dli_sname,
|
||||
reinterpret_cast<uintptr_t>(address) - reinterpret_cast<uintptr_t>(info.dli_saddr));
|
||||
} else {
|
||||
dprintf(fd, "(+%p) ", info.dli_saddr);
|
||||
}
|
||||
}
|
||||
|
||||
dprintf(fd, "[%p]\n", address);
|
||||
}
|
||||
}
|
|
@ -2,16 +2,384 @@
|
|||
|
||||
#ifdef GEODE_IS_ANDROID
|
||||
|
||||
ghc::filesystem::path crashlog::getCrashLogDirectory() {
|
||||
return geode::dirs::getSaveDir();
|
||||
using namespace geode::prelude;
|
||||
|
||||
#include <Geode/utils/string.hpp>
|
||||
#include <array>
|
||||
#include <thread>
|
||||
#include <ghc/fs_fwd.hpp>
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
#include <algorithm>
|
||||
#include <link.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#include "backtrace/execinfo.hpp"
|
||||
|
||||
static constexpr size_t FRAME_SIZE = 64;
|
||||
static std::mutex s_mutex;
|
||||
static std::condition_variable s_cv;
|
||||
static int s_signal = 0;
|
||||
static siginfo_t* s_siginfo = nullptr;
|
||||
static ucontext_t* s_context = nullptr;
|
||||
static size_t s_backtraceSize = 0;
|
||||
static std::array<void*, FRAME_SIZE> s_backtrace;
|
||||
|
||||
static std::string_view getSignalCodeString() {
|
||||
switch(s_signal) {
|
||||
case SIGSEGV: return "SIGSEGV: Segmentation Fault";
|
||||
case SIGINT: return "SIGINT: Interactive attention signal, (usually ctrl+c)";
|
||||
case SIGFPE:
|
||||
switch(s_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(s_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()";
|
||||
case SIGBUS: return "SIGBUS: Bus error (bad memory access)";
|
||||
default: return "Unknown signal code";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getImageName(Elf32_Phdr const* image) {
|
||||
if (image == nullptr) {
|
||||
return "<Unknown>";
|
||||
}
|
||||
std::string imageName;// = image->imageFilePath;
|
||||
if (imageName.empty()) {
|
||||
imageName = "<Unknown>";
|
||||
}
|
||||
return imageName;
|
||||
}
|
||||
|
||||
// static std::vector<struct dyld_image_info const*> getAllImages() {
|
||||
// std::vector<struct dyld_image_info const*> images;
|
||||
// struct task_dyld_info dyldInfo;
|
||||
// mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
// if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyldInfo, &count) == KERN_SUCCESS) {
|
||||
// struct dyld_all_image_infos* imageInfos = (struct dyld_all_image_infos*)dyldInfo.all_image_info_addr;
|
||||
|
||||
// for (size_t i = 0; i < imageInfos->infoArrayCount; ++i) {
|
||||
// images.push_back(&imageInfos->infoArray[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return images;
|
||||
// }
|
||||
|
||||
static Elf32_Phdr const* imageFromAddress(void const* addr) {
|
||||
if (addr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// auto loadedImages = getAllImages();
|
||||
// std::sort(loadedImages.begin(), loadedImages.end(), [](auto const a, auto const b) {
|
||||
// return (uintptr_t)a->imageLoadAddress < (uintptr_t)b->imageLoadAddress;
|
||||
// });
|
||||
// auto iter = std::upper_bound(loadedImages.begin(), loadedImages.end(), addr, [](auto const addr, auto const image) {
|
||||
// return (uintptr_t)addr < (uintptr_t)image->imageLoadAddress;
|
||||
// });
|
||||
|
||||
// if (iter == loadedImages.begin()) {
|
||||
// return nullptr;
|
||||
// }
|
||||
// --iter;
|
||||
|
||||
// auto image = *iter;
|
||||
// // auto imageSize = getImageSize((struct mach_header_64 const*)image->imageLoadAddress);
|
||||
// auto imageAddress = (uintptr_t)image->imageLoadAddress;
|
||||
// if ((uintptr_t)addr >= imageAddress/* && (uintptr_t)addr < imageAddress + imageSize*/) {
|
||||
// return image;
|
||||
// }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Mod* modFromAddress(void const* addr) {
|
||||
if (addr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
// auto image = imageFromAddress(addr);
|
||||
// if (image == nullptr) {
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
// ghc::filesystem::path imagePath = getImageName(image);
|
||||
// if (!ghc::filesystem::exists(imagePath)) {
|
||||
// return nullptr;
|
||||
// }
|
||||
// auto geodePath = dirs::getGameDir() / "Frameworks" / "Geode.dylib";
|
||||
// if (ghc::filesystem::equivalent(imagePath, geodePath)) {
|
||||
// return Mod::get();
|
||||
// }
|
||||
|
||||
// for (auto& mod : Loader::get()->getAllMods()) {
|
||||
// if (!mod->isEnabled() || !ghc::filesystem::exists(mod->getBinaryPath())) {
|
||||
// continue;
|
||||
// }
|
||||
// if (ghc::filesystem::equivalent(imagePath, mod->getBinaryPath())) {
|
||||
// return mod;
|
||||
// }
|
||||
// }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::string getInfo(void* address, Mod* faultyMod) {
|
||||
std::stringstream stream;
|
||||
stream << "Faulty Lib: " << getImageName(imageFromAddress(address)) << "\n";
|
||||
stream << "Faulty Mod: " << (faultyMod ? faultyMod->getID() : "<Unknown>") << "\n";
|
||||
stream << "Instruction Address: " << address << "\n";
|
||||
stream << "Signal Code: " << std::hex << s_signal << " (" << getSignalCodeString() << ")" << std::dec << "\n";
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static struct sigaction oldActionSEGV;
|
||||
static struct sigaction oldActionBUS;
|
||||
static struct sigaction oldActionILL;
|
||||
|
||||
extern "C" void signalHandler(int signal, siginfo_t* signalInfo, void* vcontext) {
|
||||
auto context = reinterpret_cast<ucontext_t*>(vcontext);
|
||||
s_backtraceSize = 0;
|
||||
// s_backtraceSize = backtrace(s_backtrace.data(), FRAME_SIZE);
|
||||
|
||||
// for some reason this is needed, dont ask me why
|
||||
// s_backtrace[1] = reinterpret_cast<void*>(context->uc_mcontext.fault_address);
|
||||
// if (s_backtraceSize < FRAME_SIZE) {
|
||||
// s_backtrace[s_backtraceSize] = nullptr;
|
||||
// }
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(s_mutex);
|
||||
s_signal = signal;
|
||||
s_siginfo = signalInfo;
|
||||
s_context = context;
|
||||
}
|
||||
|
||||
s_cv.notify_all();
|
||||
std::unique_lock<std::mutex> lock(s_mutex);
|
||||
s_cv.wait(lock, [] { return s_signal == 0; });
|
||||
// std::_Exit(EXIT_FAILURE);
|
||||
|
||||
switch (signal) {
|
||||
case SIGSEGV:
|
||||
sigaction(signal, &oldActionSEGV, nullptr);
|
||||
oldActionSEGV.sa_sigaction(signal, signalInfo, vcontext);
|
||||
break;
|
||||
case SIGBUS:
|
||||
sigaction(signal, &oldActionBUS, nullptr);
|
||||
oldActionBUS.sa_sigaction(signal, signalInfo, vcontext);
|
||||
break;
|
||||
case SIGILL:
|
||||
sigaction(signal, &oldActionILL, nullptr);
|
||||
oldActionILL.sa_sigaction(signal, signalInfo, vcontext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getStacktrace() {
|
||||
std::stringstream stacktrace;
|
||||
|
||||
if (s_backtraceSize == 0) {
|
||||
return stacktrace.str();
|
||||
}
|
||||
|
||||
auto messages = backtrace_symbols(s_backtrace.data(), s_backtraceSize);
|
||||
if (s_backtraceSize < FRAME_SIZE) {
|
||||
messages[s_backtraceSize] = nullptr;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 1; i < s_backtraceSize; ++i) {
|
||||
auto message = std::string(messages[i]);
|
||||
|
||||
// TODO: parse the message
|
||||
stacktrace << message << "\n";
|
||||
|
||||
|
||||
// auto stream = std::stringstream(message);
|
||||
// int index;
|
||||
// std::string binary;
|
||||
// uintptr_t address;
|
||||
// std::string function;
|
||||
// uintptr_t offset;
|
||||
// std::string line;
|
||||
|
||||
// stream >> index;
|
||||
|
||||
// if (!lines.eof()) {
|
||||
// std::getline(lines, line);
|
||||
// }
|
||||
// std::getline(stream, binary);
|
||||
// auto cutoff = binary.find("0x");
|
||||
// stream = std::stringstream(binary.substr(cutoff));
|
||||
// binary = geode::utils::string::trim(binary.substr(0, cutoff));
|
||||
// stream >> std::hex >> address >> std::dec;
|
||||
|
||||
// if (!line.empty()) {
|
||||
// // log::debug("address: {}", address);
|
||||
// auto image = imageFromAddress(reinterpret_cast<void*>(address));
|
||||
// // log::debug("image: {}", image);
|
||||
// stacktrace << " - " << std::showbase << std::hex;
|
||||
|
||||
// if (image) {
|
||||
// auto baseAddress = image->imageLoadAddress;
|
||||
// auto imageName = getImageName(image);
|
||||
// stacktrace << imageName << " + " << (address - (uintptr_t)baseAddress);
|
||||
// }
|
||||
// else {
|
||||
// stacktrace << address;
|
||||
// }
|
||||
// stacktrace << std::dec;
|
||||
// stacktrace << ": " << line << "\n";
|
||||
// }
|
||||
// else {
|
||||
// std::getline(stream, function);
|
||||
// cutoff = function.find("+");
|
||||
// stream = std::stringstream(function.substr(cutoff));
|
||||
// stream >> offset;
|
||||
// function = geode::utils::string::trim(function.substr(0, cutoff));
|
||||
|
||||
// {
|
||||
// int status;
|
||||
// auto demangle = abi::__cxa_demangle(function.c_str(), 0, 0, &status);
|
||||
// if (status == 0) {
|
||||
// function = demangle;
|
||||
// }
|
||||
// free(demangle);
|
||||
// }
|
||||
|
||||
// stacktrace << "- " << binary;
|
||||
// stacktrace << " @ " << std::showbase << std::hex << address << std::dec;
|
||||
// stacktrace << " (" << function << " + " << offset << ")\n";
|
||||
// }
|
||||
}
|
||||
|
||||
free(messages);
|
||||
|
||||
return stacktrace.str();
|
||||
}
|
||||
|
||||
static std::string getRegisters() {
|
||||
std::stringstream registers;
|
||||
|
||||
auto context = s_context;
|
||||
auto& ctx = context->uc_mcontext;
|
||||
|
||||
// geez
|
||||
registers << std::showbase << std::hex /*<< std::setfill('0') << std::setw(16) */;
|
||||
registers << "r0: " << ctx.arm_r0 << "\n";
|
||||
registers << "r1: " << ctx.arm_r1 << "\n";
|
||||
registers << "r2: " << ctx.arm_r2 << "\n";
|
||||
registers << "r3: " << ctx.arm_r3 << "\n";
|
||||
registers << "r4: " << ctx.arm_r4 << "\n";
|
||||
registers << "r5: " << ctx.arm_r5 << "\n";
|
||||
registers << "r6: " << ctx.arm_r6 << "\n";
|
||||
registers << "r7: " << ctx.arm_r7 << "\n";
|
||||
registers << "r8: " << ctx.arm_r8 << "\n";
|
||||
registers << "r9: " << ctx.arm_r9 << "\n";
|
||||
registers << "r10: " << ctx.arm_r10 << "\n";
|
||||
registers << "r11: " << ctx.arm_fp << "\n";
|
||||
registers << "r12: " << ctx.arm_ip << "\n";
|
||||
registers << "sp: " << ctx.arm_sp << "\n";
|
||||
registers << "lr: " << ctx.arm_lr << "\n";
|
||||
registers << "pc: " << ctx.arm_pc << "\n";
|
||||
registers << "cpsr: " << ctx.arm_cpsr << "\n";
|
||||
|
||||
return registers.str();
|
||||
}
|
||||
|
||||
static void handlerThread() {
|
||||
std::unique_lock<std::mutex> lock(s_mutex);
|
||||
s_cv.wait(lock, [] { return s_signal != 0; });
|
||||
|
||||
auto signalAddress = reinterpret_cast<void*>(s_context->uc_mcontext.fault_address);
|
||||
// Mod* faultyMod = nullptr;
|
||||
// for (int i = 1; i < s_backtraceSize; ++i) {
|
||||
// auto mod = modFromAddress(s_backtrace[i]);
|
||||
// if (mod != nullptr) {
|
||||
// faultyMod = mod;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
Mod* faultyMod = modFromAddress(signalAddress);
|
||||
|
||||
auto text = crashlog::writeCrashlog(faultyMod, getInfo(signalAddress, faultyMod), getStacktrace(), getRegisters());
|
||||
|
||||
log::error("Geode crashed!\n{}", text);
|
||||
|
||||
s_signal = 0;
|
||||
s_cv.notify_all();
|
||||
|
||||
log::debug("Notified");
|
||||
}
|
||||
|
||||
static bool s_lastLaunchCrashed;
|
||||
|
||||
bool crashlog::setupPlatformHandler() {
|
||||
return false;
|
||||
struct sigaction action;
|
||||
action.sa_sigaction = &signalHandler;
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(SIGSEGV, &action, &oldActionSEGV);
|
||||
// I'd rather not track interrupt lol
|
||||
// sigaction(SIGINT, &action, nullptr);
|
||||
// sigaction(SIGFPE, &action, nullptr);
|
||||
sigaction(SIGILL, &action, &oldActionILL);
|
||||
// sigaction(SIGTERM, &action, nullptr);
|
||||
// sigaction(SIGABRT, &action, nullptr);
|
||||
sigaction(SIGBUS, &action, &oldActionBUS);
|
||||
|
||||
std::thread(&handlerThread).detach();
|
||||
|
||||
auto lastCrashedFile = crashlog::getCrashLogDirectory() / "last-crashed";
|
||||
if (ghc::filesystem::exists(lastCrashedFile)) {
|
||||
s_lastLaunchCrashed = true;
|
||||
try {
|
||||
ghc::filesystem::remove(lastCrashedFile);
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool crashlog::didLastLaunchCrash() {
|
||||
return false;
|
||||
return s_lastLaunchCrashed;
|
||||
}
|
||||
|
||||
ghc::filesystem::path crashlog::getCrashLogDirectory() {
|
||||
return dirs::getGeodeDir() / "crashlogs";
|
||||
}
|
||||
|
||||
// ghc::filesystem::path crashlog::getCrashLogDirectory() {
|
||||
// return geode::dirs::getSaveDir();
|
||||
// }
|
||||
|
||||
// bool crashlog::setupPlatformHandler() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// bool crashlog::didLastLaunchCrash() {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue