forked from qt-creator/qt-creator
Debugger[CDB]: Implement simple dumpers for further Qt types.
QFile/QFileInfo/QUrl: For those types, there is no symbolic information for their *Private classes. Poke around in raw memory do obtain some information. Move readMemory-utilities around.
This commit is contained in:
@@ -550,36 +550,10 @@ std::string gdbmiRegisters(CIDebugRegisters *regs,
|
|||||||
return str.str();
|
return str.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read memory and return allocated array
|
|
||||||
unsigned char *readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
|
||||||
std::string *errorMessage = 0)
|
|
||||||
{
|
|
||||||
unsigned char *buffer = new unsigned char[length];
|
|
||||||
std::fill(buffer, buffer + length, 0);
|
|
||||||
ULONG received = 0;
|
|
||||||
const HRESULT hr = ds->ReadVirtual(address, buffer, length, &received);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
delete [] buffer;
|
|
||||||
if (errorMessage) {
|
|
||||||
std::ostringstream estr;
|
|
||||||
estr << "Cannot read " << length << " bytes from " << address << ": "
|
|
||||||
<< msgDebugEngineComFailed("ReadVirtual", hr);
|
|
||||||
*errorMessage = estr.str();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (received < length && errorMessage) {
|
|
||||||
std::ostringstream estr;
|
|
||||||
estr << "Warning: Received only " << received << " bytes of " << length << " requested at " << address << '.';
|
|
||||||
*errorMessage = estr.str();
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
||||||
std::string *errorMessage /* = 0 */)
|
std::string *errorMessage /* = 0 */)
|
||||||
{
|
{
|
||||||
if (const unsigned char *buffer = readMemory(ds, address, length, errorMessage)) {
|
if (const unsigned char *buffer = SymbolGroupValue::readMemory(ds, address, length, errorMessage)) {
|
||||||
std::ostringstream str;
|
std::ostringstream str;
|
||||||
base64Encode(str, buffer, length);
|
base64Encode(str, buffer, length);
|
||||||
delete [] buffer;
|
delete [] buffer;
|
||||||
@@ -591,7 +565,7 @@ std::string memoryToBase64(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
|||||||
std::wstring memoryToHexW(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
std::wstring memoryToHexW(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
||||||
std::string *errorMessage /* = 0 */)
|
std::string *errorMessage /* = 0 */)
|
||||||
{
|
{
|
||||||
if (const unsigned char *buffer = readMemory(ds, address, length, errorMessage)) {
|
if (const unsigned char *buffer = SymbolGroupValue::readMemory(ds, address, length, errorMessage)) {
|
||||||
const std::wstring hex = dataToHexW(buffer, buffer + length);
|
const std::wstring hex = dataToHexW(buffer, buffer + length);
|
||||||
delete [] buffer;
|
delete [] buffer;
|
||||||
return hex;
|
return hex;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ enum KnownType
|
|||||||
KT_QSharedPointer = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22,
|
KT_QSharedPointer = KT_Qt_Type + KT_HasSimpleDumper + KT_HasComplexDumper + 22,
|
||||||
// Types: Various QT movable types
|
// Types: Various QT movable types
|
||||||
KT_QPen = KT_Qt_Type + KT_Qt_MovableType + 30,
|
KT_QPen = KT_Qt_Type + KT_Qt_MovableType + 30,
|
||||||
KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31,
|
KT_QUrl = KT_Qt_Type + KT_Qt_MovableType + 31 + KT_HasSimpleDumper,
|
||||||
KT_QIcon = KT_Qt_Type + KT_Qt_MovableType + 32,
|
KT_QIcon = KT_Qt_Type + KT_Qt_MovableType + 32,
|
||||||
KT_QBrush = KT_Qt_Type + KT_Qt_MovableType + 33,
|
KT_QBrush = KT_Qt_Type + KT_Qt_MovableType + 33,
|
||||||
KT_QImage = KT_Qt_Type + KT_Qt_MovableType + 35,
|
KT_QImage = KT_Qt_Type + KT_Qt_MovableType + 35,
|
||||||
@@ -91,7 +91,7 @@ enum KnownType
|
|||||||
KT_QXmlName = KT_Qt_Type + KT_Qt_MovableType + 41,
|
KT_QXmlName = KT_Qt_Type + KT_Qt_MovableType + 41,
|
||||||
KT_QBitArray = KT_Qt_Type + KT_Qt_MovableType + 42,
|
KT_QBitArray = KT_Qt_Type + KT_Qt_MovableType + 42,
|
||||||
KT_QDateTime = KT_Qt_Type + KT_Qt_MovableType + 43,
|
KT_QDateTime = KT_Qt_Type + KT_Qt_MovableType + 43,
|
||||||
KT_QFileInfo = KT_Qt_Type + KT_Qt_MovableType + 44,
|
KT_QFileInfo = KT_Qt_Type + KT_Qt_MovableType + KT_HasSimpleDumper + 44,
|
||||||
KT_QMetaEnum = KT_Qt_Type + KT_Qt_MovableType + 45,
|
KT_QMetaEnum = KT_Qt_Type + KT_Qt_MovableType + 45,
|
||||||
KT_QVector2D = KT_Qt_Type + KT_Qt_MovableType + 46,
|
KT_QVector2D = KT_Qt_Type + KT_Qt_MovableType + 46,
|
||||||
KT_QVector3D = KT_Qt_Type + KT_Qt_MovableType + 47,
|
KT_QVector3D = KT_Qt_Type + KT_Qt_MovableType + 47,
|
||||||
@@ -136,6 +136,7 @@ enum KnownType
|
|||||||
KT_QPatternist_ItemSequenceCacheCell = KT_Qt_Type + KT_Qt_MovableType + 86,
|
KT_QPatternist_ItemSequenceCacheCell = KT_Qt_Type + KT_Qt_MovableType + 86,
|
||||||
KT_QNetworkHeadersPrivate_RawHeaderPair = KT_Qt_Type + KT_Qt_MovableType + 87,
|
KT_QNetworkHeadersPrivate_RawHeaderPair = KT_Qt_Type + KT_Qt_MovableType + 87,
|
||||||
KT_QPatternist_AccelTree_BasicNodeData = KT_Qt_Type + KT_Qt_MovableType + 88,
|
KT_QPatternist_AccelTree_BasicNodeData = KT_Qt_Type + KT_Qt_MovableType + 88,
|
||||||
|
KT_QFile = KT_Qt_Type + KT_HasSimpleDumper + 89,
|
||||||
// Types: Qt primitive types
|
// Types: Qt primitive types
|
||||||
KT_QFixed = KT_Qt_Type + KT_Qt_PrimitiveType + 90,
|
KT_QFixed = KT_Qt_Type + KT_Qt_PrimitiveType + 90,
|
||||||
KT_QTextItem = KT_Qt_Type + KT_Qt_PrimitiveType + 91,
|
KT_QTextItem = KT_Qt_Type + KT_Qt_PrimitiveType + 91,
|
||||||
|
|||||||
@@ -218,21 +218,50 @@ ULONG64 SymbolGroupValue::pointerValue(ULONG64 defaultValue) const
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ULONG64 SymbolGroupValue::readPointerValue(CIDebugDataSpaces *ds, ULONG64 address,
|
||||||
|
std::string *errorMessage /* = 0 */)
|
||||||
|
{
|
||||||
|
ULONG64 v = 0;
|
||||||
|
if (const unsigned ps = SymbolGroupValue::pointerSize())
|
||||||
|
if (const unsigned char *buffer = SymbolGroupValue::readMemory(ds, address, ps, errorMessage)) {
|
||||||
|
memcpy(&v, buffer, ps);
|
||||||
|
delete [] buffer;
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read memory and return allocated array
|
||||||
|
unsigned char *SymbolGroupValue::readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
||||||
|
std::string *errorMessage /* = 0 */)
|
||||||
|
{
|
||||||
|
unsigned char *buffer = new unsigned char[length];
|
||||||
|
std::fill(buffer, buffer + length, 0);
|
||||||
|
ULONG received = 0;
|
||||||
|
const HRESULT hr = ds->ReadVirtual(address, buffer, length, &received);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
delete [] buffer;
|
||||||
|
if (errorMessage) {
|
||||||
|
std::ostringstream estr;
|
||||||
|
estr << "Cannot read " << length << " bytes from " << address << ": "
|
||||||
|
<< msgDebugEngineComFailed("ReadVirtual", hr);
|
||||||
|
*errorMessage = estr.str();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (received < length && errorMessage) {
|
||||||
|
std::ostringstream estr;
|
||||||
|
estr << "Warning: Received only " << received << " bytes of " << length << " requested at " << address << '.';
|
||||||
|
*errorMessage = estr.str();
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
// Return allocated array of data
|
// Return allocated array of data
|
||||||
unsigned char *SymbolGroupValue::pointerData(unsigned length) const
|
unsigned char *SymbolGroupValue::pointerData(unsigned length) const
|
||||||
{
|
{
|
||||||
if (isValid()) {
|
if (isValid())
|
||||||
if (const ULONG64 ptr = pointerValue()) {
|
if (const ULONG64 ptr = pointerValue())
|
||||||
unsigned char *data = new unsigned char[length];
|
return SymbolGroupValue::readMemory(m_context.dataspaces, ptr, length);
|
||||||
std::fill(data, data + length, 0);
|
|
||||||
const HRESULT hr = m_context.dataspaces->ReadVirtual(ptr, data, length, NULL);
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
delete [] data;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -993,6 +1022,8 @@ static KnownType knownClassTypeHelper(const std::string &type,
|
|||||||
return KT_QRect;
|
return KT_QRect;
|
||||||
if (!type.compare(qPos, 5, "QIcon"))
|
if (!type.compare(qPos, 5, "QIcon"))
|
||||||
return KT_QIcon;
|
return KT_QIcon;
|
||||||
|
if (!type.compare(qPos, 5, "QFile"))
|
||||||
|
return KT_QFile;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (!type.compare(qPos, 6, "QColor"))
|
if (!type.compare(qPos, 6, "QColor"))
|
||||||
@@ -1281,6 +1312,134 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pad a memory offset to align with pointer size */
|
||||||
|
static inline unsigned padOffset(unsigned offset)
|
||||||
|
{
|
||||||
|
const unsigned ps = SymbolGroupValue::pointerSize();
|
||||||
|
return (offset % ps) ? (1 + offset / ps) * ps : offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the offset to be accounted for "QSharedData" to access
|
||||||
|
* the first member of a QSharedData-derived class */
|
||||||
|
static unsigned qSharedDataOffset(const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
unsigned offset = 0;
|
||||||
|
if (!offset) {
|
||||||
|
// As of 4.X, a QAtomicInt, which will be padded to 8 on a 64bit system.
|
||||||
|
const std::string qSharedData = QtInfo::get(ctx).prependQtCoreModule("QSharedData");
|
||||||
|
offset = padOffset(SymbolGroupValue::sizeOf(qSharedData.c_str()));
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the size of a QString */
|
||||||
|
static unsigned qStringSize(const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
static const unsigned size = SymbolGroupValue::sizeOf(QtInfo::get(ctx).prependQtCoreModule("QString").c_str());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the size of a QByteArray */
|
||||||
|
static unsigned qByteArraySize(const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
static const unsigned size = SymbolGroupValue::sizeOf(QtInfo::get(ctx).prependQtCoreModule("QByteArray").c_str());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the size of a QAtomicInt */
|
||||||
|
static unsigned qAtomicIntSize(const SymbolGroupValueContext &ctx)
|
||||||
|
{
|
||||||
|
static const unsigned size = SymbolGroupValue::sizeOf(QtInfo::get(ctx).prependQtCoreModule("QAtomicInt").c_str());
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump a QByteArray
|
||||||
|
static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str)
|
||||||
|
{
|
||||||
|
// TODO: More sophisticated dumping of binary data?
|
||||||
|
if (const SymbolGroupValue data = v["d"]["data"]) {
|
||||||
|
str << data.value();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump QFileInfo: Works by poking around in raw memory: Dereference the d-ptr and
|
||||||
|
* obtain the QFileInfoPrivate. Access the right string past its QSharedData base class. */
|
||||||
|
static bool dumpQFileInfo(const SymbolGroupValue &v, std::wostream &str)
|
||||||
|
{
|
||||||
|
std::string errorMessage;
|
||||||
|
// Dererence d-Ptr.
|
||||||
|
const ULONG64 dptr = SymbolGroupValue::readPointerValue(v.context().dataspaces,
|
||||||
|
v.address(), &errorMessage);
|
||||||
|
if (!dptr)
|
||||||
|
return false;
|
||||||
|
// Get address of string, obtain value by dumping a QString at address
|
||||||
|
const ULONG64 stringAddress = dptr + qSharedDataOffset(v.context()) + qStringSize(v.context());
|
||||||
|
const std::string qStringType = QtInfo::get(v.context()).prependQtCoreModule("QString");
|
||||||
|
const std::string symbolName = SymbolGroupValue::pointedToSymbolName(stringAddress , qStringType);
|
||||||
|
SymbolGroupNode *fileNameNode =
|
||||||
|
v.node()->symbolGroup()->addSymbol(v.module(), symbolName, std::string(), &errorMessage);
|
||||||
|
if (!fileNameNode)
|
||||||
|
return false;
|
||||||
|
return dumpQString(SymbolGroupValue(fileNameNode, v.context()), str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump QFile: Works by poking around in raw memory: Dereference the d-ptr and
|
||||||
|
* obtain the QFilePrivate. Access the right string past its QIODevicePrivate base class. */
|
||||||
|
static bool dumpQFile(const SymbolGroupValue &v, std::wostream &str)
|
||||||
|
{
|
||||||
|
std::string errorMessage;
|
||||||
|
// Dererence d-Ptr (past virtual function table).
|
||||||
|
const ULONG64 dptr = SymbolGroupValue::readPointerValue(v.context().dataspaces,
|
||||||
|
v.address() + SymbolGroupValue::pointerSize(),
|
||||||
|
&errorMessage);
|
||||||
|
if (!dptr)
|
||||||
|
return false;
|
||||||
|
// Get address of the file name string, obtain value by dumping a QString at address
|
||||||
|
static unsigned qIoDevicePrivateSize = 0;
|
||||||
|
if (!qIoDevicePrivateSize) {
|
||||||
|
const std::string qIoDevicePrivateType = QtInfo::get(v.context()).prependQtCoreModule("QIODevicePrivate");
|
||||||
|
qIoDevicePrivateSize = padOffset(SymbolGroupValue::sizeOf(qIoDevicePrivateType.c_str()));
|
||||||
|
}
|
||||||
|
if (!qIoDevicePrivateSize)
|
||||||
|
return false;
|
||||||
|
const ULONG64 stringAddress = dptr + qIoDevicePrivateSize;
|
||||||
|
const std::string qStringType = QtInfo::get(v.context()).prependQtCoreModule("QString");
|
||||||
|
const std::string symbolName = SymbolGroupValue::pointedToSymbolName(stringAddress , qStringType);
|
||||||
|
SymbolGroupNode *fileNameNode =
|
||||||
|
v.node()->symbolGroup()->addSymbol(v.module(), symbolName, std::string(), &errorMessage);
|
||||||
|
if (!fileNameNode)
|
||||||
|
return false;
|
||||||
|
return dumpQString(SymbolGroupValue(fileNameNode, v.context()), str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump QUrl: Works by poking around in raw memory: Dereference the d-ptr and
|
||||||
|
* obtain the QUrlPrivate. Access the 'originally encoded' byte array. */
|
||||||
|
static bool dumpQUrl(const SymbolGroupValue &v, std::wostream &str, void **specialInfoIn)
|
||||||
|
{
|
||||||
|
std::string errorMessage;
|
||||||
|
// Dererence d-Ptr (past virtual function table).
|
||||||
|
const ULONG64 dptr = SymbolGroupValue::readPointerValue(v.context().dataspaces,
|
||||||
|
v.address(),
|
||||||
|
&errorMessage);
|
||||||
|
if (!dptr)
|
||||||
|
return false;
|
||||||
|
if (specialInfoIn)
|
||||||
|
*specialInfoIn = reinterpret_cast<void *>(intptr_t(dptr));
|
||||||
|
// Get address of the original-encoded byte array, obtain value by dumping at address
|
||||||
|
const ULONG64 origBA_Address = dptr + padOffset(qAtomicIntSize(v.context()))
|
||||||
|
+ 6 * qStringSize(v.context())
|
||||||
|
+ qByteArraySize(v.context());
|
||||||
|
const std::string qByteArrayType = QtInfo::get(v.context()).prependQtCoreModule("QByteArray");
|
||||||
|
const std::string symbolName = SymbolGroupValue::pointedToSymbolName(origBA_Address, qByteArrayType);
|
||||||
|
SymbolGroupNode *origEncodedBANode =
|
||||||
|
v.node()->symbolGroup()->addSymbol(v.module(), symbolName, std::string(), &errorMessage);
|
||||||
|
if (!origEncodedBANode)
|
||||||
|
return false;
|
||||||
|
return dumpQByteArray(SymbolGroupValue(origEncodedBANode, v.context()), str);
|
||||||
|
}
|
||||||
|
|
||||||
// Dump QColor
|
// Dump QColor
|
||||||
static bool dumpQColor(const SymbolGroupValue &v, std::wostream &str)
|
static bool dumpQColor(const SymbolGroupValue &v, std::wostream &str)
|
||||||
{
|
{
|
||||||
@@ -1396,17 +1555,6 @@ static bool dumpQTime(const SymbolGroupValue &v, std::wostream &str)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump a QByteArray
|
|
||||||
static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str)
|
|
||||||
{
|
|
||||||
// TODO: More sophisticated dumping of binary data?
|
|
||||||
if (const SymbolGroupValue data = v["d"]["data"]) {
|
|
||||||
str << data.value();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump a rectangle in X11 syntax
|
// Dump a rectangle in X11 syntax
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void dumpRect(std::wostream &str, T x, T y, T width, T height)
|
inline void dumpRect(std::wostream &str, T x, T y, T width, T height)
|
||||||
@@ -1796,6 +1944,15 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
|
|||||||
case KT_QByteArray:
|
case KT_QByteArray:
|
||||||
rc = dumpQByteArray(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
rc = dumpQByteArray(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
||||||
break;
|
break;
|
||||||
|
case KT_QFileInfo:
|
||||||
|
rc = dumpQFileInfo(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
||||||
|
break;
|
||||||
|
case KT_QFile:
|
||||||
|
rc = dumpQFile(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
||||||
|
break;
|
||||||
|
case KT_QUrl:
|
||||||
|
rc = dumpQUrl(v, str, specialInfoIn) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
||||||
|
break;
|
||||||
case KT_QString:
|
case KT_QString:
|
||||||
rc = dumpQString(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
rc = dumpQString(v, str) ? SymbolGroupNode::SimpleDumperOk : SymbolGroupNode::SimpleDumperFailed;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ public:
|
|||||||
const SymbolGroupValueContext &c,
|
const SymbolGroupValueContext &c,
|
||||||
std::string *errorMessage = 0);
|
std::string *errorMessage = 0);
|
||||||
|
|
||||||
|
static unsigned char *readMemory(CIDebugDataSpaces *ds, ULONG64 address, ULONG length,
|
||||||
|
std::string *errorMessage = 0);
|
||||||
|
static ULONG64 readPointerValue(CIDebugDataSpaces *ds, ULONG64 address,
|
||||||
|
std::string *errorMessage = 0);
|
||||||
|
|
||||||
static unsigned pointerSize();
|
static unsigned pointerSize();
|
||||||
static unsigned intSize();
|
static unsigned intSize();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user