From b7851eeb55fd284bd647b7042e7f94a1ea1d3490 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Wed, 22 Apr 2020 16:48:31 +0300 Subject: [PATCH] Debugger: Fix breakpoint insertion stalling for UVSC engine The UVSC support the debugger commands execution feature using the UVSC_DBG_EXEC_CMD function. This function non-blocks if an command execution fails. So we can use this function to execute a breakpoint insertion command: * http://www.keil.com/support/man/docs/uv4/uv4_cm_breakset.htm But, to get the properties of the inserted breakpoint we need to enumerate all available breakpoints and to find the desired breakpoint by its expression. Besides, we need to fix and the 'expressionBuffer' field of the BKRSP structure according to the original UVSC API. Change-Id: I3c52e8955de28180aaafa1af9f6001ff6ee3b7fb Reviewed-by: hjk --- src/plugins/debugger/uvsc/uvscclient.cpp | 124 +++++++++++++++------- src/plugins/debugger/uvsc/uvscclient.h | 3 + src/plugins/debugger/uvsc/uvscdatatypes.h | 4 +- src/plugins/debugger/uvsc/uvscutils.cpp | 8 ++ src/plugins/debugger/uvsc/uvscutils.h | 1 + 5 files changed, 99 insertions(+), 41 deletions(-) diff --git a/src/plugins/debugger/uvsc/uvscclient.cpp b/src/plugins/debugger/uvsc/uvscclient.cpp index 588ca9c18b0..5c31411248c 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::User + 1); @@ -803,22 +803,28 @@ bool UvscClient::createBreakpoint(const QString &exp, quint32 &tickMark, quint64 if (!controlHiddenBreakpoint(exp)) 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.data()), - bkparm.size(), - reinterpret_cast(bkrsp.data()), - &bkrspLength); - if (st != UVSC_STATUS_SUCCESS) { - setError(RuntimeError); + // Execute command to create the BP. + const QString setCmd = QStringLiteral("BS %1").arg(exp); + QString setCmdOutput; + if (!executeCommand(setCmd, setCmdOutput)) return false; - } - const auto bkrspPtr = reinterpret_cast(bkrsp.constData()); - tickMark = bkrspPtr->tickMark; - address = bkrspPtr->address; + std::vector 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(bpenum.expressionBuffer), + bpenum.expressionLength).trimmed(); + return bpexp.contains(exp); + }); + if (bpenumIt == bpenumEnd) + return false; + + tickMark = bpenumIt->tickMark; + address = bpenumIt->address; if (!addressToFileLine(address, fileName, function, line)) return false; @@ -833,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.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; @@ -853,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.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; @@ -873,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.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; @@ -903,16 +903,15 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp) if (slashIndex == -1 || (slashIndex + 1) == exp.size()) return true; - QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); + BKRSP bkrsp = {}; const QString hiddenExp = exp.mid(0, slashIndex); QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, hiddenExp); - qint32 bkrspLength = bkrsp.size(); + qint32 bkrspLength = sizeof(bkrsp); UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor, reinterpret_cast(bkparm.data()), bkparm.size(), - reinterpret_cast(bkrsp.data()), - &bkrspLength); + &bkrsp, &bkrspLength); if (st != UVSC_STATUS_SUCCESS) { setError(RuntimeError); return false; @@ -920,11 +919,9 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp) BKCHG bkchg = {}; bkchg.type = CHG_KILLBP; - bkchg.tickMark = reinterpret_cast(bkrsp.constData())->tickMark; - bkrspLength = bkrsp.size(); - st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), - reinterpret_cast(bkrsp.data()), - &bkrspLength); + 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; @@ -933,6 +930,24 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp) return true; } +bool UvscClient::enumerateBreakpoints(std::vector &bpenums) +{ + if (!checkConnection()) + return false; + + bpenums.resize(kMaximumBreakpointEnumsCount); + qint32 bpenumsCount = kMaximumBreakpointEnumsCount; + std::vector 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()) @@ -1184,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(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 diff --git a/src/plugins/debugger/uvsc/uvscclient.h b/src/plugins/debugger/uvsc/uvscclient.h index c39a5f4a076..98b001ac4e3 100644 --- a/src/plugins/debugger/uvsc/uvscclient.h +++ b/src/plugins/debugger/uvsc/uvscclient.h @@ -36,6 +36,7 @@ QT_END_NAMESPACE // From UVSC api. struct STACKENUM; +struct BKRSP; namespace Utils { class FilePath; } @@ -142,6 +143,8 @@ private: bool addressToFileLine(quint64 address, QString &fileName, QString &function, quint32 &line); bool controlHiddenBreakpoint(const QString &exp); + bool enumerateBreakpoints(std::vector &bpenums); + bool executeCommand(const QString &cmd, QString &output); qint32 m_descriptor = -1; quint64 m_exitAddress = 0; diff --git a/src/plugins/debugger/uvsc/uvscdatatypes.h b/src/plugins/debugger/uvsc/uvscdatatypes.h index c2ef9d77129..4392d81644c 100644 --- a/src/plugins/debugger/uvsc/uvscdatatypes.h +++ b/src/plugins/debugger/uvsc/uvscdatatypes.h @@ -610,9 +610,9 @@ struct BKRSP { quint32 tickMark; quint64 address; quint32 expressionLength; - qint8 expressionBuffer[1]; + qint8 expressionBuffer[512]; }; -static_assert(sizeof(BKRSP) == 29, "BKRSP size is not 29 bytes"); +static_assert(sizeof(BKRSP) == 540, "BKRSP size is not 540 bytes"); // Breakpoint change data. struct BKCHG { diff --git a/src/plugins/debugger/uvsc/uvscutils.cpp b/src/plugins/debugger/uvsc/uvscutils.cpp index d7fb4d22eff..a8e7d97e623 100644 --- a/src/plugins/debugger/uvsc/uvscutils.cpp +++ b/src/plugins/debugger/uvsc/uvscutils.cpp @@ -120,6 +120,14 @@ QByteArray encodeAmem(quint64 address, const QByteArray &data) return buffer; } +EXECCMD encodeCommand(const QString &cmd) +{ + EXECCMD exeCmd = {}; + exeCmd.useEcho = false; + exeCmd.command = encodeSstr(cmd); + return exeCmd; +} + TVAL encodeVoidTval() { TVAL tval = {}; diff --git a/src/plugins/debugger/uvsc/uvscutils.h b/src/plugins/debugger/uvsc/uvscutils.h index b51ac017a5a..61778f11e5d 100644 --- a/src/plugins/debugger/uvsc/uvscutils.h +++ b/src/plugins/debugger/uvsc/uvscutils.h @@ -57,6 +57,7 @@ QByteArray encodeProjectData(const QStringList &someNames); QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString()); QByteArray encodeAmem(quint64 address, quint32 bytesCount); QByteArray encodeAmem(quint64 address, const QByteArray &data); +EXECCMD encodeCommand(const QString &cmd); TVAL encodeVoidTval(); TVAL encodeIntTval(int value); TVAL encodeU64Tval(quint64 value);