49 #include <QtCore/QTime> |
49 #include <QtCore/QTime> |
50 |
50 |
51 #define logMessage(s) do { qDebug() << "TRKCLIENT: " << s; } while (0) |
51 #define logMessage(s) do { qDebug() << "TRKCLIENT: " << s; } while (0) |
52 |
52 |
53 namespace trk { |
53 namespace trk { |
|
54 |
|
55 Library::Library() : codeseg(0), dataseg(0), pid(0) |
|
56 { |
|
57 } |
|
58 |
|
59 Library::Library(const TrkResult &result) : codeseg(0), dataseg(0), pid(0) |
|
60 { |
|
61 if (result.data.size() < 20) { |
|
62 qWarning("Invalid trk creation notification received."); |
|
63 return; |
|
64 } |
|
65 |
|
66 const char *data = result.data.constData(); |
|
67 pid = extractInt(data + 2); |
|
68 codeseg = extractInt(data + 10); |
|
69 dataseg = extractInt(data + 14); |
|
70 const uint len = extractShort(data + 18); |
|
71 name = result.data.mid(20, len); |
|
72 } |
54 |
73 |
55 TrkAppVersion::TrkAppVersion() |
74 TrkAppVersion::TrkAppVersion() |
56 { |
75 { |
57 reset(); |
76 reset(); |
58 } |
77 } |
141 fpTypeSizeStr = QCoreApplication::translate("trk::Session", ", float size: %1").arg(fpTypeSize); |
160 fpTypeSizeStr = QCoreApplication::translate("trk::Session", ", float size: %1").arg(fpTypeSize); |
142 msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr); |
161 msg = msg.arg(defaultTypeSizeStr).arg(fpTypeSizeStr); |
143 return msg.arg(formatTrkVersion(trkAppVersion)); |
162 return msg.arg(formatTrkVersion(trkAppVersion)); |
144 } |
163 } |
145 |
164 |
|
165 QByteArray Session::gdbLibraryList() const |
|
166 { |
|
167 const int count = libraries.size(); |
|
168 QByteArray response = "l<library-list>"; |
|
169 for (int i = 0; i != count; ++i) { |
|
170 const trk::Library &lib = libraries.at(i); |
|
171 response += "<library name=\""; |
|
172 response += lib.name; |
|
173 response += "\">"; |
|
174 response += "<section address=\"0x"; |
|
175 response += trk::hexNumber(lib.codeseg); |
|
176 response += "\"/>"; |
|
177 response += "<section address=\"0x"; |
|
178 response += trk::hexNumber(lib.dataseg); |
|
179 response += "\"/>"; |
|
180 response += "<section address=\"0x"; |
|
181 response += trk::hexNumber(lib.dataseg); |
|
182 response += "\"/>"; |
|
183 response += "</library>"; |
|
184 } |
|
185 response += "</library-list>"; |
|
186 return response; |
|
187 } |
|
188 |
|
189 QByteArray Session::gdbQsDllInfo(int start, int count) const |
|
190 { |
|
191 // Happens with gdb 6.4.50.20060226-cvs / CodeSourcery. |
|
192 // Never made it into FSF gdb that got qXfer:libraries:read instead. |
|
193 // http://sourceware.org/ml/gdb/2007-05/msg00038.html |
|
194 // Name=hexname,TextSeg=textaddr[,DataSeg=dataaddr] |
|
195 const int libraryCount = libraries.size(); |
|
196 const int end = count < 0 ? libraryCount : qMin(libraryCount, start + count); |
|
197 QByteArray response(1, end == libraryCount ? 'l' : 'm'); |
|
198 for (int i = start; i < end; ++i) { |
|
199 if (i != start) |
|
200 response += ';'; |
|
201 const Library &lib = libraries.at(i); |
|
202 response += "Name="; |
|
203 response += lib.name.toHex(); |
|
204 response += ",TextSeg="; |
|
205 response += hexNumber(lib.codeseg); |
|
206 response += ",DataSeg="; |
|
207 response += hexNumber(lib.dataseg); |
|
208 } |
|
209 return response; |
|
210 } |
|
211 |
|
212 QString Session::toString() const |
|
213 { |
|
214 QString rc; |
|
215 QTextStream str(&rc); |
|
216 str << "Session: " << deviceDescription(false) << '\n' |
|
217 << "pid: " << pid << "main thread: " << mainTid |
|
218 << " current thread: " << tid << ' '; |
|
219 str.setIntegerBase(16); |
|
220 str << " code: 0x" << codeseg << " data: 0x" << dataseg << '\n'; |
|
221 if (const int libCount = libraries.size()) { |
|
222 str << "Libraries:\n"; |
|
223 for (int i = 0; i < libCount; i++) |
|
224 str << " #" << i << ' ' << libraries.at(i).name |
|
225 << " code: 0x" << libraries.at(i).codeseg |
|
226 << " data: 0x" << libraries.at(i).dataseg << '\n'; |
|
227 } |
|
228 if (const int moduleCount = modules.size()) { |
|
229 str << "Modules:\n"; |
|
230 for (int i = 0; i < moduleCount; i++) |
|
231 str << " #" << i << ' ' << modules.at(i) << '\n'; |
|
232 } |
|
233 str.setIntegerBase(10); |
|
234 if (!addressToBP.isEmpty()) { |
|
235 typedef QHash<uint, uint>::const_iterator BP_ConstIterator; |
|
236 str << "Breakpoints:\n"; |
|
237 const BP_ConstIterator cend = addressToBP.constEnd(); |
|
238 for (BP_ConstIterator it = addressToBP.constBegin(); it != cend; ++it) { |
|
239 str.setIntegerBase(16); |
|
240 str << " 0x" << it.key(); |
|
241 str.setIntegerBase(10); |
|
242 str << ' ' << it.value() << '\n'; |
|
243 } |
|
244 } |
|
245 |
|
246 return rc; |
|
247 } |
|
248 |
146 // -------------- |
249 // -------------- |
147 |
250 |
148 QByteArray decode7d(const QByteArray &ba) |
251 QByteArray decode7d(const QByteArray &ba) |
149 { |
252 { |
150 QByteArray res; |
253 QByteArray res; |
186 { |
289 { |
187 QString str; |
290 QString str; |
188 QString ascii; |
291 QString ascii; |
189 const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); |
292 const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); |
190 for (int i = 0; i < size; ++i) { |
293 for (int i = 0; i < size; ++i) { |
191 //if (i == 5 || i == ba.size() - 2) |
294 const int c = byte(ba.at(i)); |
192 // str += " "; |
295 str += QString::fromAscii("%1 ").arg(c, 2, 16, QChar('0')); |
193 int c = byte(ba.at(i)); |
296 ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); |
194 str += QString("%1 ").arg(c, 2, 16, QChar('0')); |
|
195 if (i >= 8 && i < ba.size() - 2) |
|
196 ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); |
|
197 } |
297 } |
198 if (size != ba.size()) { |
298 if (size != ba.size()) { |
199 str += "..."; |
299 str += QLatin1String("..."); |
200 ascii += "..."; |
300 ascii += QLatin1String("..."); |
201 } |
301 } |
202 return str + " " + ascii; |
302 return str + QLatin1String(" ") + ascii; |
203 } |
303 } |
204 |
304 |
205 SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) |
305 SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) |
206 { |
306 { |
207 QByteArray ba = QByteArray::number(n, 16); |
307 QByteArray ba = QByteArray::number(n, 16); |
297 } |
397 } |
298 // Some ASCII log message up to first delimiter or all |
398 // Some ASCII log message up to first delimiter or all |
299 return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); |
399 return firstDelimiterPos != -1 ? firstDelimiterPos : buffer.size(); |
300 } |
400 } |
301 |
401 |
302 bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, QByteArray *rawData) |
402 bool extractResult(QByteArray *buffer, bool serialFrame, TrkResult *result, bool &linkEstablishmentMode, QByteArray *rawData) |
303 { |
403 { |
304 result->clear(); |
404 result->clear(); |
305 if(rawData) |
405 if(rawData) |
306 rawData->clear(); |
406 rawData->clear(); |
307 const ushort len = isValidTrkResult(*buffer, serialFrame, result->multiplex); |
407 ushort len = isValidTrkResult(*buffer, serialFrame, result->multiplex); |
|
408 // handle receiving application output, which is not a regular command |
|
409 const int delimiterPos = serialFrame ? 4 : 0; |
|
410 if (linkEstablishmentMode) { |
|
411 //when "hot connecting" a device, we can receive partial frames. |
|
412 //this code resyncs by discarding data until a TRK frame is found |
|
413 while (buffer->length() > delimiterPos |
|
414 && result->multiplex != MuxTextTrace |
|
415 && !(result->multiplex == MuxTrk && buffer->at(delimiterPos) == 0x7e)) { |
|
416 buffer->remove(0,1); |
|
417 len = isValidTrkResult(*buffer, serialFrame, result->multiplex); |
|
418 } |
|
419 } |
308 if (!len) |
420 if (!len) |
309 return false; |
421 return false; |
310 // handle receiving application output, which is not a regular command |
|
311 const int delimiterPos = serialFrame ? 4 : 0; |
|
312 if (buffer->at(delimiterPos) != 0x7e) { |
422 if (buffer->at(delimiterPos) != 0x7e) { |
313 result->isDebugOutput = true; |
423 result->isDebugOutput = true; |
314 result->data = buffer->mid(delimiterPos, len); |
424 result->data = buffer->mid(delimiterPos, len); |
315 *buffer->remove(0, delimiterPos + len); |
425 buffer->remove(0, delimiterPos + len); |
316 return true; |
426 return true; |
317 } |
427 } |
318 // FIXME: what happens if the length contains 0xfe? |
428 // FIXME: what happens if the length contains 0xfe? |
319 // Assume for now that it passes unencoded! |
429 // Assume for now that it passes unencoded! |
320 const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); |
430 const QByteArray data = decode7d(buffer->mid(delimiterPos + 1, len - 2)); |
321 if(rawData) |
431 if(rawData) |
322 *rawData = data; |
432 *rawData = data; |
323 *buffer->remove(0, delimiterPos + len); |
433 buffer->remove(0, delimiterPos + len); |
324 |
434 |
325 byte sum = 0; |
435 byte sum = 0; |
326 for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum |
436 for (int i = 0; i < data.size(); ++i) // 3 = 2 * 0xfe + sum |
327 sum += byte(data.at(i)); |
437 sum += byte(data.at(i)); |
328 if (sum != 0xff) |
438 if (sum != 0xff) |
333 result->data = data.mid(2, data.size() - 3); |
443 result->data = data.mid(2, data.size() - 3); |
334 //logMessage(" REST BUF: " << stringFromArray(*buffer)); |
444 //logMessage(" REST BUF: " << stringFromArray(*buffer)); |
335 //logMessage(" CURR DATA: " << stringFromArray(data)); |
445 //logMessage(" CURR DATA: " << stringFromArray(data)); |
336 //QByteArray prefix = "READ BUF: "; |
446 //QByteArray prefix = "READ BUF: "; |
337 //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data()); |
447 //logMessage((prefix + "HEADER: " + stringFromArray(header).toLatin1()).data()); |
|
448 linkEstablishmentMode = false; //have received a good TRK packet, therefore in sync |
338 return true; |
449 return true; |
339 } |
450 } |
340 |
451 |
341 SYMBIANUTILS_EXPORT ushort extractShort(const char *data) |
452 SYMBIANUTILS_EXPORT ushort extractShort(const char *data) |
342 { |
453 { |