1 /*
2 SPDX-FileCopyrightText: 2009 George Kiagiadakis <gkiagia@users.sourceforge.net>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include <config-drkonqi.h>
8
9 #include "crashedapplication.h"
10
11 #if HAVE_STRSIGNAL && defined(Q_OS_UNIX)
12 #include <clocale>
13 #include <cstdlib>
14 #include <cstring>
15 #else
16 #if defined(Q_OS_UNIX)
17 #include <signal.h>
18 #else
19 #include <windows.h>
20 #endif
21 #endif
22
23 #include <KIO/CommandLauncherJob>
24
CrashedApplication(int pid,int thread,int signalNumber,const QFileInfo & executable,const QString & version,const BugReportAddress & reportAddress,const QString & name,const QString & productName,const QDateTime & datetime,bool restarted,bool hasDeletedFiles,const QString & fakeBaseName,QObject * parent)25 CrashedApplication::CrashedApplication(int pid,
26 int thread,
27 int signalNumber,
28 const QFileInfo &executable,
29 const QString &version,
30 const BugReportAddress &reportAddress,
31 const QString &name,
32 const QString &productName,
33 const QDateTime &datetime,
34 bool restarted,
35 bool hasDeletedFiles,
36 const QString &fakeBaseName,
37 QObject *parent)
38
39 : QObject(parent)
40 , m_pid(pid)
41 , m_signalNumber(signalNumber)
42 , m_name(name)
43 , m_executable(executable)
44 , m_fakeBaseName(fakeBaseName)
45 , m_version(version)
46 , m_reportAddress(reportAddress)
47 , m_productName(productName)
48 , m_restarted(restarted)
49 , m_thread(thread)
50 , m_datetime(datetime)
51 , m_hasDeletedFiles(hasDeletedFiles)
52
53 {
54 }
55
56 CrashedApplication::~CrashedApplication() = default;
57
name() const58 QString CrashedApplication::name() const
59 {
60 return m_name.isEmpty() ? fakeExecutableBaseName() : m_name;
61 }
62
executable() const63 QFileInfo CrashedApplication::executable() const
64 {
65 return m_executable;
66 }
67
fakeExecutableBaseName() const68 QString CrashedApplication::fakeExecutableBaseName() const
69 {
70 if (!m_fakeBaseName.isEmpty()) {
71 return m_fakeBaseName;
72 } else {
73 return m_executable.baseName();
74 }
75 }
76
version() const77 QString CrashedApplication::version() const
78 {
79 return m_version;
80 }
81
bugReportAddress() const82 BugReportAddress CrashedApplication::bugReportAddress() const
83 {
84 return m_reportAddress;
85 }
86
productName() const87 QString CrashedApplication::productName() const
88 {
89 return m_productName;
90 }
91
pid() const92 int CrashedApplication::pid() const
93 {
94 return m_pid;
95 }
96
signalNumber() const97 int CrashedApplication::signalNumber() const
98 {
99 return m_signalNumber;
100 }
101
signalName() const102 QString CrashedApplication::signalName() const
103 {
104 #if HAVE_STRSIGNAL && defined(Q_OS_UNIX)
105 const QByteArray originalLocale(std::setlocale(LC_MESSAGES, nullptr));
106 std::setlocale(LC_MESSAGES, "C");
107 const char *name = strsignal(m_signalNumber);
108 std::setlocale(LC_MESSAGES, originalLocale.data() /* empty string if we got a nullptr */);
109 return QString::fromLocal8Bit(name ? name : "Unknown");
110 #else
111 switch (m_signalNumber) {
112 #if defined(Q_OS_UNIX)
113 case SIGILL:
114 return QLatin1String("SIGILL");
115 case SIGABRT:
116 return QLatin1String("SIGABRT");
117 case SIGFPE:
118 return QLatin1String("SIGFPE");
119 case SIGSEGV:
120 return QLatin1String("SIGSEGV");
121 case SIGBUS:
122 return QLatin1String("SIGBUS");
123 #else
124 case EXCEPTION_ACCESS_VIOLATION:
125 return QLatin1String("EXCEPTION_ACCESS_VIOLATION");
126 case EXCEPTION_DATATYPE_MISALIGNMENT:
127 return QLatin1String("EXCEPTION_DATATYPE_MISALIGNMENT");
128 case EXCEPTION_BREAKPOINT:
129 return QLatin1String("EXCEPTION_BREAKPOINT");
130 case EXCEPTION_SINGLE_STEP:
131 return QLatin1String("EXCEPTION_SINGLE_STEP");
132 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
133 return QLatin1String("EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
134 case EXCEPTION_FLT_DENORMAL_OPERAND:
135 return QLatin1String("EXCEPTION_FLT_DENORMAL_OPERAND");
136 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
137 return QLatin1String("EXCEPTION_FLT_DIVIDE_BY_ZERO");
138 case EXCEPTION_FLT_INEXACT_RESULT:
139 return QLatin1String("EXCEPTION_FLT_INEXACT_RESULT");
140 case EXCEPTION_FLT_INVALID_OPERATION:
141 return QLatin1String("EXCEPTION_FLT_INVALID_OPERATION");
142 case EXCEPTION_FLT_OVERFLOW:
143 return QLatin1String("EXCEPTION_FLT_OVERFLOW");
144 case EXCEPTION_FLT_STACK_CHECK:
145 return QLatin1String("EXCEPTION_FLT_STACK_CHECK");
146 case EXCEPTION_FLT_UNDERFLOW:
147 return QLatin1String("EXCEPTION_FLT_UNDERFLOW");
148 case EXCEPTION_INT_DIVIDE_BY_ZERO:
149 return QLatin1String("EXCEPTION_INT_DIVIDE_BY_ZERO");
150 case EXCEPTION_INT_OVERFLOW:
151 return QLatin1String("EXCEPTION_INT_OVERFLOW");
152 case EXCEPTION_PRIV_INSTRUCTION:
153 return QLatin1String("EXCEPTION_PRIV_INSTRUCTION");
154 case EXCEPTION_IN_PAGE_ERROR:
155 return QLatin1String("EXCEPTION_IN_PAGE_ERROR");
156 case EXCEPTION_ILLEGAL_INSTRUCTION:
157 return QLatin1String("EXCEPTION_ILLEGAL_INSTRUCTION");
158 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
159 return QLatin1String("EXCEPTION_NONCONTINUABLE_EXCEPTION");
160 case EXCEPTION_STACK_OVERFLOW:
161 return QLatin1String("EXCEPTION_STACK_OVERFLOW");
162 case EXCEPTION_INVALID_DISPOSITION:
163 return QLatin1String("EXCEPTION_INVALID_DISPOSITION");
164 #endif
165 default:
166 return QLatin1String("Unknown");
167 }
168 #endif
169 }
170
hasBeenRestarted() const171 bool CrashedApplication::hasBeenRestarted() const
172 {
173 return m_restarted;
174 }
175
thread() const176 int CrashedApplication::thread() const
177 {
178 return m_thread;
179 }
180
datetime() const181 const QDateTime &CrashedApplication::datetime() const
182 {
183 return m_datetime;
184 }
185
hasDeletedFiles() const186 bool CrashedApplication::hasDeletedFiles() const
187 {
188 return m_hasDeletedFiles;
189 }
190
restart()191 void CrashedApplication::restart()
192 {
193 if (m_restarted) {
194 return;
195 }
196
197 // start the application via CommandLauncherJob so it runs in a new cgroup if possible.
198 // if m_fakeBaseName is set, this means m_executable is the path to kdeinit4
199 // so we need to use the fakeBaseName to restart the app
200 auto job = new KIO::CommandLauncherJob(!m_fakeBaseName.isEmpty() ? m_fakeBaseName : m_executable.absoluteFilePath());
201 if (const QString &id = DrKonqi::startupId(); !id.isEmpty()) {
202 job->setStartupId(id.toUtf8());
203 }
204 connect(job, &KIO::CommandLauncherJob::result, this, [job, this] {
205 m_restarted = (job->error() == KJob::NoError);
206 Q_EMIT restarted(m_restarted);
207 });
208 job->start();
209 }
210
getSuggestedKCrashFilename(const CrashedApplication * app)211 QString getSuggestedKCrashFilename(const CrashedApplication *app)
212 {
213 QString filename =
214 app->fakeExecutableBaseName() + QLatin1Char('-') + app->datetime().toString(QStringLiteral("yyyyMMdd-hhmmss")) + QStringLiteral(".kcrash");
215
216 if (filename.contains(QLatin1Char('/'))) {
217 filename = filename.mid(filename.lastIndexOf(QLatin1Char('/')) + 1);
218 }
219
220 return filename;
221 }
222