Debugger: Add peripheral registers description file support

This feature is useful for the bare-metal programming. It allows
to view the peripheral registers of the debugged device using
the GDB.

An information about the peripheral registers for a concrete
device contains in a special SVD file. A format of this file
described e.g. here:

* https://www.keil.com/pack/doc/CMSIS/SVD/html/svd_Format_pg.html

This feature supported only for ARM devices, and an appropriate
SVD files can be found in the Internet, also this files provides
by KEIL or IAR EW IDE's.

A use case in QtC is that the user should to choose desired SVD
file and set its path to the bare-metal device configuration widget.
After this, the user can enable the "Peripheral Registers" view,
choose a desired register group and to see a peripheral register
values.

Currently the following basic features are implemented:

* Choosing SVD file for a target bare-metal device.
* Choosing any peripheral register group, which is available for
  this device.
* Seeing the info about the each peripheral register and its fields.
* Seeing the value for the each peripheral register and its fields.
* Changing the value for the each peripheral register and its fields
  (if it is allowed by access for a concrete register or field).
* Changing the format of the values (hexadecimal, decimal, octal,
  binary).

Fixes: QTCREATORBUG-18729
Change-Id: I3c38ea50ccd2e128746458f9b918095b4c2d644a
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Denis Shienkov
2019-07-28 23:32:33 +03:00
parent 25a3c93cfe
commit 239c82bfb0
11 changed files with 1318 additions and 28 deletions

View File

@@ -1030,6 +1030,7 @@ void GdbEngine::updateAll()
stackHandler()->setCurrentIndex(0);
runCommand({"-thread-info", CB(handleThreadInfo)});
reloadRegisters();
reloadPeripheralRegisters();
updateLocals();
}
@@ -2903,6 +2904,7 @@ void GdbEngine::handleStackListFrames(const DebuggerResponse &response, bool isF
// logStreamOutput: "Previous frame identical to this frame (corrupt stack?)\n"
//qDebug() << "LISTING STACK FAILED: " << response.toString();
reloadRegisters();
reloadPeripheralRegisters();
return;
}
@@ -2943,6 +2945,7 @@ void GdbEngine::activateFrame(int frameIndex)
updateLocals();
reloadRegisters();
reloadPeripheralRegisters();
}
void GdbEngine::handleThreadInfo(const DebuggerResponse &response)
@@ -3062,6 +3065,22 @@ void GdbEngine::reloadRegisters()
}
}
void GdbEngine::reloadPeripheralRegisters()
{
if (!isPeripheralRegistersWindowVisible())
return;
const QList<quint64> addresses = peripheralRegisterHandler()->activeRegisters();
if (addresses.isEmpty())
return; // Nothing to update.
for (const quint64 address : addresses) {
const QString fun = QStringLiteral("x/1u 0x%1")
.arg(QString::number(address, 16));
runCommand({fun, CB(handlePeripheralRegisterListValues)});
}
}
static QString readWord(const QString &ba, int *pos)
{
const int n = ba.size();
@@ -3127,6 +3146,15 @@ void GdbEngine::setRegisterValue(const QString &name, const QString &value)
reloadRegisters();
}
void GdbEngine::setPeripheralRegisterValue(quint64 address, quint64 value)
{
const QString fun = QStringLiteral("set {int}0x%1=%2")
.arg(QString::number(address, 16))
.arg(value);
runCommand({fun});
reloadPeripheralRegisters();
}
void GdbEngine::handleRegisterListNames(const DebuggerResponse &response)
{
if (response.resultClass != ResultDone) {
@@ -3227,6 +3255,28 @@ void GdbEngine::handleRegisterListValues(const DebuggerResponse &response)
handler->commitUpdates();
}
void GdbEngine::handlePeripheralRegisterListValues(
const DebuggerResponse &response)
{
if (response.resultClass != ResultDone)
return;
const QString output = response.consoleStreamOutput;
// Regexp to match for '0x50060800:\t0\n'.
const QRegularExpression re("^(0x[0-9A-F]+):\\t(\\d+)\\n$");
const QRegularExpressionMatch m = re.match(output);
if (!m.hasMatch())
return;
enum { AddressMatch = 1, ValueMatch = 2 };
bool aok = false;
bool vok = false;
const quint64 address = m.captured(AddressMatch).toULongLong(&aok, 16);
const quint64 value = m.captured(ValueMatch).toULongLong(&vok, 10);
if (!aok || !vok)
return;
peripheralRegisterHandler()->updateRegister(address, value);
}
//////////////////////////////////////////////////////////////////////
//
@@ -3703,6 +3753,9 @@ void GdbEngine::setupEngine()
runCommand({commands});
runCommand({"loadDumpers", CB(handlePythonSetup)});
// Reload peripheral register description.
peripheralRegisterHandler()->updateRegisterGroups();
}
void GdbEngine::handleGdbStartFailed()