From f34fd810d5a1f48c935e459e42e273f0e6102558 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Wed, 11 Aug 2010 15:46:55 +0200 Subject: [PATCH] Debugger[TCF TRK]: Adapt to TCF TRK 4.0.5 - Parse/Format errors correctly (long codes) - Use standard 'Registers' service, fake 'getm' as long as it is unimplemented - Use 'Registers|getChildren' for each thread to activate the context and use the names obtained from there instead of hardcoded register names --- src/plugins/debugger/gdb/symbian.cpp | 20 +- src/plugins/debugger/gdb/symbian.h | 1 + src/plugins/debugger/gdb/tcftrkgdbadapter.cpp | 126 ++++++++--- src/plugins/debugger/gdb/tcftrkgdbadapter.h | 2 + src/shared/symbianutils/tcftrkdevice.cpp | 198 +++++++++++++++--- src/shared/symbianutils/tcftrkdevice.h | 41 +++- src/shared/symbianutils/tcftrkmessage.cpp | 2 +- src/shared/symbianutils/tcftrkmessage.h | 1 - 8 files changed, 317 insertions(+), 74 deletions(-) diff --git a/src/plugins/debugger/gdb/symbian.cpp b/src/plugins/debugger/gdb/symbian.cpp index 46ad97537c1..34e87921753 100644 --- a/src/plugins/debugger/gdb/symbian.cpp +++ b/src/plugins/debugger/gdb/symbian.cpp @@ -147,17 +147,23 @@ QByteArray Thread::gdbReportRegisters() const return ba; } +QByteArray Thread::registerContentsLogMessage() const +{ + QByteArray logMsg; + for (int i = 0; i < RegisterCount; ++i) { + logMsg += dumpRegister(i, registers[i]); + logMsg += ' '; + } + return logMsg; +} + QByteArray Thread::gdbRegisterLogMessage(bool verbose) const { - QByteArray logMsg = "REGISTER CONTENTS: (Thread 0x"; + QByteArray logMsg = "Register contents: (Thread 0x"; logMsg += QByteArray::number(id, 16); logMsg += " ) "; - if (verbose) { - for (int i = 0; i < RegisterCount; ++i) { - logMsg += dumpRegister(i, registers[i]); - logMsg += ' '; - } - } + if (verbose) + logMsg += registerContentsLogMessage(); return logMsg; } diff --git a/src/plugins/debugger/gdb/symbian.h b/src/plugins/debugger/gdb/symbian.h index 74f0aaeba8e..30012183c53 100644 --- a/src/plugins/debugger/gdb/symbian.h +++ b/src/plugins/debugger/gdb/symbian.h @@ -110,6 +110,7 @@ struct Thread { void resetRegisters(); // Gdb helpers for reporting values QByteArray gdbReportRegisters() const; + QByteArray registerContentsLogMessage() const; QByteArray gdbRegisterLogMessage(bool verbose) const; QByteArray gdbReportSingleRegister(unsigned i) const; QByteArray gdbSingleRegisterLogMessage(unsigned i) const; diff --git a/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp b/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp index 16af8f82a23..5ed26239d28 100644 --- a/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp @@ -62,14 +62,6 @@ enum { debug = 0 }; -// Register names used by the 'SimpleRegister' service -static const char *tcfTrkSimpleRegisterNamesC[] = -{"R0", "R1", "R2", "R3", - "R4", "R5", "R6", "R7", - "R8", "R9", "R10", "R11", - "R12", "SP", "LR", "PC", - "CPSR"}; - namespace Debugger { namespace Internal { @@ -138,14 +130,6 @@ TcfTrkGdbAdapter::TcfTrkGdbAdapter(GdbEngine *engine) : this, SLOT(trkLogMessage(QString))); connect(m_trkDevice, SIGNAL(tcfEvent(tcftrk::TcfTrkEvent)), this, SLOT(tcftrkEvent(tcftrk::TcfTrkEvent))); - - // Set register mappings - const int registerCount = sizeof(tcfTrkSimpleRegisterNamesC)/sizeof(const char*); - QVector<QByteArray> registerNames; - registerNames.reserve(registerCount); - for (int i = 0; i < registerCount; i++) - registerNames.push_back(QByteArray(tcfTrkSimpleRegisterNamesC[i])); - m_trkDevice->setRegisterNames(registerNames); } TcfTrkGdbAdapter::~TcfTrkGdbAdapter() @@ -282,8 +266,7 @@ void TcfTrkGdbAdapter::tcftrkEvent(const TcfTrkEvent &e) static_cast<const TcfTrkRunControlModuleLoadContextSuspendedEvent &>(e)); break; case TcfTrkEvent::RunControlContextAdded: // Thread/process added - foreach(const RunControlContext &rc, - static_cast<const TcfTrkRunControlContextAddedEvent &>(e).contexts()) + foreach(const RunControlContext &rc, static_cast<const TcfTrkRunControlContextAddedEvent &>(e).contexts()) if (rc.type() == RunControlContext::Thread) addThread(rc.threadId()); break; @@ -693,9 +676,11 @@ void TcfTrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) // FIXME: Assume all goes well. m_snapshot.setRegisterValue(m_session.tid, regnumValue.first, regnumValue.second); logMessage(_("Setting register #%1 to 0x%2").arg(regnumValue.first).arg(regnumValue.second, 0, 16)); + QByteArray registerValue; + trk::appendInt(®isterValue, trk::BigEndian); // Registers are big endian m_trkDevice->sendRegistersSetCommand( TcfTrkCallback(this, &TcfTrkGdbAdapter::handleWriteRegister), - currentThreadContextId(), regnumValue.first, regnumValue.second, + currentThreadContextId(), regnumValue.first, registerValue, QVariant(regnumValue.first)); // Note that App TRK refuses to write registers 13 and 14 } @@ -1016,6 +1001,11 @@ void TcfTrkGdbAdapter::addThread(unsigned id) if (m_session.mainTid == 0) m_session.mainTid = id; } + // We cannot retrieve register values unless the registers of that + // thread have been retrieved (TCF TRK oddity). + const QByteArray contextId = tcftrk::RunControlContext::tcfId(m_session.pid, id); + m_trkDevice->sendRegistersGetChildrenCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleRegisterChildren), + contextId, QVariant(contextId)); } } @@ -1149,9 +1139,48 @@ void TcfTrkGdbAdapter::reportRegisters() sendGdbServerMessage(thread.gdbReportRegisters(), thread.gdbRegisterLogMessage(m_verbose)); } +void TcfTrkGdbAdapter::handleRegisterChildren(const tcftrk::TcfTrkCommandResult &result) +{ + const QByteArray contextId = result.cookie.toByteArray(); + if (!result) { + logMessage("Error retrieving register children of " + contextId + ": " + result.errorString(), LogError); + return; + } + // Parse out registers. + // If this is a single 'pid.tid.rGPR' parent entry, recurse to get the actual registers, + // ('pid.tid.rGPR.R0'..). At least 'pid.tid.rGPR' must have been retrieved to be + // able to access the register contents. + QVector<QByteArray> registerNames = tcftrk::TcfTrkDevice::parseRegisterGetChildren(result); + if (registerNames.size() == 1) { + m_trkDevice->sendRegistersGetChildrenCommand(TcfTrkCallback(this, &TcfTrkGdbAdapter::handleRegisterChildren), + registerNames.front(), result.cookie); + return; + } + // First thread: Set base names in device. + if (!m_trkDevice->registerNames().isEmpty()) + return; + // Make sure we get all registers + const int registerCount = registerNames.size(); + if (registerCount != Symbian::RegisterCount) { + logMessage(QString::fromLatin1("Invalid number of registers received, expected %1, got %2"). + arg(Symbian::RegisterCount).arg(registerCount), LogError); + return; + } + // Set up register names (strip thread context "pid.tid"+'.') + QString msg = QString::fromLatin1("Retrieved %1 register names: ").arg(registerCount); + const int contextLength = contextId.size() + 1; + for (int i = 0; i < registerCount; i++) { + registerNames[i].remove(0, contextLength); + if (i) + msg += QLatin1Char(','); + msg += QString::fromAscii(registerNames[i]); + } + logMessage(msg); + m_trkDevice->setRegisterNames(registerNames); +} + void TcfTrkGdbAdapter::handleReadRegisters(const TcfTrkCommandResult &result) { - logMessage(" REGISTER RESULT: " + result.toString()); if (!result) { logMessage("ERROR: " + result.errorString(), LogError); return; @@ -1163,8 +1192,10 @@ void TcfTrkGdbAdapter::handleReadRegisters(const TcfTrkCommandResult &result) unsigned i = result.cookie.toUInt(); uint *registers = m_snapshot.registers(m_session.tid); QTC_ASSERT(registers, return;) - foreach (const JsonValue &jr, result.values.front().children()) - registers[i++] = jr.data().toUInt(0, 16); + foreach (const JsonValue &jr, result.values.front().children()) { + QByteArray bigEndianRaw = QByteArray::fromBase64(jr.data()); + registers[i++] = trk::extractInt(bigEndianRaw); + } m_snapshot.setRegistersValid(m_session.tid, true); if (debug) qDebug() << "handleReadRegisters: " << m_snapshot.toString(); @@ -1187,13 +1218,33 @@ void TcfTrkGdbAdapter::handleAndReportReadRegister(const TcfTrkCommandResult &re thread.gdbSingleRegisterLogMessage(registerNumber)); } +QByteArray TcfTrkGdbAdapter::stopMessage() const +{ + QByteArray logMsg = "Stopped with registers in thread 0x"; + logMsg += QByteArray::number(m_session.tid, 16); + if (m_session.tid == m_session.mainTid) + logMsg += " [main]"; + const int idx = m_snapshot.indexOfThread(m_session.tid); + if (idx == -1) + return logMsg; + const Symbian::Thread &thread = m_snapshot.threadInfo.at(idx); + logMsg += ", at 0x"; + logMsg += QByteArray::number(thread.registers[Symbian::RegisterPC], 16); + logMsg += ", (loaded at 0x"; + logMsg += QByteArray::number(m_session.codeseg, 16); + logMsg += ", offset 0x"; + logMsg += QByteArray::number(thread.registers[Symbian::RegisterPC] - m_session.codeseg, 16); + logMsg += "), Register contents: "; + logMsg += thread.registerContentsLogMessage(); + return logMsg; +} + void TcfTrkGdbAdapter::handleAndReportReadRegistersAfterStop(const TcfTrkCommandResult &result) { handleReadRegisters(result); handleReadRegisters(result); const bool reportThread = m_session.tid != m_session.mainTid; - sendGdbServerMessage(m_snapshot.gdbStopMessage(m_session.tid, reportThread), - "Stopped with registers in thread " + QByteArray::number(m_session.tid, 16)); + sendGdbServerMessage(m_snapshot.gdbStopMessage(m_session.tid, reportThread), stopMessage()); } void TcfTrkGdbAdapter::handleAndReportSetBreakpoint(const TcfTrkCommandResult &result) @@ -1249,13 +1300,20 @@ void TcfTrkGdbAdapter::handleReadMemoryBuffered(const TcfTrkCommandResult &resul const QByteArray memory = TcfTrkDevice::parseMemoryGet(result); const MemoryRange range = result.cookie.value<MemoryRange>(); - if (unsigned(memory.size()) != range.size()) { - logMessage(_("TEMPORARY: ") + msgMemoryReadError(range.from, range.size())); - logMessage(_("RETRYING UNBUFFERED")); + const bool error = !result; + const bool insufficient = unsigned(memory.size()) != range.size(); + if (error || insufficient) { + QString msg = error ? + QString::fromLatin1("Error reading memory: %1").arg(result.errorString()) : + QString::fromLatin1("Error reading memory (got %1 of %2): %3"). + arg(memory.size()).arg(range.size()).arg(msgMemoryReadError(range.from, range.size())); + msg += QString::fromLatin1("\n(Retrying unbuffered...)"); + logMessage(msg, LogError); // FIXME: This does not handle large requests properly. sendMemoryGetCommand(range, false); return; } + m_snapshot.insertMemory(range, memory); tryAnswerGdbMemoryRequest(true); } @@ -1267,11 +1325,15 @@ void TcfTrkGdbAdapter::handleReadMemoryUnbuffered(const TcfTrkCommandResult &res const QByteArray memory = TcfTrkDevice::parseMemoryGet(result); const MemoryRange range = result.cookie.value<MemoryRange>(); - if (unsigned(memory.size()) != range.size()) { - logMessage(_("TEMPORARY: ") + msgMemoryReadError(range.from, range.size())); - logMessage(_("RETRYING UNBUFFERED")); - const QByteArray ba = "E20"; - sendGdbServerMessage(ba, msgMemoryReadError(32, range.from).toLatin1()); + const bool error = !result; + const bool insufficient = unsigned(memory.size()) != range.size(); + if (error || insufficient) { + QString msg = error ? + QString::fromLatin1("Error reading memory: %1").arg(result.errorString()) : + QString::fromLatin1("Error reading memory (got %1 of %2): %3"). + arg(memory.size()).arg(range.size()).arg(msgMemoryReadError(range.from, range.size())); + logMessage(msg, LogError); + sendGdbServerMessage(QByteArray("E20"), msgMemoryReadError(32, range.from).toLatin1()); return; } m_snapshot.insertMemory(range, memory); diff --git a/src/plugins/debugger/gdb/tcftrkgdbadapter.h b/src/plugins/debugger/gdb/tcftrkgdbadapter.h index 675faadfc0a..4dc9020c428 100644 --- a/src/plugins/debugger/gdb/tcftrkgdbadapter.h +++ b/src/plugins/debugger/gdb/tcftrkgdbadapter.h @@ -112,9 +112,11 @@ private: void handleWriteRegister(const tcftrk::TcfTrkCommandResult &result); void reportRegisters(); void handleReadRegisters(const tcftrk::TcfTrkCommandResult &result); + void handleRegisterChildren(const tcftrk::TcfTrkCommandResult &result); void handleAndReportReadRegisters(const tcftrk::TcfTrkCommandResult &result); void handleAndReportReadRegister(const tcftrk::TcfTrkCommandResult &result); void handleAndReportReadRegistersAfterStop(const tcftrk::TcfTrkCommandResult &result); + QByteArray stopMessage() const; void handleAndReportSetBreakpoint(const tcftrk::TcfTrkCommandResult &result); void handleClearBreakpoint(const tcftrk::TcfTrkCommandResult &result); void readMemory(uint addr, uint len, bool buffered); diff --git a/src/shared/symbianutils/tcftrkdevice.cpp b/src/shared/symbianutils/tcftrkdevice.cpp index c77c12091e1..eb97691f728 100644 --- a/src/shared/symbianutils/tcftrkdevice.cpp +++ b/src/shared/symbianutils/tcftrkdevice.cpp @@ -90,24 +90,25 @@ bool TcfTrkCommandError::isError() const bool TcfTrkCommandError::parse(const QVector<JsonValue> &values) { // Parse an arbitrary hash (that could as well be a command response) - // and check for error elements. + // and check for error elements. It looks like sometimes errors are appended + // to other values. unsigned errorKeyCount = 0; clear(); do { - if (values.isEmpty() || values.front().type() != JsonValue::Object) + if (values.isEmpty() || values.back().type() != JsonValue::Object) break; - foreach (const JsonValue &c, values.front().children()) { + foreach (const JsonValue &c, values.back().children()) { if (c.name() == "Time") { timeMS = c.data().toULongLong(); errorKeyCount++; } else if (c.name() == "Code") { - code = c.data().toInt(); + code = c.data().toLongLong(); errorKeyCount++; } else if (c.name() == "Format") { format = c.data(); errorKeyCount++; } else if (c.name() == "AltCode") { - alternativeCode = c.data().toInt(); + alternativeCode = c.data().toULongLong(); errorKeyCount++; } else if (c.name() == "AltOrg") { alternativeOrganization = c.data(); @@ -121,7 +122,7 @@ bool TcfTrkCommandError::parse(const QVector<JsonValue> &values) if (debug) { qDebug("TcfTrkCommandError::parse: Found error %d (%u): ", errorFound, errorKeyCount); if (!values.isEmpty()) - qDebug() << values.front().toString(); + qDebug() << values.back().toString(); } return errorFound; } @@ -166,6 +167,7 @@ QString TcfTrkCommandResult::errorString() const return rc; case FailReply: str << "NAK"; + return rc; case CommandErrorReply: commandError.write(str); break; @@ -211,6 +213,11 @@ QString TcfTrkCommandResult::toString() const return rc; } +// Entry for send queue. +enum SpecialHandlingFlags { None =0, + FakeRegisterGetMIntermediate = 0x1, + FakeRegisterGetMFinal = 0x2 }; + struct TcfTrkSendQueueEntry { typedef TcfTrkDevice::MessageType MessageType; @@ -218,10 +225,12 @@ struct TcfTrkSendQueueEntry explicit TcfTrkSendQueueEntry(MessageType mt, int tok, Services s, - const QByteArray &d, - const TcfTrkCallback &cb= TcfTrkCallback(), - const QVariant &ck = QVariant()) : - messageType(mt), service(s), data(d), token(tok), cookie(ck), callback(cb) {} + const QByteArray &d, + const TcfTrkCallback &cb= TcfTrkCallback(), + const QVariant &ck = QVariant(), + unsigned sh = 0) : + messageType(mt), service(s), data(d), token(tok), cookie(ck), callback(cb), + specialHandling(sh) {} MessageType messageType; Services service; @@ -229,6 +238,7 @@ struct TcfTrkSendQueueEntry int token; QVariant cookie; TcfTrkCallback callback; + unsigned specialHandling; }; struct TcfTrkDevicePrivate { @@ -246,6 +256,7 @@ struct TcfTrkDevicePrivate { QQueue<TcfTrkSendQueueEntry> m_sendQueue; TokenWrittenMessageMap m_writtenMessages; QVector<QByteArray> m_registerNames; + QVector<QByteArray> m_fakeGetMRegisterValues; }; TcfTrkDevicePrivate::TcfTrkDevicePrivate() : @@ -454,7 +465,8 @@ int TcfTrkDevice::parseTcfCommandReply(char type, const QVector<QByteArray> &tok return 236; } // No callback: remove entry from map, happy - if (!it.value().callback) { + const unsigned specialHandling = it.value().specialHandling; + if (!it.value().callback && specialHandling == 0u) { d->m_writtenMessages.erase(it); return 0; } @@ -474,13 +486,53 @@ int TcfTrkDevice::parseTcfCommandReply(char type, const QVector<QByteArray> &tok } } } - // Construct result and invoke callback, remove entry from map. - TcfTrkCallback callback = it.value().callback; TcfTrkCommandResult result(type, it.value().service, it.value().data, values, it.value().cookie); + + // Check special handling + if (specialHandling) { + if (!result) { + qWarning("Error in special handling: %s", qPrintable(result.errorString())); + return -2; + } + // Fake 'Registers:getm': Store single register values in cache + if ((specialHandling & FakeRegisterGetMIntermediate) + || (specialHandling & FakeRegisterGetMFinal)) { + if (result.values.size() == 1) { + const int index = int(specialHandling) >> 16; + if (index >= 0 && index < d->m_fakeGetMRegisterValues.size()) { + const QByteArray base64 = result.values.front().data(); + d->m_fakeGetMRegisterValues[index] = base64; + if (d->m_verbose) { + const QString msg = QString::fromLatin1("Caching register value #%1 '%2' 0x%3 (%4)"). + arg(index).arg(QString::fromAscii(d->m_registerNames.at(index))). + arg(QString::fromAscii(QByteArray::fromBase64(base64).toHex())). + arg(QString::fromAscii(base64)); + emitLogMessage(msg); + } + } + } + } + // Fake 'Registers:getm' final value: Reformat entries as array and send off + if (specialHandling & FakeRegisterGetMFinal) { + QByteArray str; + str.append('['); + foreach(const QByteArray &rval, d->m_fakeGetMRegisterValues) + if (!rval.isEmpty()) { + if (str.size() > 1) + str.append(','); + str.append('"'); + str.append(rval); + str.append('"'); + } + str.append(']'); + result.values[0] = JsonValue(str); + } + } + if (it.value().callback) + it.value().callback(result); d->m_writtenMessages.erase(it); - callback(result); return 0; } @@ -559,9 +611,20 @@ bool TcfTrkDevice::checkOpen() } void TcfTrkDevice::sendTcfTrkMessage(MessageType mt, Services service, const char *command, - const char *commandParameters, int commandParametersLength, + const char *commandParameters, // may contain '\0' + int commandParametersLength, const TcfTrkCallback &callBack, const QVariant &cookie) +{ + sendTcfTrkMessage(mt, service, command, commandParameters, commandParametersLength, + callBack, cookie, 0u); +} + +void TcfTrkDevice::sendTcfTrkMessage(MessageType mt, Services service, + const char *command, + const char *commandParameters, int commandParametersLength, + const TcfTrkCallback &callBack, const QVariant &cookie, + unsigned specialHandling) { if (!checkOpen()) @@ -580,7 +643,7 @@ void TcfTrkDevice::sendTcfTrkMessage(MessageType mt, Services service, const cha data.append('\0'); if (commandParametersLength) data.append(commandParameters, commandParametersLength); - const TcfTrkSendQueueEntry entry(mt, token, service, data, callBack, cookie); + const TcfTrkSendQueueEntry entry(mt, token, service, data, callBack, cookie, specialHandling); d->m_sendQueue.enqueue(entry); checkSendQueue(); } @@ -867,7 +930,7 @@ QByteArray TcfTrkDevice::parseMemoryGet(const TcfTrkCommandResult &r) // R.4."TlVMTA==".{"Time":1276786871255,"Code":1,"AltCode":-38,"AltOrg":"POSIX","Format":"BadDescriptor"} // Not sure what to make of it. if (r.values.size() >= 2 && r.values.at(1).type() == JsonValue::Object) - qWarning("Error retrieving memory: %s", r.values.at(1).toString(false).constData()); + qWarning("TcfTrkDevice::parseMemoryGet(): Error retrieving memory: %s", r.values.at(1).toString(false).constData()); // decode const QByteArray memory = QByteArray::fromBase64(memoryV.data()); if (memory.isEmpty()) @@ -877,16 +940,97 @@ QByteArray TcfTrkDevice::parseMemoryGet(const TcfTrkCommandResult &r) return memory; } +// Parse register children (array of names) +QVector<QByteArray> TcfTrkDevice::parseRegisterGetChildren(const TcfTrkCommandResult &r) +{ + QVector<QByteArray> rc; + if (!r || r.values.size() < 1 || r.values.front().type() != JsonValue::Array) + return rc; + const JsonValue &front = r.values.front(); + rc.reserve(front.childCount()); + foreach(const JsonValue &v, front.children()) + rc.push_back(v.data()); + return rc; +} + +void TcfTrkDevice::sendRegistersGetChildrenCommand(const TcfTrkCallback &callBack, + const QByteArray &contextId, + const QVariant &cookie) +{ + QByteArray data; + JsonInputStream str(data); + str << contextId; + sendTcfTrkMessage(MessageWithReply, RegistersService, "getChildren", data, callBack, cookie); +} + +// Format id of register get request (needs contextId containing process and thread) +static inline QByteArray registerId(const QByteArray &contextId, QByteArray id) +{ + QByteArray completeId = contextId; + if (!completeId.isEmpty()) + completeId.append('.'); + completeId.append(id); + return completeId; +} + +// Format parameters of register get request +static inline QByteArray registerGetData(const QByteArray &contextId, QByteArray id) +{ + QByteArray data; + JsonInputStream str(data); + str << registerId(contextId, id); + return data; +} + +void TcfTrkDevice::sendRegistersGetCommand(const TcfTrkCallback &callBack, + const QByteArray &contextId, + QByteArray id, + const QVariant &cookie) +{ + sendTcfTrkMessage(MessageWithReply, RegistersService, "get", + registerGetData(contextId, id), callBack, cookie); +} + void TcfTrkDevice::sendRegistersGetMCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, const QVector<QByteArray> &ids, const QVariant &cookie) { // TODO: use "Registers" (which uses base64-encoded values) +#if 0 // Once 'getm' is supported: + // Manually format the complete register ids as an array QByteArray data; JsonInputStream str(data); - str << contextId << '\0' << ids; - sendTcfTrkMessage(MessageWithReply, SimpleRegistersService, "get", data, callBack, cookie); + str << '['; + const int count = ids.size(); + for (int r = 0; r < count; r++) { + if (r) + str << ','; + str << registerId(contextId, ids.at(r)); + } + str << ']'; + sendTcfTrkMessage(MessageWithReply, RegistersService, "getm", data, callBack, cookie); +#else + // TCF TRK 4.0.5: Fake 'getm' by sending all requests, pass on callback to the last + // @Todo: Hopefully, we get 'getm'? + const int last = ids.size() - 1; + d->m_fakeGetMRegisterValues = QVector<QByteArray>(ids.size(), QByteArray()); + for (int r = 0; r <= last; r++) { + const QByteArray data = registerGetData(contextId, ids.at(r)); + // Determine special flags along with index + unsigned specialFlags = r == last ? FakeRegisterGetMFinal : FakeRegisterGetMIntermediate; + const int index = d->m_registerNames.indexOf(ids.at(r)); + if (index == -1) { // Should not happen + qWarning("Invalid register name %s", ids.at(r).constData()); + return; + } + specialFlags |= unsigned(index) << 16; + sendTcfTrkMessage(MessageWithReply, RegistersService, "get", + data.constData(), data.size(), + r == last ? callBack : TcfTrkCallback(), + cookie, specialFlags); + } +#endif } void TcfTrkDevice::sendRegistersGetMRangeCommand(const TcfTrkCallback &callBack, @@ -909,23 +1053,25 @@ void TcfTrkDevice::sendRegistersGetMRangeCommand(const TcfTrkCallback &callBack, // Set register void TcfTrkDevice::sendRegistersSetCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, - const QByteArray &id, - unsigned value, + QByteArray id, + const QByteArray &value, const QVariant &cookie) { - // TODO: use "Registers" (which uses base64-encoded values) QByteArray data; JsonInputStream str(data); - str << contextId << '\0' << QVector<QByteArray>(1, id) - << '\0' << QVector<QByteArray>(1, QByteArray::number(value, 16)); - sendTcfTrkMessage(MessageWithReply, SimpleRegistersService, "set", data, callBack, cookie); + if (!contextId.isEmpty()) { + id.prepend('.'); + id.prepend(contextId); + } + str << id << '\0' << value.toBase64(); + sendTcfTrkMessage(MessageWithReply, RegistersService, "set", data, callBack, cookie); } // Set register void TcfTrkDevice::sendRegistersSetCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, unsigned registerNumber, - unsigned value, + const QByteArray &value, const QVariant &cookie) { if (registerNumber >= (unsigned)d->m_registerNames.size()) { diff --git a/src/shared/symbianutils/tcftrkdevice.h b/src/shared/symbianutils/tcftrkdevice.h index 6946c975163..1e0f94ce2bc 100644 --- a/src/shared/symbianutils/tcftrkdevice.h +++ b/src/shared/symbianutils/tcftrkdevice.h @@ -70,11 +70,11 @@ struct SYMBIANUTILS_EXPORT TcfTrkCommandError { bool parse(const QVector<JsonValue> &values); quint64 timeMS; // Since 1.1.1970 - int code; + qint64 code; QByteArray format; // message // 'Alternative' meaning, like altOrg="POSIX"/altCode=<some errno> QByteArray alternativeOrganization; - int alternativeCode; + qint64 alternativeCode; }; /* Answer to a Tcf command passed to the callback. */ @@ -112,6 +112,12 @@ http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Specific http://dev.eclipse.org/svnroot/dsdp/org.eclipse.tm.tcf/trunk/docs/TCF%20Services.html * Commands can be sent along with callbacks that are passed a * TcfTrkCommandResult and an opaque QVariant cookie. In addition, events are emitted. + * + * Note: As of 11.8.2010, TCF Trk 4.0.5 does not currently support 'Registers::getm' + * (get multiple registers). So, TcfTrkDevice emulates it by sending a sequence of + * single commands. As soon as 'Registers::getm' is natively supported, all code + * related to 'FakeRegisterGetm' should be removed. The workaround requires that + * the register name is known. */ class SYMBIANUTILS_EXPORT TcfTrkDevice : public QObject @@ -130,7 +136,9 @@ public: unsigned verbose() const; - // Mapping of register names for indices + // Mapping of register names to indices for multi-requests. + // Register names can be retrieved via 'Registers:getChildren' (requires + // context id to be stripped). QVector<QByteArray> registerNames() const; void setRegisterNames(const QVector<QByteArray>& n); @@ -138,6 +146,7 @@ public: IODevicePtr takeDevice(); void setDevice(const IODevicePtr &dp); + // Send with parameters from string (which may contain '\0'). void sendTcfTrkMessage(MessageType mt, Services service, const char *command, const char *commandParameters, int commandParametersLength, @@ -225,7 +234,18 @@ public: quint64 start, const QByteArray& data, const QVariant &cookie = QVariant()); - // Reply is an array of hexvalues + // Get register names (children of context). + // It is possible to recurse from thread id down to single registers. + void sendRegistersGetChildrenCommand(const TcfTrkCallback &callBack, + const QByteArray &contextId, + const QVariant &cookie = QVariant()); + + // Register get + void sendRegistersGetCommand(const TcfTrkCallback &callBack, + const QByteArray &contextId, + QByteArray id, + const QVariant &cookie); + void sendRegistersGetMCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, const QVector<QByteArray> &ids, @@ -240,20 +260,21 @@ public: // Set register void sendRegistersSetCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, - const QByteArray &ids, - unsigned value, + QByteArray ids, + const QByteArray &value, // binary value const QVariant &cookie = QVariant()); // Set register void sendRegistersSetCommand(const TcfTrkCallback &callBack, const QByteArray &contextId, unsigned registerNumber, - unsigned value, + const QByteArray &value, // binary value const QVariant &cookie = QVariant()); void sendLoggingAddListenerCommand(const TcfTrkCallback &callBack, const QVariant &cookie = QVariant()); static QByteArray parseMemoryGet(const TcfTrkCommandResult &r); + static QVector<QByteArray> parseRegisterGetChildren(const TcfTrkCommandResult &r); signals: void genericTcfEvent(int service, const QByteArray &name, const QVector<tcftrk::JsonValue> &value); @@ -278,6 +299,12 @@ private: int parseMessage(const QByteArray &); int parseTcfCommandReply(char type, const QVector<QByteArray> &tokens); int parseTcfEvent(const QVector<QByteArray> &tokens); + // Send with parameters from string (which may contain '\0'). + void sendTcfTrkMessage(MessageType mt, Services service, + const char *command, + const char *commandParameters, int commandParametersLength, + const TcfTrkCallback &callBack, const QVariant &cookie, + unsigned specialHandling); TcfTrkDevicePrivate *d; }; diff --git a/src/shared/symbianutils/tcftrkmessage.cpp b/src/shared/symbianutils/tcftrkmessage.cpp index 4aeb9387113..7b0822af4d7 100644 --- a/src/shared/symbianutils/tcftrkmessage.cpp +++ b/src/shared/symbianutils/tcftrkmessage.cpp @@ -36,7 +36,7 @@ // Names matching the enum static const char *serviceNamesC[] = { "Locator", "RunControl", "Processes", "Memory", "Settings", "Breakpoints", - "Registers", "SimpleRegisters", "Logging", + "Registers", "Logging", "UnknownService"}; namespace tcftrk { diff --git a/src/shared/symbianutils/tcftrkmessage.h b/src/shared/symbianutils/tcftrkmessage.h index 0a1aa06945a..b9e2ac420f7 100644 --- a/src/shared/symbianutils/tcftrkmessage.h +++ b/src/shared/symbianutils/tcftrkmessage.h @@ -52,7 +52,6 @@ enum Services { SettingsService, // non-standard, trk specific BreakpointsService, RegistersService, - SimpleRegistersService, // non-standard, trk specific LoggingService, // non-standard, trk specific UnknownService }; // Note: Check string array 'serviceNamesC' of same size when modifying this. -- GitLab