Warning: That file was not part of the compilation database. It may have many parsing errors.
1 | /**************************************************************************** |
---|---|
2 | ** |
3 | ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the tools applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and Digia. For licensing terms and |
14 | ** conditions see http://qt.digia.com/licensing. For further information |
15 | ** use the contact form at http://qt.digia.com/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 2.1 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements |
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
24 | ** |
25 | ** In addition, as a special exception, Digia gives you certain additional |
26 | ** rights. These rights are described in the Digia Qt LGPL Exception |
27 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
28 | ** |
29 | ** GNU General Public License Usage |
30 | ** Alternatively, this file may be used under the terms of the GNU |
31 | ** General Public License version 3.0 as published by the Free Software |
32 | ** Foundation and appearing in the file LICENSE.GPL included in the |
33 | ** packaging of this file. Please review the following information to |
34 | ** ensure the GNU General Public License version 3.0 requirements will be |
35 | ** met: http://www.gnu.org/copyleft/gpl.html. |
36 | ** |
37 | ** |
38 | ** $QT_END_LICENSE$ |
39 | ** |
40 | ****************************************************************************/ |
41 | |
42 | #include <QDebug> |
43 | #include <QCoreApplication> |
44 | #include <QObject> |
45 | #include <QFile> |
46 | #include <QDir> |
47 | #include "trksignalhandler.h" |
48 | #include "trkutils.h" |
49 | |
50 | class CrashState |
51 | { |
52 | public: |
53 | uint pid; |
54 | uint tid; |
55 | QString crashReason; |
56 | uint crashPC; |
57 | }; |
58 | |
59 | class TrkSignalHandlerPrivate |
60 | { |
61 | friend class TrkSignalHandler; |
62 | public: |
63 | TrkSignalHandlerPrivate(); |
64 | ~TrkSignalHandlerPrivate(); |
65 | private: |
66 | QTextStream out; |
67 | QTextStream err; |
68 | int loglevel; |
69 | int lastpercent; |
70 | QList<trk::Library> libraries; |
71 | QFile crashlogtextfile; |
72 | QFile crashstackfile; |
73 | QList<CrashState> queuedCrashes; |
74 | QList<int> dyingThreads; |
75 | QString crashlogPath; |
76 | bool crashlog; |
77 | bool terminateNeeded; |
78 | }; |
79 | |
80 | void TrkSignalHandler::copyingStarted(const QString &fileName) |
81 | { |
82 | if (d->loglevel > 0) |
83 | d->out << "Copying "<< fileName << "..."<< endl; |
84 | } |
85 | |
86 | void TrkSignalHandler::canNotConnect(const QString &errorMessage) |
87 | { |
88 | d->err << "Cannot connect - "<< errorMessage << endl; |
89 | } |
90 | |
91 | void TrkSignalHandler::canNotCreateFile(const QString &filename, const QString &errorMessage) |
92 | { |
93 | d->err << "Cannot create file ("<< filename << ") - "<< errorMessage << endl; |
94 | } |
95 | |
96 | void TrkSignalHandler::canNotWriteFile(const QString &filename, const QString &errorMessage) |
97 | { |
98 | d->err << "Cannot write file ("<< filename << ") - "<< errorMessage << endl; |
99 | } |
100 | |
101 | void TrkSignalHandler::canNotCloseFile(const QString &filename, const QString &errorMessage) |
102 | { |
103 | d->err << "Cannot close file ("<< filename << ") - "<< errorMessage << endl; |
104 | } |
105 | |
106 | void TrkSignalHandler::installingStarted(const QString &packageName) |
107 | { |
108 | if (d->loglevel > 0) |
109 | d->out << "Installing "<< packageName << "..."<< endl; |
110 | } |
111 | |
112 | void TrkSignalHandler::canNotInstall(const QString &packageFilename, const QString &errorMessage) |
113 | { |
114 | d->err << "Cannot install file ("<< packageFilename << ") - "<< errorMessage << endl; |
115 | } |
116 | |
117 | void TrkSignalHandler::installingFinished() |
118 | { |
119 | if (d->loglevel > 0) |
120 | d->out << "Installing finished"<< endl; |
121 | } |
122 | |
123 | void TrkSignalHandler::startingApplication() |
124 | { |
125 | if (d->loglevel > 0) |
126 | d->out << "Starting app..."<< endl; |
127 | } |
128 | |
129 | void TrkSignalHandler::applicationRunning(uint pid) |
130 | { |
131 | Q_UNUSED(pid) |
132 | if (d->loglevel > 0) |
133 | d->out << "Running..."<< endl; |
134 | } |
135 | |
136 | void TrkSignalHandler::canNotRun(const QString &errorMessage) |
137 | { |
138 | d->err << "Cannot run - "<< errorMessage << endl; |
139 | } |
140 | |
141 | void TrkSignalHandler::finished() |
142 | { |
143 | if (d->loglevel > 0) |
144 | d->out << "Done."<< endl; |
145 | QCoreApplication::quit(); |
146 | } |
147 | |
148 | void TrkSignalHandler::applicationOutputReceived(const QString &output) |
149 | { |
150 | d->out << output << flush; |
151 | } |
152 | |
153 | void TrkSignalHandler::copyProgress(int percent) |
154 | { |
155 | if (d->loglevel > 0) { |
156 | if (d->lastpercent == 0) |
157 | d->out << "[ ]\r["<< flush; |
158 | while (percent > d->lastpercent) { |
159 | d->out << QLatin1Char( |
160 | d->lastpercent+=2; //because typical console is 80 chars wide |
161 | } |
162 | d->out.flush(); |
163 | if (percent==100) |
164 | d->out << endl; |
165 | } |
166 | } |
167 | |
168 | void TrkSignalHandler::stateChanged(int state) |
169 | { |
170 | if (d->loglevel > 1) |
171 | d->out << "State"<< state << endl; |
172 | } |
173 | |
174 | void TrkSignalHandler::setLogLevel(int level) |
175 | { |
176 | d->loglevel = level; |
177 | } |
178 | |
179 | void TrkSignalHandler::setCrashLogging(bool enabled) |
180 | { |
181 | d->crashlog = enabled; |
182 | } |
183 | |
184 | void TrkSignalHandler::setCrashLogPath(QString path) |
185 | { |
186 | d->crashlogPath = path; |
187 | } |
188 | |
189 | bool lessThanCodeBase(const trk::Library& cs1, const trk::Library& cs2) |
190 | { |
191 | return cs1.codeseg < cs2.codeseg; |
192 | } |
193 | |
194 | void TrkSignalHandler::stopped(uint pc, uint pid, uint tid, const QString& reason) |
195 | { |
196 | d->err << "STOPPED: pc="<< hex << pc << " pid="<< pid |
197 | << " tid="<< tid << dec << " - "<< reason << endl; |
198 | |
199 | if (d->crashlog) { |
200 | CrashState cs; |
201 | cs.pid = pid; |
202 | cs.tid = tid; |
203 | cs.crashPC = pc; |
204 | cs.crashReason = reason; |
205 | |
206 | if (d->dyingThreads.contains(tid)) { |
207 | if(d->queuedCrashes.isEmpty()) |
208 | emit terminate(); |
209 | else |
210 | d->terminateNeeded = true; |
211 | } else { |
212 | d->queuedCrashes.append(cs); |
213 | d->dyingThreads.append(tid); |
214 | |
215 | if (d->queuedCrashes.count() == 1) { |
216 | d->err << "Fetching registers and stack..."<< endl; |
217 | emit getRegistersAndCallStack(pid, tid); |
218 | } |
219 | } |
220 | } |
221 | else |
222 | emit terminate(); |
223 | } |
224 | |
225 | void TrkSignalHandler::registersAndCallStackReadComplete(const QList<uint>& registers, const QByteArray& stack) |
226 | { |
227 | CrashState cs = d->queuedCrashes.first(); |
228 | QDir dir(d->crashlogPath); |
229 | d->crashlogtextfile.setFileName(dir.filePath(QString("d_exc_%1.txt").arg(cs.tid))); |
230 | d->crashstackfile.setFileName(dir.filePath(QString("d_exc_%1.stk").arg(cs.tid))); |
231 | d->crashlogtextfile.open(QIODevice::WriteOnly); |
232 | QTextStream crashlog(&d->crashlogtextfile); |
233 | |
234 | crashlog << "-----------------------------------------------------------------------------"<< endl; |
235 | crashlog << "EKA2 USER CRASH LOG"<< endl; |
236 | crashlog << "Thread Name: "<< QString( "ProcessID-%1::ThreadID-%2").arg(cs.pid).arg(cs.tid) << endl; |
237 | crashlog << "Thread ID: "<< cs.tid << endl; |
238 | //this is wrong, but TRK doesn't make stack limit available so we lie |
239 | crashlog << QString("User Stack %1-%2").arg(registers.at(13), 8, 16, QChar( |
240 | //this is also wrong, but TRK doesn't give all information for exceptions |
241 | crashlog << QString("Panic: PC=%1 ").arg(cs.crashPC, 8, 16, QChar( |
242 | crashlog << endl; |
243 | crashlog << "USER REGISTERS:"<< endl; |
244 | crashlog << QString("CPSR=%1").arg(registers.at(16), 8, 16, QChar( |
245 | for (int i=0;i<16;i+=4) { |
246 | crashlog << QString("r%1=%2 %3 %4 %5") |
247 | .arg(i, 2, 10, QChar( |
248 | .arg(registers.at(i), 8, 16, QChar( |
249 | .arg(registers.at(i+1), 8, 16, QChar( |
250 | .arg(registers.at(i+2), 8, 16, QChar( |
251 | .arg(registers.at(i+3), 8, 16, QChar( |
252 | } |
253 | crashlog << endl; |
254 | |
255 | //emit info for post mortem debug |
256 | qSort(d->libraries.begin(), d->libraries.end(), lessThanCodeBase); |
257 | d->err << "Code Segments:"<< endl; |
258 | crashlog << "CODE SEGMENTS:"<< endl; |
259 | for(int i=0; i<d->libraries.count(); i++) { |
260 | const trk::Library& seg = d->libraries.at(i); |
261 | if(seg.pid != cs.pid) |
262 | continue; |
263 | if (d->loglevel > 1) { |
264 | d->err << QString("Code: %1 Data: %2 Name: ") |
265 | .arg(seg.codeseg, 8, 16, QChar( |
266 | .arg(seg.dataseg, 8, 16, QChar( |
267 | << seg.name << endl; |
268 | } |
269 | |
270 | //produce fake code segment end addresses since we don't get the real ones from TRK |
271 | uint end; |
272 | if (i+1 < d->libraries.count()) |
273 | end = d->libraries.at(i+1).codeseg - 1; |
274 | else |
275 | end = 0xFFFFFFFF; |
276 | |
277 | crashlog << QString("%1-%2 ") |
278 | .arg(seg.codeseg, 8, 16, QChar( |
279 | .arg(end, 8, 16, QChar( |
280 | << seg.name << endl; |
281 | } |
282 | |
283 | d->crashlogtextfile.close(); |
284 | |
285 | if (d->loglevel > 1) { |
286 | d->err << "Registers:"<< endl; |
287 | for (int i=0;i<16;i++) { |
288 | d->err << QString("R%1: %2 ").arg(i, 2, 10, QChar( |
289 | if (i % 4 == 3) |
290 | d->err << endl; |
291 | } |
292 | d->err << QString("CPSR: %1").arg(registers.at(16), 8, 16, QChar( |
293 | |
294 | d->err << "Stack:"<< endl; |
295 | uint sp = registers.at(13); |
296 | for(int i=0; i<stack.size(); i+=16, sp+=16) { |
297 | d->err << QString("%1: ").arg(sp, 8, 16, QChar( |
298 | d->err << trk::stringFromArray(stack.mid(i,16)); |
299 | d->err << endl; |
300 | } |
301 | } |
302 | d->crashstackfile.open(QIODevice::WriteOnly); |
303 | d->crashstackfile.write(stack); |
304 | d->crashstackfile.close(); |
305 | |
306 | if (d->loglevel > 0) |
307 | d->err << "Crash logs saved to "<< d->crashlogtextfile.fileName() << " & "<< d->crashstackfile.fileName() << endl; |
308 | |
309 | // resume the thread to allow Symbian OS to handle the panic normally. |
310 | // terminate when a non main thread is suspended reboots the phone (TRK bug) |
311 | emit resume(cs.pid, cs.tid); |
312 | |
313 | //fetch next crashed thread |
314 | d->queuedCrashes.removeFirst(); |
315 | if (d->queuedCrashes.count()) { |
316 | cs = d->queuedCrashes.first(); |
317 | d->err << "Fetching registers and stack..."<< endl; |
318 | emit getRegistersAndCallStack(cs.pid, cs.tid); |
319 | } |
320 | else if (d->terminateNeeded) |
321 | emit terminate(); |
322 | |
323 | } |
324 | |
325 | void TrkSignalHandler::libraryLoaded(const trk::Library &lib) |
326 | { |
327 | d->libraries << lib; |
328 | } |
329 | |
330 | void TrkSignalHandler::libraryUnloaded(const trk::Library &lib) |
331 | { |
332 | for (QList<trk::Library>::iterator i = d->libraries.begin(); i != d->libraries.end(); i++) { |
333 | if((*i).name == lib.name && (*i).pid == lib.pid) |
334 | i = d->libraries.erase(i); |
335 | } |
336 | } |
337 | |
338 | void TrkSignalHandler::timeout() |
339 | { |
340 | d->err << "FAILED: stopping test due to timeout"<< endl; |
341 | emit terminate(); |
342 | } |
343 | |
344 | TrkSignalHandlerPrivate::TrkSignalHandlerPrivate() |
345 | : out(stdout), |
346 | err(stderr), |
347 | loglevel(0), |
348 | lastpercent(0), |
349 | terminateNeeded(false) |
350 | { |
351 | |
352 | } |
353 | |
354 | TrkSignalHandlerPrivate::~TrkSignalHandlerPrivate() |
355 | { |
356 | out.flush(); |
357 | err.flush(); |
358 | } |
359 | |
360 | TrkSignalHandler::TrkSignalHandler() |
361 | : d(new TrkSignalHandlerPrivate()) |
362 | { |
363 | } |
364 | |
365 | TrkSignalHandler::~TrkSignalHandler() |
366 | { |
367 | delete d; |
368 | } |
369 |
Warning: That file was not part of the compilation database. It may have many parsing errors.