From c8c6c8ec50f3d9f18a55c26350a4e3f80117fd88 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 15 Dec 2015 09:06:00 +0100 Subject: [PATCH] Debugger: Replace cdb output encoding enum by strings Change-Id: I05225f5be61fdaa448b9991b14056e89228c26a4 Reviewed-by: hjk Reviewed-by: David Schulz --- src/libs/qtcreatorcdbext/symbolgroupnode.cpp | 68 +++---------------- src/libs/qtcreatorcdbext/symbolgroupnode.h | 14 ++-- src/libs/qtcreatorcdbext/symbolgroupvalue.cpp | 52 ++++---------- src/libs/qtcreatorcdbext/symbolgroupvalue.h | 4 +- src/plugins/debugger/debuggerprotocol.cpp | 22 ++++++ src/plugins/debugger/debuggerprotocol.h | 25 ++++--- src/plugins/debugger/watchdata.cpp | 4 +- src/plugins/debugger/watchhandler.cpp | 50 +++++++++----- 8 files changed, 106 insertions(+), 133 deletions(-) diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp index 637029cb4ae..19726dd14ed 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp @@ -319,9 +319,7 @@ DumpParameters::FormatMap DumpParameters::decodeFormatArgument(const std::string std::string::size_type nextPos = f.find(',', numberPos); if (nextPos == std::string::npos) nextPos = size; - int format; - if (!integerFromString(f.substr(numberPos, nextPos - numberPos), &format)) - return rc; + std::string format = f.substr(numberPos, nextPos - numberPos); if (name == "std::basic_string") { // Python dumper naming convention for types rc.insert(FormatMap::value_type(stdStringTypeC, format)); rc.insert(FormatMap::value_type(stdWStringTypeC, format)); @@ -334,7 +332,7 @@ DumpParameters::FormatMap DumpParameters::decodeFormatArgument(const std::string return rc; } -int DumpParameters::format(const std::string &type, const std::string &iname) const +std::string DumpParameters::format(const std::string &type, const std::string &iname) const { if (!individualFormats.empty()) { const FormatMap::const_iterator iit = individualFormats.find(iname); @@ -351,20 +349,9 @@ int DumpParameters::format(const std::string &type, const std::string &iname) co if (tit != typeFormats.end()) return tit->second; } - return -1; + return std::string(); } -// Watch data pointer format requests. This should match the values -// in DisplayFormat in watchhandler.h. -enum PointerFormats -{ - FormatAuto = 0, - FormatLatin1String = 101, - FormatUtf8String = 102, - FormatUtf16String = 104, - FormatUcs4String = 105 -}; - /* Recode arrays/pointers of char*, wchar_t according to users * specification. Handles char formats for 'char *', '0x834478 "hallo.."' * and 'wchar_t *', '0x834478 "hallo.."', 'wchar_t[56] "hallo"', etc. @@ -440,19 +427,13 @@ DumpParameters::checkRecode(const std::string &type, if (!length) return result; // Choose format - result.recommendedFormat = dp ? dp->format(type, iname) : FormatAuto; + if (dp) + result.recommendedFormat = dp->format(type, iname); // The user did not specify any format, still, there are '?'/'.' // (indicating non-printable) in what the debugger prints. // Reformat in this case. If there are no '?'-> all happy. - if (result.recommendedFormat < FormatLatin1String) { - const bool hasNonPrintable = value.find(L'?', quote1 + 1) != std::wstring::npos - || value.find(L'.', quote1 + 1) != std::wstring::npos; - if (!hasNonPrintable) - return result; // All happy, no need to re-encode - // Pass as on 8-bit such that Watchmodel's reformatting can trigger. - result.recommendedFormat = result.isWide ? - FormatUtf16String : FormatLatin1String; - } + if (result.recommendedFormat.empty()) + result.recommendedFormat = "latin1"; // Get address from value if it is a pointer. if (reformatType == ReformatPointer) { address = 0; @@ -468,16 +449,6 @@ DumpParameters::checkRecode(const std::string &type, if (!elementSize) return result; result.size = length * elementSize; - switch (result.recommendedFormat) { - case FormatUtf16String: // Paranoia: make sure buffer is terminated at 2 byte borders - if (result.size % 2) - result.size &= ~1; - break; - case FormatUcs4String: // Paranoia: make sure buffer is terminated at 4 byte borders - if (result.size % 4) - result.size &= ~3; - break; - } result.buffer = new unsigned char[result.size]; std::fill(result.buffer, result.buffer + result.size, 0); ULONG obtained = 0; @@ -506,25 +477,8 @@ bool DumpParameters::recode(const std::string &type, = checkRecode(type, iname, *value, ctx, address, this); if (!check.buffer) return false; - // Recode raw memory - switch (check.recommendedFormat) { - case FormatLatin1String: - *value = dataToHexW(check.buffer, check.buffer + check.size); // Latin1 + 0 - *encoding = "latin1"; - break; - case FormatUtf8String: - *value = dataToHexW(check.buffer, check.buffer + check.size); // UTF8 + 0 - *encoding = "utf8"; - break; - case FormatUtf16String: // Paranoia: make sure buffer is terminated at 2 byte borders - *value = dataToHexW(check.buffer, check.buffer + check.size); - *encoding = "utf16"; - break; - case FormatUcs4String: // Paranoia: make sure buffer is terminated at 4 byte borders - *value = dataToHexW(check.buffer, check.buffer + check.size); // UTF16 + 0 - *encoding = "ucs4"; - break; - } + *value = dataToHexW(check.buffer, check.buffer + check.size); + *encoding = check.recommendedFormat; delete [] check.buffer; return true; } @@ -1138,8 +1092,8 @@ int SymbolGroupNode::dumpNode(std::ostream &str, str << ",valueencoded=\"utf16:2:0\",value=\""; hexEncode(str, reinterpret_cast(value.c_str()), value.size() * sizeof(wchar_t)); str << '"'; - const int format = dumpParameters.format(t, aFullIName); - if (format > 0) + const std::string &format = dumpParameters.format(t, aFullIName); + if (!format.empty()) dumpEditValue(this, ctx, format, str); } // Children: Dump all known non-obscured or subelements diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h index cf4994fb112..a33ed89135b 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupnode.h +++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h @@ -45,17 +45,15 @@ class MemoryHandle; // Helper struct used for check results when recoding CDB char pointer output. struct DumpParameterRecodeResult { - DumpParameterRecodeResult() : buffer(0), size(0), recommendedFormat(0),isWide(false) {} - - unsigned char *buffer; - size_t size; - int recommendedFormat; - bool isWide; + unsigned char *buffer = 0; + size_t size = 0; + std::string recommendedFormat; + bool isWide = false; }; struct DumpParameters { - typedef std::map FormatMap; // type or iname to format + typedef std::map FormatMap; // type or iname to format enum DumpFlags { DumpHumanReadable = 0x1, @@ -80,7 +78,7 @@ struct DumpParameters const SymbolGroupValueContext &ctx, ULONG64 address, std::wstring *value, std::string *encoding) const; - int format(const std::string &type, const std::string &iname) const; + std::string format(const std::string &type, const std::string &iname) const; unsigned dumpFlags; FormatMap typeFormats; diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp index 5820647dca8..8f829cc2079 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp @@ -3047,55 +3047,27 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, return rc; } -static inline void formatEditValue(int displayFormat, const MemoryHandle *mh, std::ostream &str) +static inline void formatEditValue(const std::string &displayFormat, const MemoryHandle *mh, std::ostream &str) { str << "editformat=\"" << displayFormat << "\",editvalue=\"" << mh->toHex() << "\","; } -bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, - int desiredFormat, std::ostream &str) +void dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, + const std::string &desiredFormat, std::ostream &str) { - // Keep in sync watchhandler.cpp/showEditValue(), dumper.py. - enum DebuggerEditFormats { - DisplayImageData = 1, - DisplayUtf16String = 2, - DisplayImageFile = 3, - DisplayLatin1String = 4, - DisplayUtf8String = 5 - }; - - enum Formats { - NormalFormat = 0, - StringSeparateWindow = 1 // corresponds to menu index. - }; - - if (desiredFormat <= 0) - return true; - if (SymbolGroupValue::verbose) DebugPrint() << __FUNCTION__ << ' ' << n->name() << '/' << desiredFormat; - switch (n->dumperType()) { - case KT_QString: - case KT_StdWString: - if (desiredFormat == StringSeparateWindow) - if (const MemoryHandle *mh = n->memory()) - formatEditValue(DisplayUtf16String, mh, str); - break; - case KT_QByteArray: - case KT_StdString: - if (desiredFormat == StringSeparateWindow) - if (const MemoryHandle *mh = n->memory()) - formatEditValue(DisplayLatin1String, mh, str); - break; - case KT_QImage: - if (desiredFormat == 1) // Image. - if (const MemoryHandle *mh = n->memory()) - formatEditValue(DisplayImageData, mh, str); - break; - } - return true; + auto separatorPos = desiredFormat.find(':'); + if (separatorPos == std::string::npos) + return; + + if (desiredFormat.substr(separatorPos) != "separate") + return; + + if (const MemoryHandle *mh = n->memory()) + formatEditValue(desiredFormat, mh, str); } // Dump of QByteArray: Display as an array of unsigned chars. diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h index ad19aff641e..529f937e3b6 100644 --- a/src/libs/qtcreatorcdbext/symbolgroupvalue.h +++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h @@ -255,8 +255,8 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx, void **specialInfoIn = 0, MemoryHandle **memoryHandleIn = 0); -bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, - int desiredFormat, std::ostream &str); +void dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, + const std::string &desiredFormat, std::ostream &str); enum AssignEncoding { diff --git a/src/plugins/debugger/debuggerprotocol.cpp b/src/plugins/debugger/debuggerprotocol.cpp index b772452b77b..6bfd17f220e 100644 --- a/src/plugins/debugger/debuggerprotocol.cpp +++ b/src/plugins/debugger/debuggerprotocol.cpp @@ -877,5 +877,27 @@ QString DebuggerEncoding::toString() const return QString::fromLatin1("%1:%2:%3").arg(type).arg(size).arg(quotes); } +DebuggerDisplay::DebuggerDisplay(const QByteArray &data) +{ + const QByteArrayList l = data.split(':'); + + const QByteArray &t = l.at(0); + if (t == "latin1") { + type = DisplayLatin1String; + } else if (t == "utf8") { + type = DisplayUtf8String; + } else if (t == "utf16") { + type = DisplayUtf16String; + } else if (t == "imagedata") { + type = DisplayImageData; + } else if (t == "imagefile") { + type = DisplayImageFile; + } else if (t == "plot") { + type = DisplayPlotData; + } + if (l.size() > 1 && l.at(1) == "separate") + separate = true; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerprotocol.h b/src/plugins/debugger/debuggerprotocol.h index cc5c558a504..adea4b98e74 100644 --- a/src/plugins/debugger/debuggerprotocol.h +++ b/src/plugins/debugger/debuggerprotocol.h @@ -241,15 +241,24 @@ enum DisplayFormat // They are never stored in settings. // Keep in sync with dumper.py, symbolgroupvalue.cpp of CDB -enum DebuggerDisplay +class DebuggerDisplay { - StopDisplay = 0, - DisplayImageData = 1, - DisplayUtf16String = 2, - DisplayImageFile = 3, - DisplayLatin1String = 4, - DisplayUtf8String = 5, - DisplayPlotData = 6 +public: + enum DisplayType { + StopDisplay = 0, + DisplayImageData = 1, + DisplayUtf16String = 2, + DisplayImageFile = 3, + DisplayLatin1String = 4, + DisplayUtf8String = 5, + DisplayPlotData = 6 + }; + + DebuggerDisplay() {} + DebuggerDisplay(const QByteArray &data); + + DisplayType type = StopDisplay; + bool separate = false; }; } // namespace Internal diff --git a/src/plugins/debugger/watchdata.cpp b/src/plugins/debugger/watchdata.cpp index 96421d1bcf7..2be4a083b38 100644 --- a/src/plugins/debugger/watchdata.cpp +++ b/src/plugins/debugger/watchdata.cpp @@ -110,7 +110,7 @@ bool isIntOrFloatType(const QByteArray &type) WatchItem::WatchItem() : id(WatchItem::InvalidId), state(InitialState), - editformat(StopDisplay), + editformat(), address(0), origaddr(0), size(0), @@ -389,7 +389,7 @@ void WatchItem::parseHelper(const GdbMi &input) setType(mi.data()); editvalue = input["editvalue"].data(); - editformat = DebuggerDisplay(input["editformat"].toInt()); + editformat = DebuggerDisplay(input["editformat"].data()); editencoding = DebuggerEncoding(input["editencoding"].data()); mi = input["valueelided"]; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 4852bf1c978..c58f6ec0142 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -1466,16 +1466,16 @@ static void swapEndian(char *d, int nchar) void WatchModel::showEditValue(const WatchItem *item) { const QByteArray key = item->address ? item->hexAddress() : item->iname; - switch (item->editformat) { - case StopDisplay: + switch (item->editformat.type) { + case DebuggerDisplay::StopDisplay: m_separatedView->removeObject(key); break; - case DisplayImageData: - case DisplayImageFile: { // QImage + case DebuggerDisplay::DisplayImageData: + case DebuggerDisplay::DisplayImageFile: { // QImage int width = 0, height = 0, nbytes = 0, format = 0; QByteArray ba; uchar *bits = 0; - if (item->editformat == DisplayImageData) { + if (item->editformat.type == DebuggerDisplay::DisplayImageData) { ba = QByteArray::fromHex(item->editvalue); QTC_ASSERT(ba.size() > 16, return); const int *header = (int *)(ba.data()); @@ -1486,7 +1486,7 @@ void WatchModel::showEditValue(const WatchItem *item) height = header[1]; nbytes = header[2]; format = header[3]; - } else if (item->editformat == DisplayImageFile) { + } else if (item->editformat.type == DebuggerDisplay::DisplayImageFile) { QTextStream ts(item->editvalue); QString fileName; ts >> width >> height >> nbytes >> format >> fileName; @@ -1515,23 +1515,23 @@ void WatchModel::showEditValue(const WatchItem *item) v->setImage(im); break; } - case DisplayUtf16String: - case DisplayLatin1String: - case DisplayUtf8String: { // String data. + case DebuggerDisplay::DisplayUtf16String: + case DebuggerDisplay::DisplayLatin1String: + case DebuggerDisplay::DisplayUtf8String: { // String data. QByteArray ba = QByteArray::fromHex(item->editvalue); QString str; - if (item->editformat == DisplayUtf16String) + if (item->editformat.type == DebuggerDisplay::DisplayUtf16String) str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2); - else if (item->editformat == DisplayLatin1String) + else if (item->editformat.type == DebuggerDisplay::DisplayLatin1String) str = QString::fromLatin1(ba.constData(), ba.size()); - else if (item->editformat == DisplayUtf8String) + else if (item->editformat.type == DebuggerDisplay::DisplayUtf8String) str = QString::fromUtf8(ba.constData(), ba.size()); QTextEdit *t = m_separatedView->prepareObject(key, item->name); t->setProperty(INameProperty, item->iname); t->setText(str); break; } - case DisplayPlotData: { // Plots + case DebuggerDisplay::DisplayPlotData: { // Plots std::vector data; readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding); PlotViewer *v = m_separatedView->prepareObject(key, item->name); @@ -1540,7 +1540,7 @@ void WatchModel::showEditValue(const WatchItem *item) break; } default: - QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat); + QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat.type); break; } } @@ -1681,6 +1681,24 @@ QString WatchHandler::nameForFormat(int format) return WatchModel::nameForFormat(format); } +static const char *formatStringFromFormatCode(int code) +{ + switch (code) { + // Taken from debuggerprotocol.h, DisplayFormat. + case Latin1StringFormat: + return "latin"; + case SeparateLatin1StringFormat: + return "latin:separate"; + case Utf8StringFormat: + return "utf8"; + case SeparateUtf8StringFormat: + return "utf8:separate"; + case Utf16StringFormat: + return "utf16"; + } + return ""; +} + QByteArray WatchHandler::typeFormatRequests() const { QByteArray ba; @@ -1692,7 +1710,7 @@ QByteArray WatchHandler::typeFormatRequests() const if (format != AutomaticFormat) { ba.append(it.key().toHex()); ba.append('='); - ba.append(QByteArray::number(format)); + ba.append(formatStringFromFormatCode(format)); ba.append(','); } } @@ -1712,7 +1730,7 @@ QByteArray WatchHandler::individualFormatRequests() const if (format != AutomaticFormat) { ba.append(it.key()); ba.append('='); - ba.append(QByteArray::number(it.value())); + ba.append(formatStringFromFormatCode(it.value())); ba.append(','); } }