File indexing completed on 2024-03-24 05:29:41
0001 /* 0002 SPDX-FileCopyrightText: 2009 George Kiagiadakis <gkiagia@users.sourceforge.net> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <config-drkonqi.h> 0008 0009 #include "crashedapplication.h" 0010 0011 #if HAVE_STRSIGNAL && defined(Q_OS_UNIX) 0012 #include <clocale> 0013 #include <cstdlib> 0014 #include <cstring> 0015 #else 0016 #if defined(Q_OS_UNIX) 0017 #include <signal.h> 0018 #endif 0019 #endif 0020 0021 #include <QDir> 0022 0023 #include <KIO/CommandLauncherJob> 0024 0025 #include "drkonqi_debug.h" 0026 0027 CrashedApplication::CrashedApplication(int pid, 0028 int thread, 0029 int signalNumber, 0030 const QFileInfo &executable, 0031 const QString &version, 0032 const BugReportAddress &reportAddress, 0033 const QString &name, 0034 const QString &productName, 0035 const QDateTime &datetime, 0036 bool restarted, 0037 bool hasDeletedFiles, 0038 const QString &fakeBaseName, 0039 QObject *parent) 0040 0041 : QObject(parent) 0042 , m_pid(pid) 0043 , m_signalNumber(signalNumber) 0044 , m_name(name) 0045 , m_executable(executable) 0046 , m_fakeBaseName(fakeBaseName) 0047 , m_version(version) 0048 , m_reportAddress(reportAddress) 0049 , m_productName(productName) 0050 , m_restarted(restarted) 0051 , m_thread(thread) 0052 , m_datetime(datetime) 0053 , m_hasDeletedFiles(hasDeletedFiles) 0054 0055 { 0056 } 0057 0058 CrashedApplication::~CrashedApplication() 0059 { 0060 if (!m_coreFile.isEmpty()) { 0061 const auto path = QFileInfo(m_coreFile).path(); 0062 if (!path.isEmpty() && QFile::exists(path)) { 0063 qCDebug(DRKONQI_LOG) << "Cleaning up" << path; 0064 QDir(path).removeRecursively(); 0065 } 0066 } 0067 }; 0068 0069 QString CrashedApplication::name() const 0070 { 0071 return m_name.isEmpty() ? fakeExecutableBaseName() : m_name; 0072 } 0073 0074 QFileInfo CrashedApplication::executable() const 0075 { 0076 return m_executable; 0077 } 0078 0079 QString CrashedApplication::fakeExecutableBaseName() const 0080 { 0081 if (!m_fakeBaseName.isEmpty()) { 0082 return m_fakeBaseName; 0083 } else { 0084 return m_executable.baseName(); 0085 } 0086 } 0087 0088 QString CrashedApplication::version() const 0089 { 0090 return m_version; 0091 } 0092 0093 BugReportAddress CrashedApplication::bugReportAddress() const 0094 { 0095 return m_reportAddress; 0096 } 0097 0098 QString CrashedApplication::productName() const 0099 { 0100 return m_productName; 0101 } 0102 0103 int CrashedApplication::pid() const 0104 { 0105 return m_pid; 0106 } 0107 0108 int CrashedApplication::signalNumber() const 0109 { 0110 return m_signalNumber; 0111 } 0112 0113 QString CrashedApplication::signalName() const 0114 { 0115 #if HAVE_STRSIGNAL && defined(Q_OS_UNIX) 0116 const QByteArray originalLocale(std::setlocale(LC_MESSAGES, nullptr)); 0117 std::setlocale(LC_MESSAGES, "C"); 0118 const char *name = strsignal(m_signalNumber); 0119 std::setlocale(LC_MESSAGES, originalLocale.data() /* empty string if we got a nullptr */); 0120 return QString::fromLocal8Bit(name ? name : "Unknown"); 0121 #else 0122 switch (m_signalNumber) { 0123 #if defined(Q_OS_UNIX) 0124 case SIGILL: 0125 return QLatin1String("SIGILL"); 0126 case SIGABRT: 0127 return QLatin1String("SIGABRT"); 0128 case SIGFPE: 0129 return QLatin1String("SIGFPE"); 0130 case SIGSEGV: 0131 return QLatin1String("SIGSEGV"); 0132 case SIGBUS: 0133 return QLatin1String("SIGBUS"); 0134 #else 0135 case EXCEPTION_ACCESS_VIOLATION: 0136 return QLatin1String("EXCEPTION_ACCESS_VIOLATION"); 0137 case EXCEPTION_DATATYPE_MISALIGNMENT: 0138 return QLatin1String("EXCEPTION_DATATYPE_MISALIGNMENT"); 0139 case EXCEPTION_BREAKPOINT: 0140 return QLatin1String("EXCEPTION_BREAKPOINT"); 0141 case EXCEPTION_SINGLE_STEP: 0142 return QLatin1String("EXCEPTION_SINGLE_STEP"); 0143 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 0144 return QLatin1String("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); 0145 case EXCEPTION_FLT_DENORMAL_OPERAND: 0146 return QLatin1String("EXCEPTION_FLT_DENORMAL_OPERAND"); 0147 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 0148 return QLatin1String("EXCEPTION_FLT_DIVIDE_BY_ZERO"); 0149 case EXCEPTION_FLT_INEXACT_RESULT: 0150 return QLatin1String("EXCEPTION_FLT_INEXACT_RESULT"); 0151 case EXCEPTION_FLT_INVALID_OPERATION: 0152 return QLatin1String("EXCEPTION_FLT_INVALID_OPERATION"); 0153 case EXCEPTION_FLT_OVERFLOW: 0154 return QLatin1String("EXCEPTION_FLT_OVERFLOW"); 0155 case EXCEPTION_FLT_STACK_CHECK: 0156 return QLatin1String("EXCEPTION_FLT_STACK_CHECK"); 0157 case EXCEPTION_FLT_UNDERFLOW: 0158 return QLatin1String("EXCEPTION_FLT_UNDERFLOW"); 0159 case EXCEPTION_INT_DIVIDE_BY_ZERO: 0160 return QLatin1String("EXCEPTION_INT_DIVIDE_BY_ZERO"); 0161 case EXCEPTION_INT_OVERFLOW: 0162 return QLatin1String("EXCEPTION_INT_OVERFLOW"); 0163 case EXCEPTION_PRIV_INSTRUCTION: 0164 return QLatin1String("EXCEPTION_PRIV_INSTRUCTION"); 0165 case EXCEPTION_IN_PAGE_ERROR: 0166 return QLatin1String("EXCEPTION_IN_PAGE_ERROR"); 0167 case EXCEPTION_ILLEGAL_INSTRUCTION: 0168 return QLatin1String("EXCEPTION_ILLEGAL_INSTRUCTION"); 0169 case EXCEPTION_NONCONTINUABLE_EXCEPTION: 0170 return QLatin1String("EXCEPTION_NONCONTINUABLE_EXCEPTION"); 0171 case EXCEPTION_STACK_OVERFLOW: 0172 return QLatin1String("EXCEPTION_STACK_OVERFLOW"); 0173 case EXCEPTION_INVALID_DISPOSITION: 0174 return QLatin1String("EXCEPTION_INVALID_DISPOSITION"); 0175 #endif 0176 default: 0177 return QLatin1String("Unknown"); 0178 } 0179 #endif 0180 } 0181 0182 bool CrashedApplication::hasBeenRestarted() const 0183 { 0184 return m_restarted; 0185 } 0186 0187 int CrashedApplication::thread() const 0188 { 0189 return m_thread; 0190 } 0191 0192 const QDateTime &CrashedApplication::datetime() const 0193 { 0194 return m_datetime; 0195 } 0196 0197 bool CrashedApplication::hasDeletedFiles() const 0198 { 0199 return m_hasDeletedFiles; 0200 } 0201 0202 void CrashedApplication::restart() 0203 { 0204 if (m_restarted) { 0205 return; 0206 } 0207 0208 // start the application via CommandLauncherJob so it runs in a new cgroup if possible. 0209 // if m_fakeBaseName is set, this means m_executable is the path to kdeinit4 0210 // so we need to use the fakeBaseName to restart the app 0211 auto job = new KIO::CommandLauncherJob(!m_fakeBaseName.isEmpty() ? m_fakeBaseName : m_executable.absoluteFilePath()); 0212 if (const QString &id = DrKonqi::startupId(); !id.isEmpty()) { 0213 job->setStartupId(id.toUtf8()); 0214 } 0215 connect(job, &KIO::CommandLauncherJob::result, this, [job, this] { 0216 m_restarted = (job->error() == KJob::NoError); 0217 if (!m_restarted) { 0218 qCWarning(DRKONQI_LOG) << "Failed to restart:" << job->error() << job->errorString(); 0219 } 0220 Q_EMIT restarted(m_restarted); 0221 }); 0222 job->start(); 0223 } 0224 0225 QString getSuggestedKCrashFilename(const CrashedApplication *app) 0226 { 0227 QString filename = 0228 app->fakeExecutableBaseName() + QLatin1Char('-') + app->datetime().toString(QStringLiteral("yyyyMMdd-hhmmss")) + QStringLiteral(".kcrash"); 0229 0230 if (filename.contains(QLatin1Char('/'))) { 0231 filename = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1); 0232 } 0233 0234 return filename; 0235 } 0236 0237 #include "moc_crashedapplication.cpp"