diff --git a/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp b/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp index fd2208e14b46392c8dce259b5e3af9332850e8fd..e5bfb3f3365c7f6ed44f2fe49e5fefbefe0f7508 100644 --- a/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/tcftrkgdbadapter.cpp @@ -200,6 +200,7 @@ void TcfTrkGdbAdapter::handleTcfTrkRunControlModuleLoadContextSuspendedEvent(con library.name = minfo.name; library.codeseg = minfo.codeAddress; library.dataseg = minfo.dataAddress; + library.pid = tcftrk::RunControlContext::processIdFromTcdfId(se.id()); m_session.libraries.push_back(library); } else { const int index = m_session.modules.indexOf(moduleName); diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp index 26b6ceb69f7413aebfa948c389e102f2d4b94793..350403adbe3433490125cf05e5422836f86996ec 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.cpp +++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp @@ -164,18 +164,7 @@ QByteArray TrkGdbAdapter::trkContinueMessage(uint threadId) return ba; } -QByteArray TrkGdbAdapter::trkReadRegistersMessage() -{ - QByteArray ba; - appendByte(&ba, 0); // Register set, only 0 supported - appendShort(&ba, 0); - appendShort(&ba, RegisterCount - 1); // last register - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - return ba; -} - - QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value) +QByteArray TrkGdbAdapter::trkWriteRegisterMessage(trk::byte reg, uint value) { QByteArray ba; appendByte(&ba, 0); // ? @@ -187,21 +176,9 @@ QByteArray TrkGdbAdapter::trkReadRegistersMessage() return ba; } -QByteArray TrkGdbAdapter::trkReadMemoryMessage(uint from, uint len) -{ - QByteArray ba; - ba.reserve(11); - appendByte(&ba, 0x08); // Options, FIXME: why? - appendShort(&ba, len); - appendInt(&ba, from); - appendInt(&ba, m_session.pid); - appendInt(&ba, m_session.tid); - return ba; -} - QByteArray TrkGdbAdapter::trkReadMemoryMessage(const MemoryRange &range) { - return trkReadMemoryMessage(range.from, range.size()); + return trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, range.from, range.size()); } QByteArray TrkGdbAdapter::trkWriteMemoryMessage(uint addr, const QByteArray &data) @@ -539,7 +516,7 @@ void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) sendGdbServerAck(); sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), - trkReadRegistersMessage()); + Launcher::readRegistersMessage(m_session.pid, m_session.tid)); } } @@ -549,7 +526,7 @@ void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) m_snapshot.setRegistersValid(m_session.tid, false); sendTrkMessage(0x12, TrkCB(handleAndReportReadRegisters), - trkReadRegistersMessage()); + Launcher::readRegistersMessage(m_session.pid, m_session.tid)); } else if (cmd.startsWith("salstep,")) { @@ -611,7 +588,7 @@ void TrkGdbAdapter::handleGdbServerCommand(const QByteArray &cmd) //qDebug() << "Fetching single register"; sendTrkMessage(0x12, TrkCB(handleAndReportReadRegister), - trkReadRegistersMessage(), registerNumber); + Launcher::readRegistersMessage(m_session.pid, m_session.tid), registerNumber); } } @@ -978,7 +955,7 @@ void TrkGdbAdapter::handleTrkResult(const TrkResult &result) //qDebug() << "Auto-fetching registers"; sendTrkMessage(0x12, TrkCB(handleAndReportReadRegistersAfterStop), - trkReadRegistersMessage()); + Launcher::readRegistersMessage(m_session.pid, m_session.tid)); # else // As a source-line step typically consists of // several instruction steps, better avoid the multiple @@ -1018,27 +995,19 @@ void TrkGdbAdapter::handleTrkResult(const TrkResult &result) const trk::byte error = result.data.at(0); // type: 1 byte; for dll item, this value is 2. const trk::byte type = result.data.at(1); - const uint pid = extractInt(data + 2); const uint tid = extractInt(data + 6); - const uint codeseg = extractInt(data + 10); - const uint dataseg = extractInt(data + 14); - const uint len = extractShort(data + 18); - const QByteArray name = result.data.mid(20, len); // library name - m_session.modules += QString::fromAscii(name); + const Library lib = Library(result); + m_session.libraries.push_back(lib); + m_session.modules += QString::fromAscii(lib.name); QString logMsg; QTextStream str(&logMsg); str << prefix << " NOTE: LIBRARY LOAD: token=" << result.token; if (error) str << " ERROR: " << int(error); - str << " TYPE: " << int(type) << " PID: " << pid << " TID: " << tid; - str << " CODE: " << hexxNumber(codeseg); - str << " DATA: " << hexxNumber(dataseg); - str << " NAME: '" << name << '\''; - Library lib; - lib.name = name; - lib.codeseg = codeseg; - lib.dataseg = dataseg; - m_session.libraries.append(lib); + str << " TYPE: " << int(type) << " PID: " << lib.pid << " TID: " << tid; + str << " CODE: " << hexxNumber(lib.codeseg); + str << " DATA: " << hexxNumber(lib.dataseg); + str << " NAME: '" << lib.name << '\''; if (tid && tid != unsigned(-1) && m_snapshot.indexOfThread(tid) == -1) m_snapshot.addThread(tid); logMessage(logMsg); @@ -1365,7 +1334,7 @@ void TrkGdbAdapter::handleStep(const TrkResult &result) // making some progress through a 'step'. //sendTrkMessage(0x12, // TrkCB(handleAndReportReadRegistersAfterStop), - // trkReadRegistersMessage()); + // Launcher::readRegistersMessage(m_session.pid, m_session.tid)); return; } // The gdb server response is triggered later by the Stop Reply packet. @@ -1681,7 +1650,7 @@ void TrkGdbAdapter::write(const QByteArray &data) if (data.startsWith("@@")) { // Read data sendTrkMessage(0x10, TrkCB(handleDirectWrite1), - trkReadMemoryMessage(m_session.dataseg, 12)); + Launcher::readMemoryMessage(m_session.pid, m_session.tid, m_session.dataseg, 12)); return; } m_gdbProc.write(data); @@ -1745,7 +1714,7 @@ void TrkGdbAdapter::handleDirectWrite2(const TrkResult &response) } else { // Check sendTrkMessage(0x10, TrkCB(handleDirectWrite3), - trkReadMemoryMessage(scratch, 12)); + trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, scratch, 12)); } } @@ -1811,7 +1780,8 @@ void TrkGdbAdapter::handleDirectWrite7(const TrkResult &response) } else { // Check sendTrkMessage(0x10, TrkCB(handleDirectWrite8), - trkReadMemoryMessage(scratch, 8)); + trk::Launcher::readMemoryMessage(m_session.pid, m_session.tid, + scratch, 8)); } } @@ -1824,7 +1794,7 @@ void TrkGdbAdapter::handleDirectWrite8(const TrkResult &response) // Re-read registers sendTrkMessage(0x12, TrkCB(handleAndReportReadRegistersAfterStop), - trkReadRegistersMessage()); + Launcher::readRegistersMessage(m_session.pid, m_session.tid)); } } diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h index bed271e6c69bacbd67ef299d419db3e128de0c96..69a770af3018194631ebaef2004b5a983d911c73 100644 --- a/src/plugins/debugger/gdb/trkgdbadapter.h +++ b/src/plugins/debugger/gdb/trkgdbadapter.h @@ -185,10 +185,8 @@ private: void handleDirectWrite9(const TrkResult &response); QByteArray trkContinueMessage(uint threadId); - QByteArray trkReadRegistersMessage(); QByteArray trkWriteRegisterMessage(trk::byte reg, uint value); QByteArray trkReadMemoryMessage(const MemoryRange &range); - QByteArray trkReadMemoryMessage(uint addr, uint len); QByteArray trkWriteMemoryMessage(uint addr, const QByteArray &date); QByteArray trkBreakpointMessage(uint addr, uint len, bool armMode = true); QByteArray trkStepRangeMessage(); diff --git a/src/shared/symbianutils/launcher.cpp b/src/shared/symbianutils/launcher.cpp index 0948ca02c92e98dcab05b1c036f6bffc2c8eaaf6..a22c12f990533a42055d1a9a84650e4ceeb5e2dd 100644 --- a/src/shared/symbianutils/launcher.cpp +++ b/src/shared/symbianutils/launcher.cpp @@ -46,6 +46,33 @@ namespace trk { +struct CrashReportState { + CrashReportState(); + void clear(); + + typedef uint Thread; + typedef QList<Thread> Threads; + Threads threads; + + QList<uint> registers; + QByteArray stack; + uint sp; + uint fetchingStackPID; + uint fetchingStackTID; +}; + +CrashReportState::CrashReportState() +{ + clear(); +} + +void CrashReportState::clear() +{ + threads.clear(); + stack.clear(); + sp = fetchingStackPID = fetchingStackTID = 0; +} + struct LauncherPrivate { struct CopyState { QString sourceFileName; @@ -74,6 +101,7 @@ struct LauncherPrivate { int m_verbose; Launcher::Actions m_startupActions; bool m_closeDevice; + CrashReportState m_crashReportState; }; LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) : @@ -190,6 +218,7 @@ void Launcher::setCloseDevice(bool c) bool Launcher::startServer(QString *errorMessage) { errorMessage->clear(); + d->m_crashReportState.clear(); if (d->m_verbose) { QString msg; QTextStream str(&msg); @@ -404,46 +433,37 @@ void Launcher::handleResult(const TrkResult &result) // target->host OS notification case TrkNotifyCreated: { // Notify Created - /* - const char *data = result.data.data(); - byte error = result.data.at(0); - byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. - uint pid = extractInt(data + 2); // ProcessID: 4 bytes; - uint tid = extractInt(data + 6); //threadID: 4 bytes - uint codeseg = extractInt(data + 10); //code address: 4 bytes; code base address for the library - uint dataseg = extractInt(data + 14); //data address: 4 bytes; data base address for the library - uint len = extractShort(data + 18); //length: 2 bytes; length of the library name string to follow - QByteArray name = result.data.mid(20, len); // name: library name - - logMessage(prefix + "NOTE: LIBRARY LOAD: " + str); - logMessage(prefix + "TOKEN: " + result.token); - logMessage(prefix + "ERROR: " + int(error)); - logMessage(prefix + "TYPE: " + int(type)); - logMessage(prefix + "PID: " + pid); - logMessage(prefix + "TID: " + tid); - logMessage(prefix + "CODE: " + codeseg); - logMessage(prefix + "DATA: " + dataseg); - logMessage(prefix + "LEN: " + len); - logMessage(prefix + "NAME: " + name); - */ if (result.data.size() < 10) break; + const char *data = result.data.constData(); + const byte error = result.data.at(0); + Q_UNUSED(error) + const byte type = result.data.at(1); // type: 1 byte; for dll item, this value is 2. + const uint tid = extractInt(data + 6); //threadID: 4 bytes + Q_UNUSED(tid) + if (type == kDSOSDLLItem && result.data.size() >=20) { + const Library lib = Library(result); + d->m_session.libraries.push_back(lib); + emit libraryLoaded(lib); + } QByteArray ba; ba.append(result.data.mid(2, 8)); d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE"); - //d->m_device->sendTrkAck(result.token) break; } case TrkNotifyDeleted: { // NotifyDeleted const ushort itemType = (unsigned char)result.data.at(1); - const ushort len = result.data.size() > 12 ? extractShort(result.data.data() + 10) : ushort(0); + const uint pid = result.data.size() >= 6 ? extractShort(result.data.constData() + 2) : 0; + const uint tid = result.data.size() >= 10 ? extractShort(result.data.constData() + 6) : 0; + Q_UNUSED(tid) + const ushort len = result.data.size() > 12 ? extractShort(result.data.constData() + 10) : ushort(0); const QString name = len ? QString::fromAscii(result.data.mid(12, len)) : QString(); logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3"). arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")). arg(name)); d->m_device->sendTrkAck(result.token); - if (itemType == 0 // process + if (itemType == kDSOSProcessItem // process && result.data.size() >= 10 && d->m_session.pid == extractInt(result.data.data() + 6)) { if (d->m_startupActions & ActionDownload) @@ -451,6 +471,17 @@ void Launcher::handleResult(const TrkResult &result) else disconnectTrk(); } + else if (itemType == kDSOSDLLItem && len) { + // Remove libraries of process. + for (QList<Library>::iterator it = d->m_session.libraries.begin(); it != d->m_session.libraries.end(); ) { + if ((*it).pid == pid && (*it).name == name) { + emit libraryUnloaded(*it); + it = d->m_session.libraries.erase(it); + } else { + ++it; + } + } + } break; } case TrkNotifyProcessorStarted: { // NotifyProcessorStarted @@ -696,6 +727,15 @@ void Launcher::handleCreateProcess(const TrkResult &result) logMessage(msg); } emit applicationRunning(d->m_session.pid); + //create a "library" entry for the executable which launched the process + Library lib; + lib.pid = d->m_session.pid; + lib.codeseg = d->m_session.codeseg; + lib.dataseg = d->m_session.dataseg; + lib.name = d->m_fileName.toUtf8(); + d->m_session.libraries << lib; + emit libraryLoaded(lib); + QByteArray ba; appendInt(&ba, d->m_session.pid); appendInt(&ba, d->m_session.tid); @@ -847,6 +887,30 @@ QByteArray Launcher::startProcessMessage(const QString &executable, return ba; } +QByteArray Launcher::readMemoryMessage(uint pid, uint tid, uint from, uint len) +{ + QByteArray ba; + ba.reserve(11); + ba.append(char(0x8)); // Options, FIXME: why? + appendShort(&ba, len); + appendInt(&ba, from); + appendInt(&ba, pid); + appendInt(&ba, tid); + return ba; +} + +QByteArray Launcher::readRegistersMessage(uint pid, uint tid) +{ + QByteArray ba; + ba.reserve(15); + ba.append(char(0)); // Register set, only 0 supported + appendShort(&ba, 0); //R0 + appendShort(&ba, 16); // last register CPSR + appendInt(&ba, pid); + appendInt(&ba, tid); + return ba; +} + void Launcher::startInferiorIfNeeded() { emit startingApplication(); @@ -898,4 +962,63 @@ void Launcher::releaseToDeviceManager(Launcher *launcher) sdm->releaseDevice(launcher->trkServerName()); } +void Launcher::getRegistersAndCallStack(uint pid, uint tid) +{ + d->m_device->sendTrkMessage(TrkReadRegisters, + TrkCallback(this, &Launcher::handleReadRegisters), + Launcher::readRegistersMessage(pid, tid)); + d->m_crashReportState.fetchingStackPID = pid; + d->m_crashReportState.fetchingStackTID = tid; +} + +void Launcher::handleReadRegisters(const TrkResult &result) +{ + if(result.errorCode() || result.data.size() < (17*4)) { + terminate(); + return; + } + const char* data = result.data.constData() + 1; + d->m_crashReportState.registers.clear(); + d->m_crashReportState.stack.clear(); + for (int i=0;i<17;i++) { + uint r = extractInt(data); + data += 4; + d->m_crashReportState.registers.append(r); + } + d->m_crashReportState.sp = d->m_crashReportState.registers.at(13); + + const ushort len = 1024 - (d->m_crashReportState.sp % 1024); //read to 1k boundary first + const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID, + d->m_crashReportState.fetchingStackTID, + d->m_crashReportState.sp, + len); + d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba); + d->m_crashReportState.sp += len; +} + +void Launcher::handleReadStack(const TrkResult &result) +{ + if (result.errorCode()) { + //error implies memory fault when reaching end of stack + emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack); + return; + } + + const uint len = extractShort(result.data.constData() + 1); + d->m_crashReportState.stack.append(result.data.mid(3, len)); + + if (d->m_crashReportState.sp - d->m_crashReportState.registers.at(13) > 0x10000) { + //read enough stack, stop here + emit registersAndCallStackReadComplete(d->m_crashReportState.registers, d->m_crashReportState.stack); + return; + } + //read 1k more + const QByteArray ba = Launcher::readMemoryMessage(d->m_crashReportState.fetchingStackPID, + d->m_crashReportState.fetchingStackTID, + d->m_crashReportState.sp, + 1024); + d->m_device->sendTrkMessage(TrkReadMemory, TrkCallback(this, &Launcher::handleReadStack), ba); + d->m_crashReportState.sp += 1024; +} + } // namespace trk diff --git a/src/shared/symbianutils/launcher.h b/src/shared/symbianutils/launcher.h index 993a5ae97bb5b6f7f08b01f726097a55c1c09d23..7e348e80842de984f231e93b1bb83e62d2fc5ba9 100644 --- a/src/shared/symbianutils/launcher.h +++ b/src/shared/symbianutils/launcher.h @@ -30,6 +30,7 @@ #define LAUNCHER_H #include "trkdevice.h" +#include "trkutils.h" #include <QtCore/QObject> #include <QtCore/QVariant> @@ -109,6 +110,9 @@ public: // Create Trk message to start a process. static QByteArray startProcessMessage(const QString &executable, const QStringList &arguments); + // Create Trk message to read memory + static QByteArray readMemoryMessage(uint pid, uint tid, uint from, uint len); + static QByteArray readRegistersMessage(uint pid, uint tid); // Parse a TrkNotifyStopped message static bool parseNotifyStopped(const QByteArray &a, uint *pid, uint *tid, uint *address, @@ -136,12 +140,18 @@ signals: void copyProgress(int percent); void stateChanged(int); void processStopped(uint pc, uint pid, uint tid, const QString& reason); + void processResumed(uint pid, uint tid); + void libraryLoaded(const trk::Library &lib); + void libraryUnloaded(const trk::Library &lib); + void registersAndCallStackReadComplete(const QList<uint>& registers, const QByteArray& stack); // Emitted by the destructor, for releasing devices of SymbianDeviceManager by name void destroyed(const QString &serverName); public slots: void terminate(); void resumeProcess(uint pid, uint tid); + //can be used to obtain traceback after a breakpoint / exception + void getRegistersAndCallStack(uint pid, uint tid); private slots: void handleResult(const trk::TrkResult &data); @@ -169,6 +179,8 @@ private: void handleStop(const TrkResult &result); void handleSupportMask(const TrkResult &result); void handleTrkVersion(const TrkResult &result); + void handleReadRegisters(const TrkResult &result); + void handleReadStack(const TrkResult &result); void copyFileToRemote(); void copyFileFromRemote(); diff --git a/src/shared/symbianutils/trkutils.cpp b/src/shared/symbianutils/trkutils.cpp index 9caf807127b0d8585df5f2b5e34cd90d43fdb110..d09ed373d236c7a9769ad7608b06256949731714 100644 --- a/src/shared/symbianutils/trkutils.cpp +++ b/src/shared/symbianutils/trkutils.cpp @@ -40,6 +40,25 @@ namespace trk { +Library::Library() : codeseg(0), dataseg(0), pid(0) +{ +} + +Library::Library(const TrkResult &result) : codeseg(0), dataseg(0), pid(0) +{ + if (result.data.size() < 20) { + qWarning("Invalid trk creation notification received."); + return; + } + + const char *data = result.data.constData(); + pid = extractInt(data + 2); + codeseg = extractInt(data + 10); + dataseg = extractInt(data + 14); + const uint len = extractShort(data + 18); + name = result.data.mid(20, len); +} + TrkAppVersion::TrkAppVersion() { reset(); @@ -260,18 +279,15 @@ SYMBIANUTILS_EXPORT QString stringFromArray(const QByteArray &ba, int maxLen) QString ascii; const int size = maxLen == -1 ? ba.size() : qMin(ba.size(), maxLen); for (int i = 0; i < size; ++i) { - //if (i == 5 || i == ba.size() - 2) - // str += " "; - int c = byte(ba.at(i)); - str += QString("%1 ").arg(c, 2, 16, QChar('0')); - if (i >= 8 && i < ba.size() - 2) - ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); + const int c = byte(ba.at(i)); + str += QString::fromAscii("%1 ").arg(c, 2, 16, QChar('0')); + ascii += QChar(c).isPrint() ? QChar(c) : QChar('.'); } if (size != ba.size()) { - str += "..."; - ascii += "..."; + str += QLatin1String("..."); + ascii += QLatin1String("..."); } - return str + " " + ascii; + return str + QLatin1String(" ") + ascii; } SYMBIANUTILS_EXPORT QByteArray hexNumber(uint n, int digits) diff --git a/src/shared/symbianutils/trkutils.h b/src/shared/symbianutils/trkutils.h index 394f9ba85d170d3503a35dcde84d04bd0dcb4618..9885053484562300925a80c5c3872027cf6d259e 100644 --- a/src/shared/symbianutils/trkutils.h +++ b/src/shared/symbianutils/trkutils.h @@ -44,6 +44,7 @@ QT_END_NAMESPACE namespace trk { typedef unsigned char byte; +struct TrkResult; enum Command { //meta commands @@ -123,6 +124,20 @@ enum Command { TrkDSPositionFile = 0xd4 }; +enum DSOSItemTypes { + kDSOSProcessItem = 0x0000, + kDSOSThreadItem = 0x0001, + kDSOSDLLItem = 0x0002, + kDSOSAppItem = 0x0003, + kDSOSMemBlockItem = 0x0004, + kDSOSProcAttachItem = 0x0005, + kDSOSThreadAttachItem = 0x0006, + kDSOSProcAttach2Item = 0x0007, + kDSOSProcRunItem = 0x0008, + /* 0x0009 - 0x00ff reserved for general expansion */ + /* 0x0100 - 0xffff available for target-specific use */ +}; + enum SerialMultiplexor { MuxRaw = 0, MuxTextTrace = 0x0102, @@ -152,11 +167,14 @@ SYMBIANUTILS_EXPORT void appendString(QByteArray *ba, const QByteArray &str, End struct SYMBIANUTILS_EXPORT Library { - Library() {} + Library(); + explicit Library(const TrkResult &r); QByteArray name; uint codeseg; uint dataseg; + //library addresses are valid for a given process (depending on memory model, they might be loaded at the same address in all processes or not) + uint pid; }; struct SYMBIANUTILS_EXPORT TrkAppVersion