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 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);
@@ -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 *>(bkparm.data()),
bkparm.size(),
reinterpret_cast<BKRSP *>(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<const BKRSP *>(bkrsp.constData());
tickMark = bkrspPtr->tickMark;
address = bkrspPtr->address;
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;
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 *>(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 *>(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 *>(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 *>(bkparm.data()),
bkparm.size(),
reinterpret_cast<BKRSP *>(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<const BKRSP *>(bkrsp.constData())->tickMark;
bkrspLength = bkrsp.size();
st = ::UVSC_DBG_CHANGE_BP(m_descriptor, &bkchg, sizeof(bkchg),
reinterpret_cast<BKRSP *>(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<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())
@@ -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<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

View File

@@ -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<BKRSP> &bpenums);
bool executeCommand(const QString &cmd, QString &output);
qint32 m_descriptor = -1;
quint64 m_exitAddress = 0;

View File

@@ -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 {

View File

@@ -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 = {};

View File

@@ -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);