forked from qt-creator/qt-creator
Debugger: consolidate WatchData manipulation in watchdata.{h,cpp}
Change-Id: I241d37793dfde9cfe8e4895039819e91297e6cba Reviewed-by: hjk <hjk121@nokiamail.com>
This commit is contained in:
@@ -1014,8 +1014,8 @@ void GdbEngine::handleDebuggingHelperValue2Classic(const GdbResponse &response)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setWatchDataType(data, response.data.findChild("type"));
|
data.updateType(response.data.findChild("type"));
|
||||||
setWatchDataDisplayedType(data, response.data.findChild("displaytype"));
|
data.updateDisplayedType(response.data.findChild("displaytype"));
|
||||||
QList<WatchData> list;
|
QList<WatchData> list;
|
||||||
parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
|
parseWatchData(watchHandler()->expandedINames(), data, contents, &list);
|
||||||
//for (int i = 0; i != list.size(); ++i)
|
//for (int i = 0; i != list.size(); ++i)
|
||||||
@@ -1402,9 +1402,9 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
|
|||||||
data.name = _(exp);
|
data.name = _(exp);
|
||||||
data.iname = parent.iname + '.' + data.name.toLatin1();
|
data.iname = parent.iname + '.' + data.name.toLatin1();
|
||||||
data.variable = name;
|
data.variable = name;
|
||||||
setWatchDataType(data, item.findChild("type"));
|
data.updateType(item.findChild("type"));
|
||||||
setWatchDataValue(data, item);
|
data.updateValue(item);
|
||||||
setWatchDataAddress(data, item.findChild("addr"), GdbMi());
|
data.updateAddress(item.findChild("addr"), GdbMi());
|
||||||
data.setHasChildren(false);
|
data.setHasChildren(false);
|
||||||
insertData(data);
|
insertData(data);
|
||||||
} else if (parent.iname.endsWith('.')) {
|
} else if (parent.iname.endsWith('.')) {
|
||||||
@@ -1426,10 +1426,10 @@ void GdbEngine::handleVarListChildrenHelperClassic(const GdbMi &item,
|
|||||||
data.iname = parent.iname + '.' + exp;
|
data.iname = parent.iname + '.' + exp;
|
||||||
data.variable = name;
|
data.variable = name;
|
||||||
data.sortId = sortId;
|
data.sortId = sortId;
|
||||||
setWatchDataType(data, item.findChild("type"));
|
data.updateType(item.findChild("type"));
|
||||||
setWatchDataValue(data, item);
|
data.updateValue(item);
|
||||||
setWatchDataAddress(data, item.findChild("addr"), GdbMi());
|
data.updateAddress(item.findChild("addr"), GdbMi());
|
||||||
setWatchDataChildCount(data, item.findChild("numchild"));
|
data.updateChildCount(item.findChild("numchild"));
|
||||||
if (!watchHandler()->isExpandedIName(data.iname))
|
if (!watchHandler()->isExpandedIName(data.iname))
|
||||||
data.setChildrenUnneeded();
|
data.setChildrenUnneeded();
|
||||||
|
|
||||||
@@ -1524,7 +1524,7 @@ void GdbEngine::handleEvaluateExpressionClassic(const GdbResponse &response)
|
|||||||
//if (col == 0)
|
//if (col == 0)
|
||||||
// data.name = response.data.findChild("value").data();
|
// data.name = response.data.findChild("value").data();
|
||||||
//else
|
//else
|
||||||
setWatchDataValue(data, response.data);
|
data.updateValue(response.data);
|
||||||
} else {
|
} else {
|
||||||
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
|
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4137,13 +4137,13 @@ void GdbEngine::handleVarCreate(const GdbResponse &response)
|
|||||||
//qDebug() << "HANDLE VARIABLE CREATION:" << data.toString();
|
//qDebug() << "HANDLE VARIABLE CREATION:" << data.toString();
|
||||||
if (response.resultClass == GdbResultDone) {
|
if (response.resultClass == GdbResultDone) {
|
||||||
data.variable = data.iname;
|
data.variable = data.iname;
|
||||||
setWatchDataType(data, response.data.findChild("type"));
|
data.updateType(response.data.findChild("type"));
|
||||||
if (watchHandler()->isExpandedIName(data.iname)
|
if (watchHandler()->isExpandedIName(data.iname)
|
||||||
&& !response.data.findChild("children").isValid())
|
&& !response.data.findChild("children").isValid())
|
||||||
data.setChildrenNeeded();
|
data.setChildrenNeeded();
|
||||||
else
|
else
|
||||||
data.setChildrenUnneeded();
|
data.setChildrenUnneeded();
|
||||||
setWatchDataChildCount(data, response.data.findChild("numchild"));
|
data.updateChildCount(response.data.findChild("numchild"));
|
||||||
insertData(data);
|
insertData(data);
|
||||||
} else {
|
} else {
|
||||||
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
|
data.setError(QString::fromLocal8Bit(response.data.findChild("msg").data()));
|
||||||
@@ -4210,7 +4210,7 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
|
|||||||
data.setError(WatchData::msgNotInScope());
|
data.setError(WatchData::msgNotInScope());
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
setWatchDataValue(data, item);
|
data.updateValue(item);
|
||||||
//: Type of local variable or parameter shadowed by another
|
//: Type of local variable or parameter shadowed by another
|
||||||
//: variable of the same name in a nested block.
|
//: variable of the same name in a nested block.
|
||||||
data.setType(GdbEngine::tr("<shadowed>").toUtf8());
|
data.setType(GdbEngine::tr("<shadowed>").toUtf8());
|
||||||
@@ -4223,13 +4223,13 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
|
|||||||
data.iname = "local." + name;
|
data.iname = "local." + name;
|
||||||
data.name = nam;
|
data.name = nam;
|
||||||
data.exp = name;
|
data.exp = name;
|
||||||
setWatchDataType(data, item.findChild("type"));
|
data.updateType(item.findChild("type"));
|
||||||
if (uninitializedVariables.contains(data.name)) {
|
if (uninitializedVariables.contains(data.name)) {
|
||||||
data.setError(WatchData::msgNotInScope());
|
data.setError(WatchData::msgNotInScope());
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
if (isSynchronous()) {
|
if (isSynchronous()) {
|
||||||
setWatchDataValue(data, item);
|
data.updateValue(item);
|
||||||
// We know that the complete list of children is
|
// We know that the complete list of children is
|
||||||
// somewhere in the response.
|
// somewhere in the response.
|
||||||
data.setChildrenUnneeded();
|
data.setChildrenUnneeded();
|
||||||
@@ -4237,7 +4237,7 @@ WatchData GdbEngine::localVariable(const GdbMi &item,
|
|||||||
// Set value only directly if it is simple enough, otherwise
|
// Set value only directly if it is simple enough, otherwise
|
||||||
// pass through the insertData() machinery.
|
// pass through the insertData() machinery.
|
||||||
if (isIntOrFloatType(data.type) || isPointerType(data.type))
|
if (isIntOrFloatType(data.type) || isPointerType(data.type))
|
||||||
setWatchDataValue(data, item);
|
data.updateValue(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!watchHandler()->isExpandedIName(data.iname))
|
if (!watchHandler()->isExpandedIName(data.iname))
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "watchdata.h"
|
#include "watchdata.h"
|
||||||
#include "watchutils.h"
|
#include "watchutils.h"
|
||||||
|
#include "debuggerprotocol.h"
|
||||||
|
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@@ -270,7 +271,7 @@ void WatchData::setType(const QByteArray &str, bool guessChildrenFromType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WatchData::setAddress(const quint64 &a)
|
void WatchData::updateAddress(const quint64 &a)
|
||||||
{
|
{
|
||||||
address = a;
|
address = a;
|
||||||
}
|
}
|
||||||
@@ -429,6 +430,276 @@ QByteArray WatchData::hexReferencingAddress() const
|
|||||||
return QByteArray();
|
return QByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Protocol convienience
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void WatchData::updateValue(const GdbMi &item)
|
||||||
|
{
|
||||||
|
GdbMi value = item.findChild("value");
|
||||||
|
if (value.isValid()) {
|
||||||
|
int encoding = item.findChild("valueencoded").data().toInt();
|
||||||
|
setValue(decodeData(value.data(), encoding));
|
||||||
|
} else {
|
||||||
|
setValueNeeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
||||||
|
int encoding)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
data.setValueToolTip(decodeData(mi.data(), encoding));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::updateChildCount(const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
setHasChildren(mi.data().toInt() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.data() == "true")
|
||||||
|
data.valueEnabled = true;
|
||||||
|
else if (mi.data() == "false")
|
||||||
|
data.valueEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.data() == "true")
|
||||||
|
data.valueEditable = true;
|
||||||
|
else if (mi.data() == "false")
|
||||||
|
data.valueEditable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid())
|
||||||
|
data.exp = mi.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setWatchDataAddress(WatchData &data, quint64 address, quint64 origAddress = 0)
|
||||||
|
{
|
||||||
|
if (origAddress) { // Gdb dumpers reports the dereferenced address as origAddress
|
||||||
|
data.address = origAddress;
|
||||||
|
data.referencingAddress = address;
|
||||||
|
} else {
|
||||||
|
data.address = address;
|
||||||
|
}
|
||||||
|
if (data.exp.isEmpty() && !data.dumperFlags.startsWith('$')) {
|
||||||
|
if (data.iname.startsWith("local.") && data.iname.count('.') == 1)
|
||||||
|
// Solve one common case of adding 'class' in
|
||||||
|
// *(class X*)0xdeadbeef for gdb.
|
||||||
|
data.exp = data.name.toLatin1();
|
||||||
|
else
|
||||||
|
data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::updateAddress(const GdbMi &addressMi, const GdbMi &origAddressMi)
|
||||||
|
{
|
||||||
|
if (!addressMi.isValid())
|
||||||
|
return;
|
||||||
|
const QByteArray addressBA = addressMi.data();
|
||||||
|
if (!addressBA.startsWith("0x")) { // Item model dumpers pull tricks.
|
||||||
|
dumperFlags = addressBA;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const quint64 address = addressMi.toAddress();
|
||||||
|
const quint64 origAddress = origAddressMi.toAddress();
|
||||||
|
setWatchDataAddress(*this, address, origAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setWatchDataSize(WatchData &data, const GdbMi &mi)
|
||||||
|
{
|
||||||
|
if (mi.isValid()) {
|
||||||
|
bool ok = false;
|
||||||
|
const unsigned size = mi.data().toUInt(&ok);
|
||||||
|
if (ok)
|
||||||
|
data.size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the "type" and "displayedtype" children of root and set up type.
|
||||||
|
void WatchData::updateType(const GdbMi &item)
|
||||||
|
{
|
||||||
|
if (item.isValid())
|
||||||
|
setType(item.data());
|
||||||
|
else if (type.isEmpty())
|
||||||
|
setTypeNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WatchData::updateDisplayedType(const GdbMi &item)
|
||||||
|
{
|
||||||
|
if (item.isValid())
|
||||||
|
displayedType = QString::fromLatin1(item.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Utilities to decode string data returned by the dumper helpers.
|
||||||
|
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void decodeArrayHelper(QList<WatchData> *list, const WatchData &tmplate,
|
||||||
|
const QByteArray &rawData)
|
||||||
|
{
|
||||||
|
const QByteArray ba = QByteArray::fromHex(rawData);
|
||||||
|
const T *p = (const T *) ba.data();
|
||||||
|
WatchData data;
|
||||||
|
const QByteArray exp = "*(" + gdbQuoteTypes(tmplate.type) + "*)0x";
|
||||||
|
for (int i = 0, n = ba.size() / sizeof(T); i < n; ++i) {
|
||||||
|
data = tmplate;
|
||||||
|
data.sortId = i;
|
||||||
|
data.iname += QByteArray::number(i);
|
||||||
|
data.name = QString::fromLatin1("[%1]").arg(i);
|
||||||
|
data.value = QString::number(p[i]);
|
||||||
|
data.address += i * sizeof(T);
|
||||||
|
data.exp = exp + QByteArray::number(data.address, 16);
|
||||||
|
data.setAllUnneeded();
|
||||||
|
list->append(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decodeArray(QList<WatchData> *list, const WatchData &tmplate,
|
||||||
|
const QByteArray &rawData, int encoding)
|
||||||
|
{
|
||||||
|
switch (encoding) {
|
||||||
|
case Hex2EncodedInt1:
|
||||||
|
decodeArrayHelper<signed char>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt2:
|
||||||
|
decodeArrayHelper<short>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt4:
|
||||||
|
decodeArrayHelper<int>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedInt8:
|
||||||
|
decodeArrayHelper<qint64>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt1:
|
||||||
|
decodeArrayHelper<uchar>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt2:
|
||||||
|
decodeArrayHelper<ushort>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt4:
|
||||||
|
decodeArrayHelper<uint>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedUInt8:
|
||||||
|
decodeArrayHelper<quint64>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedFloat4:
|
||||||
|
decodeArrayHelper<float>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
case Hex2EncodedFloat8:
|
||||||
|
decodeArrayHelper<double>(list, tmplate, rawData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qDebug() << "ENCODING ERROR: " << encoding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
||||||
|
const WatchData &data0, const GdbMi &item,
|
||||||
|
QList<WatchData> *list)
|
||||||
|
{
|
||||||
|
//qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
|
||||||
|
WatchData data = data0;
|
||||||
|
bool isExpanded = expandedINames.contains(data.iname);
|
||||||
|
if (!isExpanded)
|
||||||
|
data.setChildrenUnneeded();
|
||||||
|
|
||||||
|
GdbMi children = item.findChild("children");
|
||||||
|
if (children.isValid() || !isExpanded)
|
||||||
|
data.setChildrenUnneeded();
|
||||||
|
|
||||||
|
data.updateType(item.findChild("type"));
|
||||||
|
GdbMi mi = item.findChild("editvalue");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.editvalue = mi.data();
|
||||||
|
mi = item.findChild("editformat");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.editformat = mi.data().toInt();
|
||||||
|
mi = item.findChild("typeformats");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.typeFormats = QString::fromUtf8(mi.data());
|
||||||
|
mi = item.findChild("bitpos");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.bitpos = mi.data().toInt();
|
||||||
|
mi = item.findChild("bitsize");
|
||||||
|
if (mi.isValid())
|
||||||
|
data.bitsize = mi.data().toInt();
|
||||||
|
|
||||||
|
data.updateValue(item);
|
||||||
|
data.updateAddress(item.findChild("addr"), item.findChild("origaddr"));
|
||||||
|
setWatchDataSize(data, item.findChild("size"));
|
||||||
|
setWatchDataExpression(data, item.findChild("exp"));
|
||||||
|
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
||||||
|
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
||||||
|
data.updateChildCount(item.findChild("numchild"));
|
||||||
|
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
|
||||||
|
list->append(data);
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
qulonglong addressBase = item.findChild("addrbase").data().toULongLong(&ok, 0);
|
||||||
|
qulonglong addressStep = item.findChild("addrstep").data().toULongLong(&ok, 0);
|
||||||
|
|
||||||
|
// Try not to repeat data too often.
|
||||||
|
WatchData childtemplate;
|
||||||
|
childtemplate.updateType(item.findChild("childtype"));
|
||||||
|
childtemplate.updateChildCount(item.findChild("childnumchild"));
|
||||||
|
//qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
|
||||||
|
|
||||||
|
mi = item.findChild("arraydata");
|
||||||
|
if (mi.isValid()) {
|
||||||
|
int encoding = item.findChild("arrayencoding").data().toInt();
|
||||||
|
childtemplate.iname = data.iname + '.';
|
||||||
|
childtemplate.address = addressBase;
|
||||||
|
decodeArray(list, childtemplate, mi.data(), encoding);
|
||||||
|
} else {
|
||||||
|
for (int i = 0, n = children.children().size(); i != n; ++i) {
|
||||||
|
const GdbMi &child = children.children().at(i);
|
||||||
|
WatchData data1 = childtemplate;
|
||||||
|
data1.sortId = i;
|
||||||
|
GdbMi name = child.findChild("name");
|
||||||
|
if (name.isValid())
|
||||||
|
data1.name = QString::fromLatin1(name.data());
|
||||||
|
else
|
||||||
|
data1.name = QString::number(i);
|
||||||
|
GdbMi iname = child.findChild("iname");
|
||||||
|
if (iname.isValid()) {
|
||||||
|
data1.iname = iname.data();
|
||||||
|
} else {
|
||||||
|
data1.iname = data.iname;
|
||||||
|
data1.iname += '.';
|
||||||
|
data1.iname += data1.name.toLatin1();
|
||||||
|
}
|
||||||
|
if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
|
||||||
|
data1.name = QLatin1Char('[') + data1.name + QLatin1Char(']');
|
||||||
|
if (addressStep) {
|
||||||
|
setWatchDataAddress(data1, addressBase);
|
||||||
|
addressBase += addressStep;
|
||||||
|
}
|
||||||
|
QByteArray key = child.findChild("key").data();
|
||||||
|
if (!key.isEmpty()) {
|
||||||
|
int encoding = child.findChild("keyencoded").data().toInt();
|
||||||
|
QString skey = decodeData(key, encoding);
|
||||||
|
if (skey.size() > 13) {
|
||||||
|
skey = skey.left(12);
|
||||||
|
skey += QLatin1String("...");
|
||||||
|
}
|
||||||
|
//data1.name += " (" + skey + ")";
|
||||||
|
data1.name = skey;
|
||||||
|
}
|
||||||
|
parseWatchData(expandedINames, data1, child, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class GdbMi;
|
||||||
|
|
||||||
class WatchData
|
class WatchData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -99,7 +101,7 @@ public:
|
|||||||
void setValue(const QString &);
|
void setValue(const QString &);
|
||||||
void setValueToolTip(const QString &);
|
void setValueToolTip(const QString &);
|
||||||
void setType(const QByteArray &, bool guessChildrenFromType = true);
|
void setType(const QByteArray &, bool guessChildrenFromType = true);
|
||||||
void setAddress(const quint64 &);
|
void updateAddress(const quint64 &);
|
||||||
void setHexAddress(const QByteArray &a);
|
void setHexAddress(const QByteArray &a);
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
@@ -113,6 +115,13 @@ public:
|
|||||||
QByteArray hexAddress() const;
|
QByteArray hexAddress() const;
|
||||||
QByteArray hexReferencingAddress() const;
|
QByteArray hexReferencingAddress() const;
|
||||||
|
|
||||||
|
// Protocol interaction.
|
||||||
|
void updateValue(const GdbMi &item);
|
||||||
|
void updateChildCount(const GdbMi &mi);
|
||||||
|
void updateAddress(const GdbMi &addressMi, const GdbMi &origAddressMi);
|
||||||
|
void updateType(const GdbMi &item);
|
||||||
|
void updateDisplayedType(const GdbMi &item);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
quint64 id; // Token for the engine for internal mapping
|
quint64 id; // Token for the engine for internal mapping
|
||||||
qint32 state; // 'needed' flags;
|
qint32 state; // 'needed' flags;
|
||||||
@@ -146,6 +155,10 @@ public:
|
|||||||
qint32 source; // Originated from dumper or symbol evaluation? (CDB only)
|
qint32 source; // Originated from dumper or symbol evaluation? (CDB only)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
||||||
|
const WatchData &parent, const GdbMi &child,
|
||||||
|
QList<WatchData> *insertions);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
@@ -327,274 +327,6 @@ QByteArray gdbQuoteTypes(const QByteArray &type)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utilities to decode string data returned by the dumper helpers.
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
void decodeArrayHelper(QList<WatchData> *list, const WatchData &tmplate,
|
|
||||||
const QByteArray &rawData)
|
|
||||||
{
|
|
||||||
const QByteArray ba = QByteArray::fromHex(rawData);
|
|
||||||
const T *p = (const T *) ba.data();
|
|
||||||
WatchData data;
|
|
||||||
const QByteArray exp = "*(" + gdbQuoteTypes(tmplate.type) + "*)0x";
|
|
||||||
for (int i = 0, n = ba.size() / sizeof(T); i < n; ++i) {
|
|
||||||
data = tmplate;
|
|
||||||
data.sortId = i;
|
|
||||||
data.iname += QByteArray::number(i);
|
|
||||||
data.name = QString::fromLatin1("[%1]").arg(i);
|
|
||||||
data.value = QString::number(p[i]);
|
|
||||||
data.address += i * sizeof(T);
|
|
||||||
data.exp = exp + QByteArray::number(data.address, 16);
|
|
||||||
data.setAllUnneeded();
|
|
||||||
list->append(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void decodeArray(QList<WatchData> *list, const WatchData &tmplate,
|
|
||||||
const QByteArray &rawData, int encoding)
|
|
||||||
{
|
|
||||||
switch (encoding) {
|
|
||||||
case Hex2EncodedInt1:
|
|
||||||
decodeArrayHelper<signed char>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedInt2:
|
|
||||||
decodeArrayHelper<short>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedInt4:
|
|
||||||
decodeArrayHelper<int>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedInt8:
|
|
||||||
decodeArrayHelper<qint64>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedUInt1:
|
|
||||||
decodeArrayHelper<uchar>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedUInt2:
|
|
||||||
decodeArrayHelper<ushort>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedUInt4:
|
|
||||||
decodeArrayHelper<uint>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedUInt8:
|
|
||||||
decodeArrayHelper<quint64>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedFloat4:
|
|
||||||
decodeArrayHelper<float>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
case Hex2EncodedFloat8:
|
|
||||||
decodeArrayHelper<double>(list, tmplate, rawData);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qDebug() << "ENCODING ERROR: " << encoding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// GdbMi interaction
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void setWatchDataValue(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
GdbMi value = item.findChild("value");
|
|
||||||
if (value.isValid()) {
|
|
||||||
int encoding = item.findChild("valueencoded").data().toInt();
|
|
||||||
data.setValue(decodeData(value.data(), encoding));
|
|
||||||
} else {
|
|
||||||
data.setValueNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
|
||||||
int encoding)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.setValueToolTip(decodeData(mi.data(), encoding));
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWatchDataChildCount(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.setHasChildren(mi.data().toInt() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.data() == "true")
|
|
||||||
data.valueEnabled = true;
|
|
||||||
else if (mi.data() == "false")
|
|
||||||
data.valueEnabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setWatchDataValueEditable(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.data() == "true")
|
|
||||||
data.valueEditable = true;
|
|
||||||
else if (mi.data() == "false")
|
|
||||||
data.valueEditable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setWatchDataExpression(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid())
|
|
||||||
data.exp = mi.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setWatchDataAddress(WatchData &data, quint64 address, quint64 origAddress = 0)
|
|
||||||
{
|
|
||||||
if (origAddress) { // Gdb dumpers reports the dereferenced address as origAddress
|
|
||||||
data.address = origAddress;
|
|
||||||
data.referencingAddress = address;
|
|
||||||
} else {
|
|
||||||
data.address = address;
|
|
||||||
}
|
|
||||||
if (data.exp.isEmpty() && !data.dumperFlags.startsWith('$')) {
|
|
||||||
if (data.iname.startsWith("local.") && data.iname.count('.') == 1)
|
|
||||||
// Solve one common case of adding 'class' in
|
|
||||||
// *(class X*)0xdeadbeef for gdb.
|
|
||||||
data.exp = data.name.toLatin1();
|
|
||||||
else
|
|
||||||
data.exp = "*(" + gdbQuoteTypes(data.type) + "*)" + data.hexAddress();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWatchDataAddress(WatchData &data, const GdbMi &addressMi, const GdbMi &origAddressMi)
|
|
||||||
{
|
|
||||||
if (!addressMi.isValid())
|
|
||||||
return;
|
|
||||||
const QByteArray addressBA = addressMi.data();
|
|
||||||
if (!addressBA.startsWith("0x")) { // Item model dumpers pull tricks.
|
|
||||||
data.dumperFlags = addressBA;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const quint64 address = addressMi.toAddress();
|
|
||||||
const quint64 origAddress = origAddressMi.toAddress();
|
|
||||||
setWatchDataAddress(data, address, origAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setWatchDataSize(WatchData &data, const GdbMi &mi)
|
|
||||||
{
|
|
||||||
if (mi.isValid()) {
|
|
||||||
bool ok = false;
|
|
||||||
const unsigned size = mi.data().toUInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
data.size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the "type" and "displayedtype" children of root and set up type.
|
|
||||||
void setWatchDataType(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
if (item.isValid())
|
|
||||||
data.setType(item.data());
|
|
||||||
else if (data.type.isEmpty())
|
|
||||||
data.setTypeNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWatchDataDisplayedType(WatchData &data, const GdbMi &item)
|
|
||||||
{
|
|
||||||
if (item.isValid())
|
|
||||||
data.displayedType = QString::fromLatin1(item.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
|
||||||
const WatchData &data0, const GdbMi &item,
|
|
||||||
QList<WatchData> *list)
|
|
||||||
{
|
|
||||||
//qDebug() << "HANDLE CHILDREN: " << data0.toString() << item.toString();
|
|
||||||
WatchData data = data0;
|
|
||||||
bool isExpanded = expandedINames.contains(data.iname);
|
|
||||||
if (!isExpanded)
|
|
||||||
data.setChildrenUnneeded();
|
|
||||||
|
|
||||||
GdbMi children = item.findChild("children");
|
|
||||||
if (children.isValid() || !isExpanded)
|
|
||||||
data.setChildrenUnneeded();
|
|
||||||
|
|
||||||
setWatchDataType(data, item.findChild("type"));
|
|
||||||
GdbMi mi = item.findChild("editvalue");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.editvalue = mi.data();
|
|
||||||
mi = item.findChild("editformat");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.editformat = mi.data().toInt();
|
|
||||||
mi = item.findChild("typeformats");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.typeFormats = QString::fromUtf8(mi.data());
|
|
||||||
mi = item.findChild("bitpos");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.bitpos = mi.data().toInt();
|
|
||||||
mi = item.findChild("bitsize");
|
|
||||||
if (mi.isValid())
|
|
||||||
data.bitsize = mi.data().toInt();
|
|
||||||
|
|
||||||
setWatchDataValue(data, item);
|
|
||||||
setWatchDataAddress(data, item.findChild("addr"), item.findChild("origaddr"));
|
|
||||||
setWatchDataSize(data, item.findChild("size"));
|
|
||||||
setWatchDataExpression(data, item.findChild("exp"));
|
|
||||||
setWatchDataValueEnabled(data, item.findChild("valueenabled"));
|
|
||||||
setWatchDataValueEditable(data, item.findChild("valueeditable"));
|
|
||||||
setWatchDataChildCount(data, item.findChild("numchild"));
|
|
||||||
//qDebug() << "\nAPPEND TO LIST: " << data.toString() << "\n";
|
|
||||||
list->append(data);
|
|
||||||
|
|
||||||
bool ok = false;
|
|
||||||
qulonglong addressBase = item.findChild("addrbase").data().toULongLong(&ok, 0);
|
|
||||||
qulonglong addressStep = item.findChild("addrstep").data().toULongLong(&ok, 0);
|
|
||||||
|
|
||||||
// Try not to repeat data too often.
|
|
||||||
WatchData childtemplate;
|
|
||||||
setWatchDataType(childtemplate, item.findChild("childtype"));
|
|
||||||
setWatchDataChildCount(childtemplate, item.findChild("childnumchild"));
|
|
||||||
//qDebug() << "CHILD TEMPLATE:" << childtemplate.toString();
|
|
||||||
|
|
||||||
mi = item.findChild("arraydata");
|
|
||||||
if (mi.isValid()) {
|
|
||||||
int encoding = item.findChild("arrayencoding").data().toInt();
|
|
||||||
childtemplate.iname = data.iname + '.';
|
|
||||||
childtemplate.address = addressBase;
|
|
||||||
decodeArray(list, childtemplate, mi.data(), encoding);
|
|
||||||
} else {
|
|
||||||
for (int i = 0, n = children.children().size(); i != n; ++i) {
|
|
||||||
const GdbMi &child = children.children().at(i);
|
|
||||||
WatchData data1 = childtemplate;
|
|
||||||
data1.sortId = i;
|
|
||||||
GdbMi name = child.findChild("name");
|
|
||||||
if (name.isValid())
|
|
||||||
data1.name = QString::fromLatin1(name.data());
|
|
||||||
else
|
|
||||||
data1.name = QString::number(i);
|
|
||||||
GdbMi iname = child.findChild("iname");
|
|
||||||
if (iname.isValid()) {
|
|
||||||
data1.iname = iname.data();
|
|
||||||
} else {
|
|
||||||
data1.iname = data.iname;
|
|
||||||
data1.iname += '.';
|
|
||||||
data1.iname += data1.name.toLatin1();
|
|
||||||
}
|
|
||||||
if (!data1.name.isEmpty() && data1.name.at(0).isDigit())
|
|
||||||
data1.name = QLatin1Char('[') + data1.name + QLatin1Char(']');
|
|
||||||
if (addressStep) {
|
|
||||||
setWatchDataAddress(data1, addressBase);
|
|
||||||
addressBase += addressStep;
|
|
||||||
}
|
|
||||||
QByteArray key = child.findChild("key").data();
|
|
||||||
if (!key.isEmpty()) {
|
|
||||||
int encoding = child.findChild("keyencoded").data().toInt();
|
|
||||||
QString skey = decodeData(key, encoding);
|
|
||||||
if (skey.size() > 13) {
|
|
||||||
skey = skey.left(12);
|
|
||||||
skey += QLatin1String("...");
|
|
||||||
}
|
|
||||||
//data1.name += " (" + skey + ")";
|
|
||||||
data1.name = skey;
|
|
||||||
}
|
|
||||||
parseWatchData(expandedINames, data1, child, list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|||||||
@@ -39,9 +39,6 @@
|
|||||||
namespace Debugger {
|
namespace Debugger {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class WatchData;
|
|
||||||
class GdbMi;
|
|
||||||
|
|
||||||
bool isSkippableFunction(const QString &funcName, const QString &fileName);
|
bool isSkippableFunction(const QString &funcName, const QString &fileName);
|
||||||
bool isLeavableFunction(const QString &funcName, const QString &fileName);
|
bool isLeavableFunction(const QString &funcName, const QString &fileName);
|
||||||
|
|
||||||
@@ -60,28 +57,6 @@ bool isIntType(const QByteArray &type);
|
|||||||
QString formatToolTipAddress(quint64 a);
|
QString formatToolTipAddress(quint64 a);
|
||||||
QString removeObviousSideEffects(const QString &exp);
|
QString removeObviousSideEffects(const QString &exp);
|
||||||
|
|
||||||
// Decode string data as returned by the dumper helpers.
|
|
||||||
void decodeArray(WatchData *list, const WatchData &tmplate,
|
|
||||||
const QByteArray &rawData, int encoding);
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// GdbMi interaction
|
|
||||||
//
|
|
||||||
|
|
||||||
void setWatchDataValue(WatchData &data, const GdbMi &item);
|
|
||||||
void setWatchDataValueToolTip(WatchData &data, const GdbMi &mi,
|
|
||||||
int encoding);
|
|
||||||
void setWatchDataChildCount(WatchData &data, const GdbMi &mi);
|
|
||||||
void setWatchDataValueEnabled(WatchData &data, const GdbMi &mi);
|
|
||||||
void setWatchDataAddress(WatchData &data, const GdbMi &addressMi, const GdbMi &origAddressMi);
|
|
||||||
void setWatchDataType(WatchData &data, const GdbMi &mi);
|
|
||||||
void setWatchDataDisplayedType(WatchData &data, const GdbMi &mi);
|
|
||||||
|
|
||||||
void parseWatchData(const QSet<QByteArray> &expandedINames,
|
|
||||||
const WatchData &parent, const GdbMi &child,
|
|
||||||
QList<WatchData> *insertions);
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Debugger
|
} // namespace Debugger
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user