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 | |
24 | typedef QList<BacktraceLine>::const_iterator BacktraceConstIterator; |
25 | |
26 | BacktraceConstIterator 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 |
50 | ParseBugBacktraces::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 | |
115 | ParseBugBacktraces::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 | |
123 | void ParseBugBacktraces::parse() |
124 | { |
125 | parse(m_bug.description()); |
126 | |
127 | QStringList = m_bug.comments(); |
128 | foreach (const QString &, comments) { |
129 | parse(comment); |
130 | } |
131 | } |
132 | |
133 | void ParseBugBacktraces::parse(const QString &) |
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 | |
149 | ParseBugBacktraces::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 | |