1/*******************************************************************
2* parsebugbacktraces.cpp
3* Copyright 2011 Matthias Fuchs <mat69@gmx.net>
4*
5* This program is free software; you can redistribute it and/or
6* modify it under the terms of the GNU General Public License as
7* published by the Free Software Foundation; either version 2 of
8* the License, or (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <http://www.gnu.org/licenses/>.
17*
18******************************************************************/
19
20#include "parsebugbacktraces.h"
21
22#include "parser/backtraceparser.h"
23
24typedef QList<BacktraceLine>::const_iterator BacktraceConstIterator;
25
26BacktraceConstIterator findCrashStackFrame(BacktraceConstIterator it, BacktraceConstIterator itEnd)
27{
28 BacktraceConstIterator result = itEnd;
29
30 //find the beginning of the crash
31 for ( ; it != itEnd; ++it) {
32 if (it->type() == BacktraceLine::KCrash) {
33 result = it;
34 break;
35 }
36 }
37
38 //find the beginning of the stack frame
39 for (it = result; it != itEnd; ++it) {
40 if (it->type() == BacktraceLine::StackFrame) {
41 result = it;
42 break;
43 }
44 }
45
46 return result;
47}
48
49//TODO improve this stuff, it is just a HACK
50ParseBugBacktraces::DuplicateRating rating(BacktraceConstIterator it, BacktraceConstIterator itEnd, BacktraceConstIterator it2, BacktraceConstIterator itEnd2)
51{
52 int matches = 0;
53 int lines = 0;
54
55 it = findCrashStackFrame(it, itEnd);
56 it2 = findCrashStackFrame(it2, itEnd2);
57
58 while (it != itEnd && it2 != itEnd2) {
59 if (it->type() == BacktraceLine::StackFrame && it2->type() == BacktraceLine::StackFrame) {
60 ++lines;
61 if (it->frameNumber() == it2->frameNumber() && it->functionName() == it2->functionName()) {
62 ++matches;
63 }
64 ++it;
65 ++it2;
66 continue;
67 }
68
69 //if iters do not point to emptylines or a stackframe increase them
70 if (it->type() != BacktraceLine::StackFrame && it->type() != BacktraceLine::EmptyLine) {
71 ++it;
72 continue;
73 }
74 if (it2->type() != BacktraceLine::StackFrame && it2->type() != BacktraceLine::EmptyLine) {
75 ++it2;
76 continue;
77 }
78
79 //one bt is shorter than the other
80 if (it->type() == BacktraceLine::StackFrame && it2->type() == BacktraceLine::EmptyLine) {
81 ++lines;
82 ++it;
83 continue;
84 }
85 if (it2->type() == BacktraceLine::StackFrame && it->type() == BacktraceLine::EmptyLine) {
86 ++lines;
87 ++it2;
88 continue;
89 }
90
91 if (it->type() == BacktraceLine::EmptyLine && it2->type() == BacktraceLine::EmptyLine) {
92 //done
93 break;
94 }
95 }
96
97 if (!lines) {
98 return ParseBugBacktraces::NoDuplicate;
99 }
100
101 const int rating = matches * 100 / lines;
102 if (rating == 100) {
103 return ParseBugBacktraces::PerfectDuplicate;
104 } else if (rating >= 90) {
105 return ParseBugBacktraces::MostLikelyDuplicate;
106 } else if (rating >= 60) {
107 return ParseBugBacktraces::MaybeDuplicate;
108 } else {
109 return ParseBugBacktraces::NoDuplicate;
110 }
111
112 return ParseBugBacktraces::NoDuplicate;
113}
114
115ParseBugBacktraces::ParseBugBacktraces(const BugReport &bug, QObject *parent)
116 : QObject(parent),
117 m_bug(bug)
118{
119 m_parser = BacktraceParser::newParser("gdb", this);
120 m_parser->connectToGenerator(this);
121}
122
123void ParseBugBacktraces::parse()
124{
125 parse(m_bug.description());
126
127 QStringList comments = m_bug.comments();
128 foreach (const QString &comment, comments) {
129 parse(comment);
130 }
131}
132
133void ParseBugBacktraces::parse(const QString &comment)
134{
135 emit starting();
136
137 int start = 0;
138 int end = -1;
139 do {
140 start = end + 1;
141 end = comment.indexOf('\n', start);
142 emit newLine(comment.mid(start, (end != -1 ? end - start + 1 : end)));
143 } while (end != -1);
144
145 //accepts anything as backtrace, the start of the backtrace is searched later anyway
146 m_backtraces << m_parser->parsedBacktraceLines();
147}
148
149ParseBugBacktraces::DuplicateRating ParseBugBacktraces::findDuplicate(const QList<BacktraceLine> &backtrace)
150{
151 if (m_backtraces.isEmpty() || backtrace.isEmpty()) {
152 return NoDuplicate;
153 }
154
155 DuplicateRating bestRating = NoDuplicate;
156 DuplicateRating currentRating = NoDuplicate;
157
158 QList<QList<BacktraceLine> >::const_iterator itBts;
159 QList<QList<BacktraceLine> >::const_iterator itEndBts = m_backtraces.constEnd();
160 for (itBts = m_backtraces.constBegin(); itBts != itEndBts; ++itBts) {
161 currentRating = rating(backtrace.constBegin(), backtrace.constEnd(), itBts->constBegin(), itBts->constEnd());
162 if (currentRating < bestRating) {
163 bestRating = currentRating;
164 }
165
166 if (bestRating == PerfectDuplicate) {
167 return bestRating;
168 }
169 }
170
171 return bestRating;
172}
173
174#include "parsebugbacktraces.moc"
175