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:
Friedemann Kleint
2011-07-18 15:12:29 +02:00
parent 2b59fceeea
commit a83d463fa5

View File

@@ -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 allocV = dV["alloc"];
if (!sizeV || !allocV)
return QtStringAddressData();
result.size = sizeV.intValue();
result.allocated = allocV.intValue();
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 offsetV = dV["offset"];
if (!dataSize || !sizeV || !offsetV) const SymbolGroupValue arrayV = dV["d"];
return false; if (!offsetV || !arrayV)
*arraySize = sizeV.intValue(); return QtStringAddressData();
*address += dataSize + offsetV.intValue() / sizeof(CharType); int offset = offsetV.intValue();
return true; 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,
unsigned *fullSize,
unsigned *arraySize,
CharType **array) 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) {