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
50class CrashState
51{
52public:
53 uint pid;
54 uint tid;
55 QString crashReason;
56 uint crashPC;
57};
58
59class TrkSignalHandlerPrivate
60{
61 friend class TrkSignalHandler;
62public:
63 TrkSignalHandlerPrivate();
64 ~TrkSignalHandlerPrivate();
65private:
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
80void TrkSignalHandler::copyingStarted(const QString &fileName)
81{
82 if (d->loglevel > 0)
83 d->out << "Copying " << fileName << "..." << endl;
84}
85
86void TrkSignalHandler::canNotConnect(const QString &errorMessage)
87{
88 d->err << "Cannot connect - " << errorMessage << endl;
89}
90
91void TrkSignalHandler::canNotCreateFile(const QString &filename, const QString &errorMessage)
92{
93 d->err << "Cannot create file (" << filename << ") - " << errorMessage << endl;
94}
95
96void TrkSignalHandler::canNotWriteFile(const QString &filename, const QString &errorMessage)
97{
98 d->err << "Cannot write file (" << filename << ") - " << errorMessage << endl;
99}
100
101void TrkSignalHandler::canNotCloseFile(const QString &filename, const QString &errorMessage)
102{
103 d->err << "Cannot close file (" << filename << ") - " << errorMessage << endl;
104}
105
106void TrkSignalHandler::installingStarted(const QString &packageName)
107{
108 if (d->loglevel > 0)
109 d->out << "Installing " << packageName << "..." << endl;
110}
111
112void TrkSignalHandler::canNotInstall(const QString &packageFilename, const QString &errorMessage)
113{
114 d->err << "Cannot install file (" << packageFilename << ") - " << errorMessage << endl;
115}
116
117void TrkSignalHandler::installingFinished()
118{
119 if (d->loglevel > 0)
120 d->out << "Installing finished" << endl;
121}
122
123void TrkSignalHandler::startingApplication()
124{
125 if (d->loglevel > 0)
126 d->out << "Starting app..." << endl;
127}
128
129void TrkSignalHandler::applicationRunning(uint pid)
130{
131 Q_UNUSED(pid)
132 if (d->loglevel > 0)
133 d->out << "Running..." << endl;
134}
135
136void TrkSignalHandler::canNotRun(const QString &errorMessage)
137{
138 d->err << "Cannot run - " << errorMessage << endl;
139}
140
141void TrkSignalHandler::finished()
142{
143 if (d->loglevel > 0)
144 d->out << "Done." << endl;
145 QCoreApplication::quit();
146}
147
148void TrkSignalHandler::applicationOutputReceived(const QString &output)
149{
150 d->out << output << flush;
151}
152
153void 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
168void TrkSignalHandler::stateChanged(int state)
169{
170 if (d->loglevel > 1)
171 d->out << "State" << state << endl;
172}
173
174void TrkSignalHandler::setLogLevel(int level)
175{
176 d->loglevel = level;
177}
178
179void TrkSignalHandler::setCrashLogging(bool enabled)
180{
181 d->crashlog = enabled;
182}
183
184void TrkSignalHandler::setCrashLogPath(QString path)
185{
186 d->crashlogPath = path;
187}
188
189bool lessThanCodeBase(const trk::Library& cs1, const trk::Library& cs2)
190{
191 return cs1.codeseg < cs2.codeseg;
192}
193
194void 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
225void 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('0')).arg(registers.at(13) + stack.size(), 8, 16, QChar('0')) << endl;
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('0')) << cs.crashReason << endl;
242 crashlog << endl;
243 crashlog << "USER REGISTERS:" << endl;
244 crashlog << QString("CPSR=%1").arg(registers.at(16), 8, 16, QChar('0')) << endl;
245 for (int i=0;i<16;i+=4) {
246 crashlog << QString("r%1=%2 %3 %4 %5")
247 .arg(i, 2, 10, QChar('0'))
248 .arg(registers.at(i), 8, 16, QChar('0'))
249 .arg(registers.at(i+1), 8, 16, QChar('0'))
250 .arg(registers.at(i+2), 8, 16, QChar('0'))
251 .arg(registers.at(i+3), 8, 16, QChar('0')) << endl;
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('0'))
266 .arg(seg.dataseg, 8, 16, QChar('0'))
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('0'))
279 .arg(end, 8, 16, QChar('0'))
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('0')).arg(registers.at(i), 8, 16, QChar('0'));
289 if (i % 4 == 3)
290 d->err << endl;
291 }
292 d->err << QString("CPSR: %1").arg(registers.at(16), 8, 16, QChar('0')) << endl;
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('0'));
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
325void TrkSignalHandler::libraryLoaded(const trk::Library &lib)
326{
327 d->libraries << lib;
328}
329
330void 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
338void TrkSignalHandler::timeout()
339{
340 d->err << "FAILED: stopping test due to timeout" << endl;
341 emit terminate();
342}
343
344TrkSignalHandlerPrivate::TrkSignalHandlerPrivate()
345 : out(stdout),
346 err(stderr),
347 loglevel(0),
348 lastpercent(0),
349 terminateNeeded(false)
350{
351
352}
353
354TrkSignalHandlerPrivate::~TrkSignalHandlerPrivate()
355{
356 out.flush();
357 err.flush();
358}
359
360TrkSignalHandler::TrkSignalHandler()
361 : d(new TrkSignalHandlerPrivate())
362{
363}
364
365TrkSignalHandler::~TrkSignalHandler()
366{
367 delete d;
368}
369

Warning: That file was not part of the compilation database. It may have many parsing errors.