forked from qt-creator/qt-creator
Debugger[CDB]: Make Qt 5's QString/QByteArray editable.
Introduce struct & routine to return address data for QStrings/ QByteArray of versions 4,5 and use that. Change-Id: I0603d160561bd28ef13bf79739b44b8af439bd93 Reviewed-on: http://codereview.qt.nokia.com/1770 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
This commit is contained in:
@@ -1396,46 +1396,62 @@ void formatKnownTypeFlags(std::ostream &os, KnownType kt)
|
|||||||
os << " simple_dumper";
|
os << " simple_dumper";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper to read the Qt 5 data elements used for QString's
|
// Helper struct containing data Address and size/alloc information
|
||||||
* and QByteArray's. These element are in a storage pool
|
// from Qt's QString/QByteArray.
|
||||||
* and the data they point to are located at an offset behind
|
struct QtStringAddressData
|
||||||
* them. */
|
|
||||||
|
|
||||||
// Determine address and length of data from a QByteArrayData/QStringData.
|
|
||||||
template <typename CharType>
|
|
||||||
bool readQt5DataSizeAddress(const SymbolGroupValue &dV,
|
|
||||||
unsigned dataSize,
|
|
||||||
unsigned *arraySize,
|
|
||||||
ULONG64 *address)
|
|
||||||
{
|
{
|
||||||
*arraySize = 0;
|
QtStringAddressData() : address(0), size(0), allocated(0) {}
|
||||||
*address = dV.pointerValue();
|
|
||||||
if (!*address)
|
ULONG64 address;
|
||||||
return false;
|
unsigned size; // Size and allocated are in ushort for QString's.
|
||||||
|
unsigned allocated;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper to determine the location and size of the data of
|
||||||
|
* QStrings/QByteArrays for versions 4,5. In Qt 4, 'd' has a 'data'
|
||||||
|
* pointer. In Qt 5, the d-elements and the data are in a storage pool
|
||||||
|
* and the data are at an offset behind the d-structures. */
|
||||||
|
QtStringAddressData readQtStringAddressData(const SymbolGroupValue &dV,
|
||||||
|
int qtMajorVersion)
|
||||||
|
{
|
||||||
|
QtStringAddressData result;
|
||||||
const SymbolGroupValue sizeV = dV["size"];
|
const SymbolGroupValue sizeV = dV["size"];
|
||||||
const SymbolGroupValue offsetV = dV["offset"];
|
const SymbolGroupValue allocV = dV["alloc"];
|
||||||
if (!dataSize || !sizeV || !offsetV)
|
if (!sizeV || !allocV)
|
||||||
return false;
|
return QtStringAddressData();
|
||||||
*arraySize = sizeV.intValue();
|
result.size = sizeV.intValue();
|
||||||
*address += dataSize + offsetV.intValue() / sizeof(CharType);
|
result.allocated = allocV.intValue();
|
||||||
return true;
|
if (qtMajorVersion < 5) {
|
||||||
|
// Qt 4: Simple 'data' pointer.
|
||||||
|
result.address = dV["data"].pointerValue();
|
||||||
|
} else {
|
||||||
|
// Qt 5: Memory pool after the data element.
|
||||||
|
const SymbolGroupValue offsetV = dV["offset"];
|
||||||
|
const SymbolGroupValue arrayV = dV["d"];
|
||||||
|
if (!offsetV || !arrayV)
|
||||||
|
return QtStringAddressData();
|
||||||
|
int offset = offsetV.intValue();
|
||||||
|
if (arrayV.type().find("short") != std::string::npos)
|
||||||
|
offset /= sizeof(short); // QString: offset is in short[].
|
||||||
|
result.address = arrayV.address()
|
||||||
|
+ SymbolGroupValue::pointerDiffSize()
|
||||||
|
+ offset;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve data from a QByteArrayData/QStringData in desired type.
|
// Retrieve data from a QByteArrayData(char)/QStringData(wchar_t)
|
||||||
// For empty arrays, no data are allocated.
|
// in desired type. For empty arrays, no data are allocated.
|
||||||
template <typename CharType>
|
template <typename CharType>
|
||||||
bool readQt5Data(const SymbolGroupValue &dV,
|
bool readQt5StringData(const SymbolGroupValue &dV, int qtMajorVersion,
|
||||||
unsigned dSize,
|
bool zeroTerminated, unsigned sizeLimit,
|
||||||
bool zeroTerminated,
|
unsigned *fullSize, unsigned *arraySize,
|
||||||
unsigned sizeLimit,
|
CharType **array)
|
||||||
unsigned *fullSize,
|
|
||||||
unsigned *arraySize,
|
|
||||||
CharType **array)
|
|
||||||
{
|
{
|
||||||
*array = 0;
|
*array = 0;
|
||||||
*arraySize = *fullSize = 0;
|
QtStringAddressData data = readQtStringAddressData(dV, qtMajorVersion);
|
||||||
ULONG64 address = 0;
|
*arraySize = *fullSize = data.size;
|
||||||
if (!readQt5DataSizeAddress<CharType>(dV, dSize, fullSize, &address))
|
if (!data.address)
|
||||||
return false;
|
return false;
|
||||||
if (!*fullSize)
|
if (!*fullSize)
|
||||||
return true;
|
return true;
|
||||||
@@ -1445,7 +1461,7 @@ bool readQt5Data(const SymbolGroupValue &dV,
|
|||||||
sizeof(CharType) * (*arraySize + (zeroTerminated ? 1 : 0));
|
sizeof(CharType) * (*arraySize + (zeroTerminated ? 1 : 0));
|
||||||
unsigned char *memory =
|
unsigned char *memory =
|
||||||
SymbolGroupValue::readMemory(dV.context().dataspaces,
|
SymbolGroupValue::readMemory(dV.context().dataspaces,
|
||||||
address, memorySize);
|
data.address, memorySize);
|
||||||
if (!memory)
|
if (!memory)
|
||||||
return false;
|
return false;
|
||||||
*array = reinterpret_cast<CharType *>(memory);
|
*array = reinterpret_cast<CharType *>(memory);
|
||||||
@@ -1473,15 +1489,10 @@ static inline bool dumpQString(const SymbolGroupValue &v, std::wostream &str)
|
|||||||
|
|
||||||
} // Qt 4.
|
} // Qt 4.
|
||||||
|
|
||||||
// Qt 5: Data start at offset past the 'd' of type QStringData.
|
|
||||||
static const unsigned dataSize =
|
|
||||||
SymbolGroupValue::sizeOf(qtInfo.prependQtCoreModule("QStringData").c_str());
|
|
||||||
if (!dataSize)
|
|
||||||
return false;
|
|
||||||
wchar_t *memory;
|
wchar_t *memory;
|
||||||
unsigned fullSize;
|
unsigned fullSize;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if (!readQt5Data(dV, dataSize, true, 10240, &fullSize, &size, &memory))
|
if (!readQt5StringData(dV, qtInfo.version, true, 10240, &fullSize, &size, &memory))
|
||||||
return false;
|
return false;
|
||||||
if (size) {
|
if (size) {
|
||||||
str << L'"' << memory;
|
str << L'"' << memory;
|
||||||
@@ -1529,13 +1540,6 @@ static unsigned qByteArraySize(const SymbolGroupValueContext &ctx)
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the size of a Qt 5's QByteArrayData */
|
|
||||||
static unsigned q5ByteArrayDataSize(const SymbolGroupValueContext &ctx)
|
|
||||||
{
|
|
||||||
static const unsigned size = SymbolGroupValue::sizeOf(QtInfo::get(ctx).prependQtCoreModule("QByteArrayData").c_str());
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the size of a QAtomicInt */
|
/* Return the size of a QAtomicInt */
|
||||||
static unsigned qAtomicIntSize(const SymbolGroupValueContext &ctx)
|
static unsigned qAtomicIntSize(const SymbolGroupValueContext &ctx)
|
||||||
{
|
{
|
||||||
@@ -1564,7 +1568,7 @@ static inline bool dumpQByteArray(const SymbolGroupValue &v, std::wostream &str)
|
|||||||
char *memory;
|
char *memory;
|
||||||
unsigned fullSize;
|
unsigned fullSize;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if (!readQt5Data(dV, q5ByteArrayDataSize(v.context()), false, 10240, &fullSize, &size, &memory))
|
if (!readQt5StringData(dV, qtInfo.version, false, 10240, &fullSize, &size, &memory))
|
||||||
return false;
|
return false;
|
||||||
if (size) {
|
if (size) {
|
||||||
// Emulate CDB's behavior of replacing unprintable characters
|
// Emulate CDB's behavior of replacing unprintable characters
|
||||||
@@ -2391,8 +2395,9 @@ static inline std::vector<AbstractSymbolGroupNode *>
|
|||||||
unsigned size = 0;
|
unsigned size = 0;
|
||||||
ULONG64 address = 0;
|
ULONG64 address = 0;
|
||||||
if (QtInfo::get(ctx).version > 4) {
|
if (QtInfo::get(ctx).version > 4) {
|
||||||
readQt5DataSizeAddress<char>(dV, q5ByteArrayDataSize(ctx),
|
const QtStringAddressData data = readQtStringAddressData(dV, 5);
|
||||||
&size, &address);
|
size = data.size;
|
||||||
|
address = data.address;
|
||||||
} else {
|
} else {
|
||||||
size = dV["size"].intValue();
|
size = dV["size"].intValue();
|
||||||
address = dV["data"].pointerValue();
|
address = dV["data"].pointerValue();
|
||||||
@@ -2536,15 +2541,18 @@ static int assignQStringI(SymbolGroupNode *n, const char *className,
|
|||||||
SymbolGroupValue d = v["d"];
|
SymbolGroupValue d = v["d"];
|
||||||
if (!d)
|
if (!d)
|
||||||
return 1;
|
return 1;
|
||||||
|
const QtInfo &qtInfo = QtInfo::get(ctx);
|
||||||
// Check the size, re-allocate if required.
|
// Check the size, re-allocate if required.
|
||||||
const size_t allocated = d["alloc"].intValue();
|
const QtStringAddressData addressData = readQtStringAddressData(d, qtInfo.version);
|
||||||
const bool needRealloc = allocated < data.stringLength;
|
if (!addressData.address)
|
||||||
|
return 9;
|
||||||
|
const bool needRealloc = addressData.allocated < data.stringLength;
|
||||||
if (needRealloc) {
|
if (needRealloc) {
|
||||||
if (!doAlloc) // Calling re-alloc failed somehow.
|
if (!doAlloc) // Calling re-alloc failed somehow.
|
||||||
return 3;
|
return 3;
|
||||||
std::ostringstream callStr;
|
std::ostringstream callStr;
|
||||||
const std::string funcName
|
const std::string funcName
|
||||||
= QtInfo::get(ctx).prependQtCoreModule(std::string(className) + "::resize");
|
= qtInfo.prependQtCoreModule(std::string(className) + "::resize");
|
||||||
callStr << funcName << '(' << std::hex << std::showbase
|
callStr << funcName << '(' << std::hex << std::showbase
|
||||||
<< v.address() << ',' << data.stringLength << ')';
|
<< v.address() << ',' << data.stringLength << ')';
|
||||||
std::wstring wOutput;
|
std::wstring wOutput;
|
||||||
@@ -2553,11 +2561,9 @@ static int assignQStringI(SymbolGroupNode *n, const char *className,
|
|||||||
assignQStringI(n, className, data, ctx, false) : 5;
|
assignQStringI(n, className, data, ctx, false) : 5;
|
||||||
}
|
}
|
||||||
// Write data.
|
// Write data.
|
||||||
const ULONG64 address = d["data"].pointerValue();
|
|
||||||
if (!address)
|
|
||||||
return 9;
|
|
||||||
if (!SymbolGroupValue::writeMemory(v.context().dataspaces,
|
if (!SymbolGroupValue::writeMemory(v.context().dataspaces,
|
||||||
address, data.data, ULONG(data.dataLength)))
|
addressData.address, data.data,
|
||||||
|
ULONG(data.dataLength)))
|
||||||
return 11;
|
return 11;
|
||||||
// Correct size unless we re-allocated
|
// Correct size unless we re-allocated
|
||||||
if (!needRealloc) {
|
if (!needRealloc) {
|
||||||
|
|||||||
Reference in New Issue
Block a user