File indexing completed on 2024-12-08 04:54:50
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 // SPDX-FileCopyrightText: 2020-2022 Harald Sitter <sitter@kde.org> 0003 0004 #include "Patient.h" 0005 0006 #include <QApplication> 0007 #include <QDebug> 0008 #include <QFileInfo> 0009 #include <QMessageBox> 0010 #include <QProcess> 0011 0012 #include <KApplicationTrader> 0013 #include <KLocalizedString> 0014 #include <KShell> 0015 #include <KTerminalLauncherJob> 0016 0017 #include "../coredump/coredump.h" 0018 0019 using namespace Qt::StringLiterals; 0020 0021 Patient::Patient(const Coredump &dump) 0022 : m_origCoreFilename(QString::fromUtf8(dump.m_rawData.value("COREDUMP_FILENAME"))) 0023 , m_coreFileInfo(m_origCoreFilename) 0024 , m_signal(dump.m_rawData["COREDUMP_SIGNAL"].toInt()) 0025 , m_appName(QFileInfo(dump.exe).fileName()) 0026 , m_pid(dump.pid) 0027 , m_timestamp(dump.m_rawData["COREDUMP_TIMESTAMP"].toLong()) 0028 , m_coredumpExe(dump.m_rawData["COREDUMP_EXE"]) 0029 , m_coredumpCom(dump.m_rawData["COREDUMP_COMM"]) 0030 { 0031 } 0032 0033 QStringList Patient::coredumpctlArguments(const QString &command) const 0034 { 0035 return {command, u"COREDUMP_FILENAME=%1"_s.arg(m_origCoreFilename)}; 0036 } 0037 0038 void Patient::launchDebugger() 0039 { 0040 const QString arguments = KShell::joinArgs({u"gdb"_s, u"--core=%1"_s.arg(m_coreFileInfo.filePath()), QString::fromUtf8(m_coredumpExe)}); 0041 auto job = new KTerminalLauncherJob(arguments); 0042 connect(job, &KJob::result, this, [job] { 0043 job->deleteLater(); 0044 if (job->error() != KJob::NoError) { 0045 qWarning() << job->errorText(); 0046 } 0047 }); 0048 job->start(); 0049 } 0050 0051 void Patient::debug() 0052 { 0053 if (!m_excavator) { 0054 m_excavator = std::make_unique<AutomaticCoredumpExcavator>(); 0055 connect(m_excavator.get(), &AutomaticCoredumpExcavator::failed, this, [this] { 0056 QMessageBox::critical(qApp ? qApp->activeWindow() : nullptr, 0057 i18nc("@title", "Failure"), 0058 i18nc("@info", "Failed to access crash data for unknown reasons.")); 0059 m_excavator.release()->deleteLater(); 0060 }); 0061 connect(m_excavator.get(), &AutomaticCoredumpExcavator::excavated, this, [this](const QString &corePath) { 0062 m_coreFileInfo = QFileInfo(corePath); 0063 launchDebugger(); 0064 }); 0065 m_excavator->excavateFrom(m_coreFileInfo.filePath()); 0066 return; 0067 } 0068 if (m_coreFileInfo.isReadable()) { 0069 launchDebugger(); 0070 } 0071 // else supposedly still waiting for excavator 0072 } 0073 0074 QString Patient::dateTime() const 0075 { 0076 QDateTime time; 0077 time.setMSecsSinceEpoch(m_timestamp / 1000); 0078 return QLocale().toString(time, QLocale::LongFormat); 0079 } 0080 0081 QString Patient::iconName() const 0082 { 0083 // Caching it because it's an N² look-up and there generally are tons of duplicates 0084 static QHash<QString, QString> s_cache; 0085 const QString executable = m_appName; 0086 auto it = s_cache.find(executable); 0087 if (it == s_cache.end()) { 0088 const auto servicesFound = KApplicationTrader::query([&executable](const KService::Ptr &service) { 0089 return QFileInfo(service->exec()).fileName() == executable; 0090 }); 0091 0092 QString iconName; 0093 if (servicesFound.isEmpty()) { 0094 iconName = QStringLiteral("applications-science"); 0095 } else { 0096 iconName = servicesFound.constFirst()->icon(); 0097 } 0098 it = s_cache.insert(executable, iconName); 0099 } 0100 return *it; 0101 } 0102 0103 bool Patient::canDebug() 0104 { 0105 return m_coreFileInfo.exists(); 0106 } 0107 0108 #include "moc_Patient.cpp"