File indexing completed on 2024-04-21 16:12:15
0001 /******************************************************************* 0002 * parsebugbacktraces.cpp 0003 * SPDX-FileCopyrightText: 2011 Matthias Fuchs <mat69@gmx.net> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 * 0007 ******************************************************************/ 0008 0009 #include "parsebugbacktraces.h" 0010 0011 #include "parser/backtraceparser.h" 0012 0013 typedef QList<BacktraceLine>::const_iterator BacktraceConstIterator; 0014 0015 BacktraceConstIterator findCrashStackFrame(BacktraceConstIterator it, BacktraceConstIterator itEnd) 0016 { 0017 BacktraceConstIterator result = itEnd; 0018 0019 // find the beginning of the crash 0020 for (; it != itEnd; ++it) { 0021 if (it->type() == BacktraceLine::KCrash) { 0022 result = it; 0023 break; 0024 } 0025 } 0026 0027 // find the beginning of the stack frame 0028 for (it = result; it != itEnd; ++it) { 0029 if (it->type() == BacktraceLine::StackFrame) { 0030 result = it; 0031 break; 0032 } 0033 } 0034 0035 return result; 0036 } 0037 0038 // TODO improve this stuff, it is just a HACK 0039 ParseBugBacktraces::DuplicateRating rating(BacktraceConstIterator it, BacktraceConstIterator itEnd, BacktraceConstIterator it2, BacktraceConstIterator itEnd2) 0040 { 0041 int matches = 0; 0042 int lines = 0; 0043 0044 it = findCrashStackFrame(it, itEnd); 0045 it2 = findCrashStackFrame(it2, itEnd2); 0046 0047 while (it != itEnd && it2 != itEnd2) { 0048 if (it->type() == BacktraceLine::StackFrame && it2->type() == BacktraceLine::StackFrame) { 0049 ++lines; 0050 if (it->frameNumber() == it2->frameNumber() && it->functionName() == it2->functionName()) { 0051 ++matches; 0052 } 0053 ++it; 0054 ++it2; 0055 continue; 0056 } 0057 0058 // if iters do not point to emptylines or a stackframe increase them 0059 if (it->type() != BacktraceLine::StackFrame && it->type() != BacktraceLine::EmptyLine) { 0060 ++it; 0061 continue; 0062 } 0063 if (it2->type() != BacktraceLine::StackFrame && it2->type() != BacktraceLine::EmptyLine) { 0064 ++it2; 0065 continue; 0066 } 0067 0068 // one bt is shorter than the other 0069 if (it->type() == BacktraceLine::StackFrame && it2->type() == BacktraceLine::EmptyLine) { 0070 ++lines; 0071 ++it; 0072 continue; 0073 } 0074 if (it2->type() == BacktraceLine::StackFrame && it->type() == BacktraceLine::EmptyLine) { 0075 ++lines; 0076 ++it2; 0077 continue; 0078 } 0079 0080 if (it->type() == BacktraceLine::EmptyLine && it2->type() == BacktraceLine::EmptyLine) { 0081 // done 0082 break; 0083 } 0084 } 0085 0086 if (!lines) { 0087 return ParseBugBacktraces::NoDuplicate; 0088 } 0089 0090 const int rating = matches * 100 / lines; 0091 if (rating == 100) { 0092 return ParseBugBacktraces::PerfectDuplicate; 0093 } else if (rating >= 90) { 0094 return ParseBugBacktraces::MostLikelyDuplicate; 0095 } else if (rating >= 60) { 0096 return ParseBugBacktraces::MaybeDuplicate; 0097 } else { 0098 return ParseBugBacktraces::NoDuplicate; 0099 } 0100 } 0101 0102 ParseBugBacktraces::ParseBugBacktraces(const QList<Bugzilla::Comment::Ptr> &comments, QObject *parent) 0103 : QObject(parent) 0104 , m_comments(comments) 0105 { 0106 m_parser = BacktraceParser::newParser(QStringLiteral("gdb"), this); 0107 m_parser->connectToGenerator(this); 0108 } 0109 0110 void ParseBugBacktraces::parse() 0111 { 0112 for (const auto &comment : m_comments) { 0113 parse(comment->text()); 0114 } 0115 } 0116 0117 void ParseBugBacktraces::parse(const QString &comment) 0118 { 0119 Q_EMIT starting(); 0120 0121 int start = 0; 0122 int end = -1; 0123 do { 0124 start = end + 1; 0125 end = comment.indexOf(QLatin1Char('\n'), start); 0126 Q_EMIT newLine(comment.mid(start, (end != -1 ? end - start + 1 : end))); 0127 } while (end != -1); 0128 0129 // accepts anything as backtrace, the start of the backtrace is searched later anyway 0130 m_backtraces << m_parser->parsedBacktraceLines(); 0131 } 0132 0133 ParseBugBacktraces::DuplicateRating ParseBugBacktraces::findDuplicate(const QList<BacktraceLine> &backtrace) 0134 { 0135 if (m_backtraces.isEmpty() || backtrace.isEmpty()) { 0136 return NoDuplicate; 0137 } 0138 0139 DuplicateRating bestRating = NoDuplicate; 0140 DuplicateRating currentRating = NoDuplicate; 0141 0142 QList<QList<BacktraceLine>>::const_iterator itBts; 0143 QList<QList<BacktraceLine>>::const_iterator itEndBts = m_backtraces.constEnd(); 0144 for (itBts = m_backtraces.constBegin(); itBts != itEndBts; ++itBts) { 0145 currentRating = rating(backtrace.constBegin(), backtrace.constEnd(), itBts->constBegin(), itBts->constEnd()); 0146 if (currentRating < bestRating) { 0147 bestRating = currentRating; 0148 } 0149 0150 if (bestRating == PerfectDuplicate) { 0151 return bestRating; 0152 } 0153 } 0154 0155 return bestRating; 0156 }