File indexing completed on 2024-04-21 16:12:21

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