source: trunk/tools/runonphone/symbianutils/tcftrkmessage.cpp@ 1147

Last change on this file since 1147 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 17.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "tcftrkmessage.h"
43#include "json.h"
44
45#include <QtCore/QString>
46#include <QtCore/QTextStream>
47
48// Names matching the enum
49static const char *serviceNamesC[] =
50{ "Locator", "RunControl", "Processes", "Memory", "Settings", "Breakpoints",
51 "Registers", "SimpleRegisters",
52 "UnknownService"};
53
54namespace tcftrk {
55
56SYMBIANUTILS_EXPORT QString joinByteArrays(const QVector<QByteArray> &a, char sep)
57{
58 QString rc;
59 const int count = a.size();
60 for (int i = 0; i < count; i++) {
61 if (i)
62 rc += QLatin1Char(sep);
63 rc += QString::fromUtf8(a.at(i));
64 }
65 return rc;
66}
67
68static inline bool jsonToBool(const JsonValue& js)
69{
70 return js.type() == JsonValue::Boolean && js.data() == "true";
71}
72
73SYMBIANUTILS_EXPORT const char *serviceName(Services s)
74{
75 return serviceNamesC[s];
76}
77
78SYMBIANUTILS_EXPORT Services serviceFromName(const char *n)
79{
80 const int count = sizeof(serviceNamesC)/sizeof(char *);
81 for (int i = 0; i < count; i++)
82 if (!qstrcmp(serviceNamesC[i], n))
83 return static_cast<Services>(i);
84 return UnknownService;
85}
86
87SYMBIANUTILS_EXPORT QString formatData(const QByteArray &a)
88{
89 const int columns = 16;
90 QString rc;
91 QTextStream str(&rc);
92 str.setIntegerBase(16);
93 str.setPadChar(QLatin1Char('0'));
94 const unsigned char *start = reinterpret_cast<const unsigned char *>(a.constData());
95 const unsigned char *end = start + a.size();
96 for (const unsigned char *p = start; p < end ; ) {
97 str << "0x";
98 str.setFieldWidth(4);
99 str << (p - start);
100 str.setFieldWidth(0);
101 str << ' ';
102 QString asc;
103 int c = 0;
104 for ( ; c < columns && p < end; c++, p++) {
105 const unsigned u = *p;
106 str.setFieldWidth(2);
107 str << u;
108 str.setFieldWidth(0);
109 str << ' ';
110 switch (u) {
111 case '\n':
112 asc += QLatin1String("\\n");
113 break;
114 case '\r':
115 asc += QLatin1String("\\r");
116 break;
117 case '\t':
118 asc += QLatin1String("\\t");
119 break;
120 default:
121 if (u >= 32 && u < 128) {
122 asc += QLatin1Char(' ');
123 asc += QLatin1Char(u);
124 } else {
125 asc += QLatin1String(" .");
126 }
127 break;
128 }
129 }
130 if (const int remainder = columns - c)
131 str << QString(3 * remainder, QLatin1Char(' '));
132 str << ' ' << asc << '\n';
133 }
134 return rc;
135}
136
137// ----------- RunControlContext
138RunControlContext::RunControlContext() :
139 flags(0), resumeFlags(0)
140{
141}
142
143void RunControlContext::clear()
144{
145 flags =0;
146 resumeFlags = 0;
147 id.clear();
148 osid.clear();
149 parentId.clear();
150}
151
152RunControlContext::Type RunControlContext::typeFromTcfId(const QByteArray &id)
153{
154 // "p12" or "p12.t34"?
155 return id.contains(".t") ? Thread : Process;
156}
157
158unsigned RunControlContext::processId() const
159{
160 return processIdFromTcdfId(id);
161}
162
163unsigned RunControlContext::threadId() const
164{
165 return threadIdFromTcdfId(id);
166}
167
168unsigned RunControlContext::processIdFromTcdfId(const QByteArray &id)
169{
170 // Cut out process id from "p12" or "p12.t34"?
171 if (!id.startsWith('p'))
172 return 0;
173 const int dotPos = id.indexOf('.');
174 const int pLen = dotPos == -1 ? id.size() : dotPos;
175 return id.mid(1, pLen - 1).toUInt();
176}
177
178unsigned RunControlContext::threadIdFromTcdfId(const QByteArray &id)
179{
180 const int tPos = id.indexOf(".t");
181 return tPos != -1 ? id.mid(tPos + 2).toUInt() : uint(0);
182}
183
184QByteArray RunControlContext::tcfId(unsigned processId, unsigned threadId /* = 0 */)
185{
186 QByteArray rc("p");
187 rc += QByteArray::number(processId);
188 if (threadId) {
189 rc += ".t";
190 rc += QByteArray::number(threadId);
191 }
192 return rc;
193}
194
195RunControlContext::Type RunControlContext::type() const
196{
197 return RunControlContext::typeFromTcfId(id);
198}
199
200bool RunControlContext::parse(const JsonValue &val)
201{
202 clear();
203 if (val.type() != JsonValue::Object)
204 return false;
205 foreach(const JsonValue &c, val.children()) {
206 if (c.name() == "ID") {
207 id = c.data();
208 } else if (c.name() == "OSID") {
209 osid = c.data();
210 } else if (c.name() == "ParentID") {
211 parentId = c.data();
212 } else if (c.name() == "IsContainer") {
213 if (jsonToBool(c))
214 flags |= Container;
215 } else if (c.name() == "CanTerminate") {
216 if (jsonToBool(c))
217 flags |= CanTerminate;
218 } else if (c.name() == "CanResume") {
219 resumeFlags = c.data().toUInt();
220 } else if (c.name() == "HasState") {
221 if (jsonToBool(c))
222 flags |= HasState;
223 } else if (c.name() == "CanSuspend") {
224 if (jsonToBool(c))
225 flags |= CanSuspend;
226 }
227 }
228 return true;
229}
230
231QString RunControlContext::toString() const
232{
233 QString rc;
234 QTextStream str(&rc);
235 format(str);
236 return rc;
237}
238
239void RunControlContext::format(QTextStream &str) const
240{
241 str << " id='" << id << "' osid='" << osid
242 << "' parentId='" << parentId <<"' ";
243 if (flags & Container)
244 str << "[container] ";
245 if (flags & HasState)
246 str << "[has state] ";
247 if (flags & CanSuspend)
248 str << "[can suspend] ";
249 if (flags & CanSuspend)
250 str << "[can terminate] ";
251 str.setIntegerBase(16);
252 str << " resume_flags: 0x" << resumeFlags;
253 str.setIntegerBase(10);
254}
255
256// ------ ModuleLoadEventInfo
257ModuleLoadEventInfo::ModuleLoadEventInfo() :
258 loaded(false), codeAddress(0), dataAddress(0), requireResume(false)
259{
260}
261
262void ModuleLoadEventInfo::clear()
263{
264 loaded = requireResume = false;
265 codeAddress = dataAddress =0;
266}
267
268bool ModuleLoadEventInfo::parse(const JsonValue &val)
269{
270 clear();
271 if (val.type() != JsonValue::Object)
272 return false;
273 foreach(const JsonValue &c, val.children()) {
274 if (c.name() == "Name") {
275 name = c.data();
276 } else if (c.name() == "File") {
277 file = c.data();
278 } else if (c.name() == "CodeAddress") {
279 codeAddress = c.data().toULongLong();
280 } else if (c.name() == "DataAddress") {
281 dataAddress = c.data().toULongLong();
282 } else if (c.name() == "Loaded") {
283 loaded = jsonToBool(c);
284 } else if (c.name() == "RequireResume") {
285 requireResume =jsonToBool(c);
286 }
287 }
288 return true;
289}
290void ModuleLoadEventInfo::format(QTextStream &str) const
291{
292 str << "name='" << name << "' file='" << file << "' " <<
293 (loaded ? "[loaded] " : "[not loaded] ");
294 if (requireResume)
295 str << "[requires resume] ";
296 str.setIntegerBase(16);
297 str << " code: 0x" << codeAddress << " data: 0x" << dataAddress;
298 str.setIntegerBase(10);
299}
300
301// ---------------------- Breakpoint
302
303// Types matching enum
304static const char *breakPointTypesC[] = {"Software", "Hardware", "Auto"};
305
306Breakpoint::Breakpoint(quint64 loc) :
307 type(Auto), enabled(true), ignoreCount(0), location(loc), size(1), thumb(true)
308{
309 if (loc)
310 id = idFromLocation(location);
311}
312
313void Breakpoint::setContextId(unsigned processId, unsigned threadId)
314{
315 contextIds = QVector<QByteArray>(1, RunControlContext::tcfId(processId, threadId));
316}
317
318QByteArray Breakpoint::idFromLocation(quint64 loc)
319{
320 return QByteArray("BP_0x") + QByteArray::number(loc, 16);
321}
322
323QString Breakpoint::toString() const
324{
325 QString rc;
326 QTextStream str(&rc);
327 str.setIntegerBase(16);
328 str << "Breakpoint '" << id << "' " << breakPointTypesC[type] << " for contexts '"
329 << joinByteArrays(contextIds, ',') << "' at 0x" << location;
330 str.setIntegerBase(10);
331 str << " size " << size;
332 if (enabled)
333 str << " [enabled]";
334 if (thumb)
335 str << " [thumb]";
336 if (ignoreCount)
337 str << " IgnoreCount " << ignoreCount;
338 return rc;
339}
340
341JsonInputStream &operator<<(JsonInputStream &str, const Breakpoint &b)
342{
343 if (b.contextIds.isEmpty())
344 qWarning("tcftrk::Breakpoint: No context ids specified");
345
346 str << '{' << "ID" << ':' << QString::fromUtf8(b.id) << ','
347 << "BreakpointType" << ':' << breakPointTypesC[b.type] << ','
348 << "Enabled" << ':' << b.enabled << ','
349 << "IgnoreCount" << ':' << b.ignoreCount << ','
350 << "ContextIds" << ':' << b.contextIds << ','
351 << "Location" << ':' << QString::number(b.location) << ','
352 << "Size" << ':' << b.size << ','
353 << "THUMB_BREAKPOINT" << ':' << b.thumb
354 << '}';
355 return str;
356}
357
358// --- Events
359TcfTrkEvent::TcfTrkEvent(Type type) : m_type(type)
360{
361}
362
363TcfTrkEvent::~TcfTrkEvent()
364{
365}
366
367TcfTrkEvent::Type TcfTrkEvent::type() const
368{
369 return m_type;
370}
371
372QString TcfTrkEvent::toString() const
373{
374 return QString();
375}
376
377static const char sharedLibrarySuspendReasonC[] = "Shared Library";
378
379TcfTrkEvent *TcfTrkEvent::parseEvent(Services s, const QByteArray &nameBA, const QVector<JsonValue> &values)
380{
381 switch (s) {
382 case LocatorService:
383 if (nameBA == "Hello" && values.size() == 1 && values.front().type() == JsonValue::Array) {
384 QStringList services;
385 foreach (const JsonValue &jv, values.front().children())
386 services.push_back(QString::fromUtf8(jv.data()));
387 return new TcfTrkLocatorHelloEvent(services);
388 }
389 break;
390 case RunControlService:
391 if (values.empty())
392 return 0;
393 // "id/PC/Reason/Data"
394 if (nameBA == "contextSuspended" && values.size() == 4) {
395 const QByteArray idBA = values.at(0).data();
396 const quint64 pc = values.at(1).data().toULongLong();
397 const QByteArray reasonBA = values.at(2).data();
398 // Module load: Special
399 if (reasonBA == sharedLibrarySuspendReasonC) {
400 ModuleLoadEventInfo info;
401 if (!info.parse(values.at(3)))
402 return 0;
403 return new TcfTrkRunControlModuleLoadContextSuspendedEvent(idBA, reasonBA, pc, info);
404 }
405 return new TcfTrkRunControlContextSuspendedEvent(idBA, reasonBA, pc);
406 } // "contextSuspended"
407 if (nameBA == "contextAdded")
408 return TcfTrkRunControlContextAddedEvent::parseEvent(values);
409 if (nameBA == "contextRemoved" && values.front().type() == JsonValue::Array) {
410 QVector<QByteArray> ids;
411 foreach(const JsonValue &c, values.front().children())
412 ids.push_back(c.data());
413 return new TcfTrkRunControlContextRemovedEvent(ids);
414 }
415 break;
416 default:
417 break;
418 }
419 return 0;
420}
421
422// -------------- TcfTrkServiceHelloEvent
423TcfTrkLocatorHelloEvent::TcfTrkLocatorHelloEvent(const QStringList &s) :
424 TcfTrkEvent(LocatorHello),
425 m_services(s)
426{
427}
428
429QString TcfTrkLocatorHelloEvent::toString() const
430{
431 return QLatin1String("ServiceHello: ") + m_services.join(QLatin1String(", "));
432}
433
434// -------------- TcfTrkIdEvent
435TcfTrkIdEvent::TcfTrkIdEvent(Type t, const QByteArray &id) :
436 TcfTrkEvent(t), m_id(id)
437{
438}
439
440// ---------- TcfTrkIdsEvent
441TcfTrkIdsEvent::TcfTrkIdsEvent(Type t, const QVector<QByteArray> &ids) :
442 TcfTrkEvent(t), m_ids(ids)
443{
444}
445
446QString TcfTrkIdsEvent::joinedIdString(const char sep) const
447{
448 return joinByteArrays(m_ids, sep);
449}
450
451// ---------------- TcfTrkRunControlContextAddedEvent
452TcfTrkRunControlContextAddedEvent::TcfTrkRunControlContextAddedEvent(const RunControlContexts &c) :
453 TcfTrkEvent(RunControlContextAdded), m_contexts(c)
454{
455}
456
457TcfTrkRunControlContextAddedEvent
458 *TcfTrkRunControlContextAddedEvent::parseEvent(const QVector<JsonValue> &values)
459{
460 // Parse array of contexts
461 if (values.size() < 1 || values.front().type() != JsonValue::Array)
462 return 0;
463
464 RunControlContexts contexts;
465 foreach (const JsonValue &v, values.front().children()) {
466 RunControlContext context;
467 if (context.parse(v))
468 contexts.push_back(context);
469 }
470 return new TcfTrkRunControlContextAddedEvent(contexts);
471}
472
473QString TcfTrkRunControlContextAddedEvent::toString() const
474{
475 QString rc;
476 QTextStream str(&rc);
477 str << "RunControl: " << m_contexts.size() << " context(s) "
478 << (type() == RunControlContextAdded ? "added" : "removed")
479 << '\n';
480 foreach (const RunControlContext &c, m_contexts) {
481 c.format(str);
482 str << '\n';
483 }
484 return rc;
485}
486
487// --------------- TcfTrkRunControlContextRemovedEvent
488TcfTrkRunControlContextRemovedEvent::TcfTrkRunControlContextRemovedEvent(const QVector<QByteArray> &ids) :
489 TcfTrkIdsEvent(RunControlContextRemoved, ids)
490{
491}
492
493QString TcfTrkRunControlContextRemovedEvent::toString() const
494{
495 return QLatin1String("RunControl: Removed contexts '") + joinedIdString() + ("'.");
496}
497
498// --------------- TcfTrkRunControlContextSuspendedEvent
499TcfTrkRunControlContextSuspendedEvent::TcfTrkRunControlContextSuspendedEvent(const QByteArray &id,
500 const QByteArray &reason,
501 quint64 pc) :
502 TcfTrkIdEvent(RunControlSuspended, id), m_pc(pc), m_reason(reason)
503{
504}
505
506TcfTrkRunControlContextSuspendedEvent::TcfTrkRunControlContextSuspendedEvent(Type t,
507 const QByteArray &id,
508 const QByteArray &reason,
509 quint64 pc) :
510 TcfTrkIdEvent(t, id), m_pc(pc), m_reason(reason)
511{
512}
513
514void TcfTrkRunControlContextSuspendedEvent::format(QTextStream &str) const
515{
516 str.setIntegerBase(16);
517 str << "RunControl: '" << idString() << "' suspended at 0x"
518 << m_pc << ": '" << m_reason << "'.";
519 str.setIntegerBase(10);
520}
521
522QString TcfTrkRunControlContextSuspendedEvent::toString() const
523{
524 QString rc;
525 QTextStream str(&rc);
526 format(str);
527 return rc;
528}
529
530TcfTrkRunControlContextSuspendedEvent::Reason TcfTrkRunControlContextSuspendedEvent::reason() const
531{
532 if (m_reason == sharedLibrarySuspendReasonC)
533 return ModuleLoad;
534 if (m_reason == "Breakpoint")
535 return BreakPoint;
536 // 'Data abort exception'/'Thread has panicked' ... unfortunately somewhat unspecific.
537 if (m_reason.contains("exception") || m_reason.contains("panick"))
538 return Crash;
539 return Other;
540}
541
542TcfTrkRunControlModuleLoadContextSuspendedEvent::TcfTrkRunControlModuleLoadContextSuspendedEvent(const QByteArray &id,
543 const QByteArray &reason,
544 quint64 pc,
545 const ModuleLoadEventInfo &mi) :
546 TcfTrkRunControlContextSuspendedEvent(RunControlModuleLoadSuspended, id, reason, pc),
547 m_mi(mi)
548{
549}
550
551QString TcfTrkRunControlModuleLoadContextSuspendedEvent::toString() const
552{
553 QString rc;
554 QTextStream str(&rc);
555 TcfTrkRunControlContextSuspendedEvent::format(str);
556 str << ' ';
557 m_mi.format(str);
558 return rc;
559}
560
561
562} // namespace tcftrk
Note: See TracBrowser for help on using the repository browser.