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 <hjk@qt.io>
This commit is contained in:
Denis Shienkov
2020-04-22 16:48:31 +03:00
parent f781a72825
commit b7851eeb55
5 changed files with 99 additions and 41 deletions

View File

@@ -43,7 +43,7 @@ constexpr int kMaximumRegisterGroupsCount = 128;
constexpr int kMaximumRegisterEnumsCount = 512; constexpr int kMaximumRegisterEnumsCount = 512;
constexpr int kMaximumVarinfosCount = 256; constexpr int kMaximumVarinfosCount = 256;
constexpr int kMaximumValueBitsSize = 32; constexpr int kMaximumValueBitsSize = 32;
constexpr int kMaximumBreakpointResponseSize = 1024; constexpr int kMaximumBreakpointEnumsCount = 128;
constexpr int kMaximumDisassembledBytesCount = 1024; constexpr int kMaximumDisassembledBytesCount = 1024;
const QEvent::Type kUvscMsgEventType = static_cast<QEvent::Type>(QEvent::User + 1); const QEvent::Type kUvscMsgEventType = static_cast<QEvent::Type>(QEvent::User + 1);
@@ -803,22 +803,28 @@ bool UvscClient::createBreakpoint(const QString &exp, quint32 &tickMark, quint64
if (!controlHiddenBreakpoint(exp)) if (!controlHiddenBreakpoint(exp))
return false; return false;
QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, exp); // Execute command to create the BP.
QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); const QString setCmd = QStringLiteral("BS %1").arg(exp);
qint32 bkrspLength = bkrsp.size(); QString setCmdOutput;
const UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor, if (!executeCommand(setCmd, setCmdOutput))
reinterpret_cast<BKPARM *>(bkparm.data()),
bkparm.size(),
reinterpret_cast<BKRSP *>(bkrsp.data()),
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError);
return false; return false;
}
const auto bkrspPtr = reinterpret_cast<const BKRSP *>(bkrsp.constData()); std::vector<BKRSP> bpenums;
tickMark = bkrspPtr->tickMark; if (!enumerateBreakpoints(bpenums))
address = bkrspPtr->address; 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;
tickMark = bpenumIt->tickMark;
address = bpenumIt->address;
if (!addressToFileLine(address, fileName, function, line)) if (!addressToFileLine(address, fileName, function, line))
return false; return false;
@@ -833,11 +839,9 @@ bool UvscClient::deleteBreakpoint(quint32 tickMark)
BKCHG bkchg = {}; BKCHG bkchg = {};
bkchg.type = CHG_KILLBP; bkchg.type = CHG_KILLBP;
bkchg.tickMark = tickMark; bkchg.tickMark = tickMark;
QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); BKRSP bkrsp = {};
qint32 bkrspLength = bkrsp.size(); qint32 bkrspLength = sizeof(bkrsp);
const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
reinterpret_cast<BKRSP *>(bkrsp.data()),
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) { if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError); setError(RuntimeError);
return false; return false;
@@ -853,11 +857,9 @@ bool UvscClient::enableBreakpoint(quint32 tickMark)
BKCHG bkchg = {}; BKCHG bkchg = {};
bkchg.type = CHG_ENABLEBP; bkchg.type = CHG_ENABLEBP;
bkchg.tickMark = tickMark; bkchg.tickMark = tickMark;
QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); BKRSP bkrsp = {};
qint32 bkrspLength = bkrsp.size(); qint32 bkrspLength = sizeof(bkrsp);
const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
reinterpret_cast<BKRSP *>(bkrsp.data()),
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) { if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError); setError(RuntimeError);
return false; return false;
@@ -873,11 +875,9 @@ bool UvscClient::disableBreakpoint(quint32 tickMark)
BKCHG bkchg = {}; BKCHG bkchg = {};
bkchg.type = CHG_DISABLEBP; bkchg.type = CHG_DISABLEBP;
bkchg.tickMark = tickMark; bkchg.tickMark = tickMark;
QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); BKRSP bkrsp = {};
qint32 bkrspLength = bkrsp.size(); qint32 bkrspLength = sizeof(bkrsp);
const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), const UVSC_STATUS st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
reinterpret_cast<BKRSP *>(bkrsp.data()),
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) { if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError); setError(RuntimeError);
return false; return false;
@@ -903,16 +903,15 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp)
if (slashIndex == -1 || (slashIndex + 1) == exp.size()) if (slashIndex == -1 || (slashIndex + 1) == exp.size())
return true; return true;
QByteArray bkrsp(kMaximumBreakpointResponseSize, 0); BKRSP bkrsp = {};
const QString hiddenExp = exp.mid(0, slashIndex); const QString hiddenExp = exp.mid(0, slashIndex);
QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, hiddenExp); QByteArray bkparm = UvscUtils::encodeBreakPoint(BRKTYPE_EXEC, hiddenExp);
qint32 bkrspLength = bkrsp.size(); qint32 bkrspLength = sizeof(bkrsp);
UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor, UVSC_STATUS st = ::UVSC_DBG_CREATE_BP(m_descriptor,
reinterpret_cast<BKPARM *>(bkparm.data()), reinterpret_cast<BKPARM *>(bkparm.data()),
bkparm.size(), bkparm.size(),
reinterpret_cast<BKRSP *>(bkrsp.data()), &bkrsp, &bkrspLength);
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) { if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError); setError(RuntimeError);
return false; return false;
@@ -920,11 +919,9 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp)
BKCHG bkchg = {}; BKCHG bkchg = {};
bkchg.type = CHG_KILLBP; bkchg.type = CHG_KILLBP;
bkchg.tickMark = reinterpret_cast<const BKRSP *>(bkrsp.constData())->tickMark; bkchg.tickMark = bkrsp.tickMark;
bkrspLength = bkrsp.size(); bkrspLength = sizeof(bkrsp);
st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg), &bkrsp, &bkrspLength);
reinterpret_cast<BKRSP *>(bkrsp.data()),
&bkrspLength);
if (st != UVSC_STATUS_SUCCESS) { if (st != UVSC_STATUS_SUCCESS) {
setError(RuntimeError); setError(RuntimeError);
return false; return false;
@@ -933,6 +930,24 @@ bool UvscClient::controlHiddenBreakpoint(const QString &exp)
return true; 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 &) bool UvscClient::calculateExpression(const QString &exp, QByteArray &)
{ {
if (!checkConnection()) if (!checkConnection())
@@ -1184,5 +1199,36 @@ bool UvscClient::addressToFileLine(quint64 address, QString &fileName,
return true; 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 Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -36,6 +36,7 @@ QT_END_NAMESPACE
// From UVSC api. // From UVSC api.
struct STACKENUM; struct STACKENUM;
struct BKRSP;
namespace Utils { class FilePath; } namespace Utils { class FilePath; }
@@ -142,6 +143,8 @@ private:
bool addressToFileLine(quint64 address, QString &fileName, QString &function, quint32 &line); bool addressToFileLine(quint64 address, QString &fileName, QString &function, quint32 &line);
bool controlHiddenBreakpoint(const QString &exp); bool controlHiddenBreakpoint(const QString &exp);
bool enumerateBreakpoints(std::vector<BKRSP> &bpenums);
bool executeCommand(const QString &cmd, QString &output);
qint32 m_descriptor = -1; qint32 m_descriptor = -1;
quint64 m_exitAddress = 0; quint64 m_exitAddress = 0;

View File

@@ -610,9 +610,9 @@ struct BKRSP {
quint32 tickMark; quint32 tickMark;
quint64 address; quint64 address;
quint32 expressionLength; 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. // Breakpoint change data.
struct BKCHG { struct BKCHG {

View File

@@ -120,6 +120,14 @@ QByteArray encodeAmem(quint64 address, const QByteArray &data)
return buffer; return buffer;
} }
EXECCMD encodeCommand(const QString &cmd)
{
EXECCMD exeCmd = {};
exeCmd.useEcho = false;
exeCmd.command = encodeSstr(cmd);
return exeCmd;
}
TVAL encodeVoidTval() TVAL encodeVoidTval()
{ {
TVAL tval = {}; TVAL tval = {};

View File

@@ -57,6 +57,7 @@ QByteArray encodeProjectData(const QStringList &someNames);
QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString()); QByteArray encodeBreakPoint(BKTYPE type, const QString &exp, const QString &cmd = QString());
QByteArray encodeAmem(quint64 address, quint32 bytesCount); QByteArray encodeAmem(quint64 address, quint32 bytesCount);
QByteArray encodeAmem(quint64 address, const QByteArray &data); QByteArray encodeAmem(quint64 address, const QByteArray &data);
EXECCMD encodeCommand(const QString &cmd);
TVAL encodeVoidTval(); TVAL encodeVoidTval();
TVAL encodeIntTval(int value); TVAL encodeIntTval(int value);
TVAL encodeU64Tval(quint64 value); TVAL encodeU64Tval(quint64 value);