2023-02-19 14:45:56 +01:00
|
|
|
#include "CrashReporter.hpp"
|
|
|
|
#include <random>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <execinfo.h>
|
|
|
|
#include <fstream>
|
2023-03-01 16:08:44 +01:00
|
|
|
#include <signal.h>
|
2023-02-19 14:45:56 +01:00
|
|
|
|
2023-02-27 13:32:38 +01:00
|
|
|
#include "../plugins/PluginSystem.hpp"
|
|
|
|
|
2023-02-20 15:15:15 +01:00
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
#endif
|
|
|
|
|
2023-02-19 14:45:56 +01:00
|
|
|
std::string getRandomMessage() {
|
|
|
|
|
|
|
|
const std::vector<std::string> MESSAGES = {"Sorry, didn't mean to...",
|
2023-09-06 21:45:37 +02:00
|
|
|
"This was an accident, I swear!",
|
|
|
|
"Calm down, it was a misinput! MISINPUT!",
|
|
|
|
"Oops",
|
|
|
|
"Vaxry is going to be upset.",
|
|
|
|
"Who tried dividing by zero?!",
|
|
|
|
"Maybe you should try dusting your PC in the meantime?",
|
|
|
|
"I tried so hard, and got so far...",
|
|
|
|
"I don't feel so good...",
|
|
|
|
"*thud*",
|
|
|
|
"Well this is awkward.",
|
|
|
|
"\"stable\"",
|
|
|
|
"I hope you didn't have any unsaved progress.",
|
|
|
|
"All these computers..."};
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
std::random_device dev;
|
|
|
|
std::mt19937 engine(dev());
|
|
|
|
std::uniform_int_distribution<> distribution(0, MESSAGES.size() - 1);
|
|
|
|
|
|
|
|
return MESSAGES[distribution(engine)];
|
|
|
|
}
|
|
|
|
|
2023-03-01 16:08:44 +01:00
|
|
|
void CrashReporter::createAndSaveCrash(int sig) {
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
// get the backtrace
|
|
|
|
const int PID = getpid();
|
|
|
|
|
|
|
|
std::string finalCrashReport = "";
|
|
|
|
|
2023-02-19 14:51:40 +01:00
|
|
|
finalCrashReport += "--------------------------------------------\n Hyprland Crash Report\n--------------------------------------------\n";
|
2023-02-19 14:45:56 +01:00
|
|
|
finalCrashReport += getRandomMessage() + "\n\n";
|
|
|
|
|
2023-09-06 12:51:36 +02:00
|
|
|
finalCrashReport += getFormat("Hyprland received signal {} ({})\n\n", sig, (const char*)strsignal(sig));
|
2023-02-19 14:45:56 +01:00
|
|
|
|
2023-09-06 12:51:36 +02:00
|
|
|
finalCrashReport += getFormat("Version: {}\nTag: {}\n\n", GIT_COMMIT_HASH, GIT_TAG);
|
2023-03-17 12:50:31 +01:00
|
|
|
|
2023-04-15 11:58:46 +02:00
|
|
|
if (g_pPluginSystem && !g_pPluginSystem->getAllPlugins().empty()) {
|
2023-02-27 13:32:38 +01:00
|
|
|
finalCrashReport += "Hyprland seems to be running with plugins. This crash might not be Hyprland's fault.\nPlugins:\n";
|
|
|
|
|
|
|
|
for (auto& p : g_pPluginSystem->getAllPlugins()) {
|
2023-09-06 21:45:37 +02:00
|
|
|
finalCrashReport += getFormat("\t{} ({}) {}\n", p->name, p->author, p->version);
|
2023-02-27 13:32:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
finalCrashReport += "\n\n";
|
|
|
|
}
|
|
|
|
|
2023-02-19 14:45:56 +01:00
|
|
|
finalCrashReport += "System info:\n";
|
|
|
|
|
|
|
|
struct utsname unameInfo;
|
|
|
|
uname(&unameInfo);
|
|
|
|
|
|
|
|
finalCrashReport +=
|
2023-09-06 12:51:36 +02:00
|
|
|
getFormat("\tSystem name: {}\n\tNode name: {}\n\tRelease: {}\n\tVersion: {}\n\n", unameInfo.sysname, unameInfo.nodename, unameInfo.release, unameInfo.version);
|
2023-02-19 14:45:56 +01:00
|
|
|
|
2023-02-20 15:15:15 +01:00
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__)
|
|
|
|
const std::string GPUINFO = execAndGet("pciconf -lv | fgrep -A4 vga");
|
|
|
|
#else
|
2023-02-19 14:45:56 +01:00
|
|
|
const std::string GPUINFO = execAndGet("lspci -vnn | grep VGA");
|
2023-02-20 15:15:15 +01:00
|
|
|
#endif
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
finalCrashReport += "GPU:\n\t" + GPUINFO;
|
|
|
|
|
2023-09-06 21:45:37 +02:00
|
|
|
finalCrashReport += getFormat("\n\nos-release:\n\t{}\n\n\n", replaceInString(execAndGet("cat /etc/os-release"), "\n", "\n\t"));
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
finalCrashReport += "Backtrace:\n";
|
|
|
|
|
2023-08-11 17:22:16 +02:00
|
|
|
const auto CALLSTACK = getBacktrace();
|
2023-02-20 15:15:15 +01:00
|
|
|
|
|
|
|
#if defined(KERN_PROC_PATHNAME)
|
|
|
|
int mib[] = {
|
2023-03-01 10:32:31 +01:00
|
|
|
CTL_KERN,
|
2023-02-20 15:15:15 +01:00
|
|
|
#if defined(__NetBSD__)
|
2023-03-01 10:32:31 +01:00
|
|
|
KERN_PROC_ARGS,
|
|
|
|
-1,
|
|
|
|
KERN_PROC_PATHNAME,
|
2023-02-20 15:15:15 +01:00
|
|
|
#else
|
2023-03-01 10:32:31 +01:00
|
|
|
KERN_PROC,
|
|
|
|
KERN_PROC_PATHNAME,
|
|
|
|
-1,
|
2023-02-20 15:15:15 +01:00
|
|
|
#endif
|
|
|
|
};
|
2023-03-01 10:32:31 +01:00
|
|
|
u_int miblen = sizeof(mib) / sizeof(mib[0]);
|
|
|
|
char exe[PATH_MAX] = "";
|
|
|
|
size_t sz = sizeof(exe);
|
2023-02-20 15:15:15 +01:00
|
|
|
sysctl(mib, miblen, &exe, &sz, NULL, 0);
|
|
|
|
const auto FPATH = std::filesystem::canonical(exe);
|
|
|
|
#elif defined(__OpenBSD__)
|
|
|
|
// Neither KERN_PROC_PATHNAME nor /proc are supported
|
|
|
|
const auto FPATH = std::filesystem::canonical("/usr/local/bin/Hyprland");
|
|
|
|
#else
|
2023-02-20 11:28:16 +01:00
|
|
|
const auto FPATH = std::filesystem::canonical("/proc/self/exe");
|
2023-02-20 15:15:15 +01:00
|
|
|
#endif
|
2023-02-19 14:45:56 +01:00
|
|
|
|
2023-08-11 17:22:16 +02:00
|
|
|
for (size_t i = 0; i < CALLSTACK.size(); ++i) {
|
2023-09-06 21:45:37 +02:00
|
|
|
finalCrashReport += getFormat("\t#{} | {}\n", i, CALLSTACK[i].desc);
|
2023-02-19 14:45:56 +01:00
|
|
|
|
2023-02-20 15:15:15 +01:00
|
|
|
#ifdef __clang__
|
2023-09-06 12:51:36 +02:00
|
|
|
const auto CMD = getFormat("llvm-addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
2023-02-20 15:15:15 +01:00
|
|
|
#else
|
2023-09-06 12:51:36 +02:00
|
|
|
const auto CMD = getFormat("addr2line -e {} -f 0x{:x}", FPATH.c_str(), (uint64_t)CALLSTACK[i].adr);
|
2023-02-20 15:15:15 +01:00
|
|
|
#endif
|
2023-02-20 11:28:16 +01:00
|
|
|
const auto ADDR2LINE = replaceInString(execAndGet(CMD.c_str()), "\n", "\n\t\t");
|
|
|
|
finalCrashReport += "\t\t" + ADDR2LINE.substr(0, ADDR2LINE.length() - 2);
|
2023-02-19 14:45:56 +01:00
|
|
|
}
|
|
|
|
|
2023-03-01 16:14:35 +01:00
|
|
|
finalCrashReport += "\n\nLog tail:\n";
|
|
|
|
|
|
|
|
finalCrashReport += execAndGet(("cat \"" + Debug::logFile + "\" | tail -n 50").c_str());
|
|
|
|
|
2023-04-15 11:58:46 +02:00
|
|
|
const auto HOME = getenv("HOME");
|
2023-03-31 14:15:24 +02:00
|
|
|
const auto CACHE_HOME = getenv("XDG_CACHE_HOME");
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
if (!HOME)
|
|
|
|
return;
|
|
|
|
|
2023-03-31 14:15:24 +02:00
|
|
|
std::ofstream ofs;
|
2023-06-23 13:22:38 +02:00
|
|
|
std::string path;
|
2023-03-31 14:15:24 +02:00
|
|
|
if (!CACHE_HOME) {
|
|
|
|
if (!std::filesystem::exists(std::string(HOME) + "/.hyprland")) {
|
|
|
|
std::filesystem::create_directory(std::string(HOME) + "/.hyprland");
|
|
|
|
std::filesystem::permissions(std::string(HOME) + "/.hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
|
|
|
}
|
|
|
|
|
2023-04-21 17:48:30 +02:00
|
|
|
path = std::string(HOME) + "/.hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
|
|
|
ofs.open(path, std::ios::trunc);
|
2023-03-31 14:15:24 +02:00
|
|
|
|
|
|
|
} else if (CACHE_HOME) {
|
|
|
|
if (!std::filesystem::exists(std::string(CACHE_HOME) + "/hyprland")) {
|
|
|
|
std::filesystem::create_directory(std::string(CACHE_HOME) + "/hyprland");
|
|
|
|
std::filesystem::permissions(std::string(CACHE_HOME) + "/hyprland", std::filesystem::perms::all, std::filesystem::perm_options::replace);
|
|
|
|
}
|
2023-02-19 14:51:40 +01:00
|
|
|
|
2023-04-21 17:48:30 +02:00
|
|
|
path = std::string(CACHE_HOME) + "/hyprland/hyprlandCrashReport" + std::to_string(PID) + ".txt";
|
|
|
|
ofs.open(path, std::ios::trunc);
|
2023-03-31 14:15:24 +02:00
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
}
|
2023-02-19 14:45:56 +01:00
|
|
|
|
|
|
|
ofs << finalCrashReport;
|
|
|
|
|
|
|
|
ofs.close();
|
2023-04-21 17:48:30 +02:00
|
|
|
|
|
|
|
Debug::disableStdout = false;
|
2023-09-06 21:45:37 +02:00
|
|
|
Debug::log(CRIT, "Hyprland has crashed :( Consult the crash report at {} for more information.", path);
|
2023-03-31 14:15:24 +02:00
|
|
|
}
|