File indexing completed on 2024-05-12 15:56:59
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Sharaf Zaman <shzam@sdf.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "KisAndroidCrashHandler.h" 0008 0009 #include <QDateTime> 0010 #include <QMap> 0011 #include <QScopedPointer> 0012 #include <QStandardPaths> 0013 #include <QThread> 0014 #include <android/log.h> 0015 #include <array> 0016 #include <fcntl.h> 0017 #include <signal.h> 0018 #include <sstream> 0019 #include <unistd.h> 0020 #include <unwindstack/Regs.h> 0021 #include <unwindstack/Unwinder.h> 0022 0023 #define CRASH_LOGGER(...) __android_log_print(ANDROID_LOG_WARN, "KisAndroidCrashHandler", __VA_ARGS__) 0024 0025 namespace KisAndroidCrashHandler { 0026 0027 static const std::array<int, 6> signals = {SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGSYS, SIGTERM}; 0028 static QMap<int, struct sigaction> g_old_actions; 0029 0030 // we need to have keep this object alive 0031 static const std::string path = 0032 QString(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/kritacrashlog.txt").toStdString(); 0033 static const char *crashlog_path = path.c_str(); 0034 0035 static bool g_handling_crash = false; 0036 0037 const char *get_signal_name(const int signo) 0038 { 0039 switch (signo) { 0040 case SIGABRT: 0041 return "SIGABRT"; 0042 case SIGBUS: 0043 return "SIGBUS"; 0044 case SIGFPE: 0045 return "SIGFPE"; 0046 case SIGSEGV: 0047 return "SIGSEGV"; 0048 case SIGSYS: 0049 return "SIGSYS"; 0050 case SIGTERM: 0051 return "SIGTERM"; 0052 default: 0053 return "?"; 0054 } 0055 } 0056 0057 void dump_backtrace(siginfo_t *info, void *ucontext) 0058 { 0059 QScopedPointer<unwindstack::Regs> regs; 0060 if (ucontext) { 0061 regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); 0062 } else { 0063 regs.reset(unwindstack::Regs::CreateFromLocal()); 0064 } 0065 0066 unwindstack::UnwinderFromPid unwinder(256, getpid(), unwindstack::Regs::CurrentArch()); 0067 if (!unwinder.Init()) { 0068 CRASH_LOGGER("Couldn't initialize the unwinder: %s\n", unwinder.LastErrorCodeString()); 0069 return; 0070 } 0071 0072 unwinder.SetRegs(regs.data()); 0073 unwinder.Unwind(); 0074 0075 std::vector<unwindstack::FrameData> frames = unwinder.frames(); 0076 if (frames.size() == 0) { 0077 CRASH_LOGGER("Couldn't unwind: %s\t code = %d\n", unwinder.LastErrorCodeString(), unwinder.LastErrorCode()); 0078 return; 0079 } 0080 0081 const int fd = open(crashlog_path, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR); 0082 0083 std::stringstream header; 0084 header << "********************** Dumping backtrace **********************\n" 0085 << "Signal: " << info->si_signo << " (" << get_signal_name(info->si_signo) << ")" 0086 << " (Code: " << info->si_code << ")" 0087 << " Time: " << QDateTime::currentDateTimeUtc().toString().toStdString().c_str() 0088 << "\n"; 0089 write(fd, header.str().c_str(), header.str().size()); 0090 0091 for (size_t i = 0; i < frames.size(); ++i) { 0092 std::string frame = unwinder.FormatFrame(frames[i]) + "\n"; 0093 write(fd, frame.c_str(), frame.size()); 0094 } 0095 write(fd, "\n", 1); 0096 close(fd); 0097 } 0098 0099 void crash_callback(int sig, siginfo_t *info, void *ucontext) 0100 { 0101 // to prevent second invocation of our signal handler 0102 if (g_handling_crash) { 0103 // uninstall the handler for the signal 0104 sigaction(sig, &g_old_actions[sig], nullptr); 0105 raise(sig); 0106 return; 0107 } 0108 0109 g_handling_crash = true; 0110 dump_backtrace(info, ucontext); 0111 0112 // uninstall the handler for the signal 0113 sigaction(sig, &g_old_actions[sig], nullptr); 0114 0115 // invoke the previous handler 0116 // Some other implementations tend to make call to handler functions 0117 // directly, seemingly to not make another _slow_ syscall. 0118 raise(sig); 0119 } 0120 0121 void handler_init() 0122 { 0123 // create an alternate stack to make sure we can handle overflows 0124 stack_t alternate_stack; 0125 alternate_stack.ss_flags = 0; 0126 alternate_stack.ss_size = SIGSTKSZ; 0127 if ((alternate_stack.ss_sp = malloc(SIGSTKSZ)) == nullptr) { 0128 CRASH_LOGGER("Couldn't allocate memory for alternate stack"); 0129 return; 0130 } 0131 0132 struct sigaction act = {}; 0133 act.sa_sigaction = crash_callback; 0134 act.sa_flags = SA_SIGINFO | SA_ONSTACK; 0135 sigaltstack(&alternate_stack, nullptr); 0136 0137 for (size_t i = 0; i < signals.size(); ++i) { 0138 sigaction(signals[i], &act, &g_old_actions[signals[i]]); 0139 } 0140 } 0141 0142 } // namespace KisAndroidCrashHandler