diff options
Diffstat (limited to 'src/plugins/debugger/uvsc/uvscclient.cpp')
-rw-r--r-- | src/plugins/debugger/uvsc/uvscclient.cpp | 197 |
1 files changed, 165 insertions, 32 deletions
diff --git a/src/plugins/debugger/uvsc/uvscclient.cpp b/src/plugins/debugger/uvsc/uvscclient.cpp index 33889646ed..50738d3377 100644 --- a/src/plugins/debugger/uvsc/uvscclient.cpp +++ b/src/plugins/debugger/uvsc/uvscclient.cpp @@ -43,7 +43,7 @@ constexpr int kMaximumRegisterGroupsCount = 128; constexpr int kMaximumRegisterEnumsCount = 512; constexpr int kMaximumVarinfosCount = 256; constexpr int kMaximumValueBitsSize = 32; -constexpr int kMaximumBreakpointResponseSize = 1024; +constexpr int kMaximumBreakpointEnumsCount = 128; constexpr int kMaximumDisassembledBytesCount = 1024; const QEvent::Type kUvscMsgEventType = static_cast<QEvent::Type>(QEvent::User + 1); @@ -691,6 +691,41 @@ bool UvscClient::inspectWatcher(const QStringList &expandedWatcherINames, return true; } +bool UvscClient::fetchMemory(quint64 address, QByteArray &data) +{ + if (data.isEmpty()) + data.resize(sizeof(quint8)); + + QByteArray amem = UvscUtils::encodeAmem(address, data); + const auto amemPtr = reinterpret_cast<AMEM *>(amem.data()); + const UVSC_STATUS st = ::UVSC_DBG_MEM_READ(m_descriptor, amemPtr, amem.size()); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + data = QByteArray(reinterpret_cast<char *>(&amemPtr->bytes), + amemPtr->bytesCount); + return true; +} + +bool UvscClient::changeMemory(quint64 address, const QByteArray &data) +{ + if (data.isEmpty()) { + setError(RuntimeError); + return false; + } + + QByteArray amem = UvscUtils::encodeAmem(address, data); + const auto amemPtr = reinterpret_cast<AMEM *>(amem.data()); + const UVSC_STATUS st = ::UVSC_DBG_MEM_WRITE(m_descriptor, amemPtr, amem.size()); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + return true; +} + bool UvscClient::disassemblyAddress(quint64 address, QByteArray &result) { if (!checkConnection()) @@ -764,22 +799,32 @@ bool UvscClient::createBreakpoint(const QString &exp, quint32 &tickMark, quint64 if (!checkConnection()) return false; - QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, exp); - QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); - qint32 bkrspLength = bkrsp.size(); - const UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor, - reinterpret_cast<BKPARM *>(bkparm.data()), - bkparm.size(), - reinterpret_cast<BKRSP *>(bkrsp.data()), - &bkrspLength); - if (st != UVSC_STATUS_SUCCESS) { - setError(RuntimeError); + // Magic workaround to prevent the stalling. + if (!controlHiddenBreakpoint(exp)) + return false; + + // Execute command to create the BP. + const QString setCmd = QStringLiteral("BS %1").arg(exp); + QString setCmdOutput; + if (!executeCommand(setCmd, setCmdOutput)) + return false; + + std::vector<BKRSP> bpenums; + if (!enumerateBreakpoints(bpenums)) + return false; + + const auto bpenumBegin = bpenums.cbegin(); + const auto bpenumEnd = bpenums.cend(); + const auto bpenumIt = std::find_if(bpenumBegin, bpenumEnd, [exp](const BKRSP &bpenum) { + const QString bpexp = QString::fromLatin1(reinterpret_cast<const char *>(bpenum.expressionBuffer), + bpenum.expressionLength).trimmed(); + return bpexp.contains(exp); + }); + if (bpenumIt == bpenumEnd) return false; - } - const auto bkrspPtr = reinterpret_cast<const BKRSP *>(bkrsp.constData()); - tickMark = bkrspPtr->tickMark; - address = bkrspPtr->address; + tickMark = bpenumIt->tickMark; + address = bpenumIt->address; if (!addressToFileLine(address, fileName, function, line)) return false; @@ -794,11 +839,9 @@ bool UvscClient::deleteBreakpoint(quint32 tickMark) BKCHG bkchg = {}; bkchg.type = CHG_KILLBP; bkchg.tickMark = tickMark; - QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); - qint32 bkrspLength = bkrsp.size(); - const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), - reinterpret_cast<BKRSP *>(bkrsp.data()), - &bkrspLength); + BKRSP bkrsp = {}; + qint32 bkrspLength = sizeof(bkrsp); + const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength); if (st != UVSC_STATUS_SUCCESS) { setError(RuntimeError); return false; @@ -814,11 +857,9 @@ bool UvscClient::enableBreakpoint(quint32 tickMark) BKCHG bkchg = {}; bkchg.type = CHG_ENABLEBP; bkchg.tickMark = tickMark; - QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); - qint32 bkrspLength = bkrsp.size(); - const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), - reinterpret_cast<BKRSP *>(bkrsp.data()), - &bkrspLength); + BKRSP bkrsp = {}; + qint32 bkrspLength = sizeof(bkrsp); + const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength); if (st != UVSC_STATUS_SUCCESS) { setError(RuntimeError); return false; @@ -834,11 +875,9 @@ bool UvscClient::disableBreakpoint(quint32 tickMark) BKCHG bkchg = {}; bkchg.type = CHG_DISABLEBP; bkchg.tickMark = tickMark; - QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); - qint32 bkrspLength = bkrsp.size(); - const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), - reinterpret_cast<BKRSP *>(bkrsp.data()), - &bkrspLength); + BKRSP bkrsp = {}; + qint32 bkrspLength = sizeof(bkrsp); + const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength); if (st != UVSC_STATUS_SUCCESS) { setError(RuntimeError); return false; @@ -846,6 +885,69 @@ bool UvscClient::disableBreakpoint(quint32 tickMark) return true; } +bool UvscClient::controlHiddenBreakpoint(const QString &exp) +{ + if (!checkConnection()) + return false; + + // It is a magic workaround to prevent the UVSC bug when the break-point + // creation may stall. A problem is that sometime the UVSC_DBG_CREATE_BP + // function blocks and returns then with the timeout error when the original + // break-point contains the full expression including the line number. + // + // It can be avoided with helps of creation and then deletion of the + // 'fake hidden' break-point with the same expression excluding the line + // number, before creation of an original break-point. + + const int slashIndex = exp.lastIndexOf('\\'); + if (slashIndex == -1 || (slashIndex + 1) == exp.size()) + return true; + + BKRSP bkrsp = {}; + + const QString hiddenExp = exp.mid(0, slashIndex); + QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, hiddenExp); + qint32 bkrspLength = sizeof(bkrsp); + UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor, + reinterpret_cast<BKPARM *>(bkparm.data()), + bkparm.size(), + &bkrsp, &bkrspLength); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + BKCHG bkchg = {}; + bkchg.type = CHG_KILLBP; + bkchg.tickMark = bkrsp.tickMark; + bkrspLength = sizeof(bkrsp); + st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + return true; +} + +bool UvscClient::enumerateBreakpoints(std::vector<BKRSP> &bpenums) +{ + if (!checkConnection()) + return false; + + bpenums.resize(kMaximumBreakpointEnumsCount); + qint32 bpenumsCount = kMaximumBreakpointEnumsCount; + std::vector<qint32> indexes(bpenumsCount, 0); + const UVSC_STATUS st = ::UVSC_DBG_ENUMERATE_BP(m_descriptor, bpenums.data(), + indexes.data(), &bpenumsCount); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + bpenums.resize(bpenumsCount); + return true; +} + bool UvscClient::calculateExpression(const QString &exp, QByteArray &) { if (!checkConnection()) @@ -985,7 +1087,7 @@ void UvscClient::setError(UvscError error, const QString &errorString) reinterpret_cast<qint8 *>(buffer.data()), buffer.size()); m_errorString = (st == UVSC_STATUS_SUCCESS) - ? QString::fromLocal8Bit(buffer) : tr("Unknown error"); + ? QString::fromLocal8Bit(buffer) : tr("Unknown error."); } else { m_errorString = errorString; } @@ -1014,7 +1116,7 @@ void UvscClient::customEvent(QEvent *event) bool UvscClient::checkConnection() { if (m_descriptor == -1) { - setError(ConfigurationError, tr("Connection is not open")); + setError(ConfigurationError, tr("Connection is not open.")); return false; } return true; @@ -1097,5 +1199,36 @@ bool UvscClient::addressToFileLine(quint64 address, QString &fileName, return true; } +bool UvscClient::executeCommand(const QString &cmd, QString &output) +{ + if (!checkConnection()) + return false; + + EXECCMD exeCmd = UvscUtils::encodeCommand(cmd); + UVSC_STATUS st = ::UVSC_DBG_EXEC_CMD(m_descriptor, &exeCmd, sizeof(exeCmd.command)); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + qint32 outputLength = 0; + st = ::UVSC_GetCmdOutputSize(m_descriptor, &outputLength); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + QByteArray data(outputLength, 0); + st = UVSC_GetCmdOutput(m_descriptor, reinterpret_cast<qint8 *>(data.data()), data.size()); + if (st != UVSC_STATUS_SUCCESS) { + setError(RuntimeError); + return false; + } + + // Note: UVSC API support only ASCII! + output = QString::fromLatin1(data); + return true; +} + } // namespace Internal } // namespace Debugger |