Debugger: Replace cdb output encoding enum by strings

Change-Id: I05225f5be61fdaa448b9991b14056e89228c26a4
Reviewed-by: hjk <hjk@theqtcompany.com>
Reviewed-by: David Schulz <david.schulz@theqtcompany.com>
This commit is contained in:
hjk
2015-12-15 09:06:00 +01:00
parent 4996be216d
commit c8c6c8ec50
8 changed files with 106 additions and 133 deletions

View File

@@ -319,9 +319,7 @@ DumpParameters::FormatMap DumpParameters::decodeFormatArgument(const std::string
std::string::size_type nextPos = f.find(',', numberPos); std::string::size_type nextPos = f.find(',', numberPos);
if (nextPos == std::string::npos) if (nextPos == std::string::npos)
nextPos = size; nextPos = size;
int format; std::string format = f.substr(numberPos, nextPos - numberPos);
if (!integerFromString(f.substr(numberPos, nextPos - numberPos), &format))
return rc;
if (name == "std::basic_string") { // Python dumper naming convention for types if (name == "std::basic_string") { // Python dumper naming convention for types
rc.insert(FormatMap::value_type(stdStringTypeC, format)); rc.insert(FormatMap::value_type(stdStringTypeC, format));
rc.insert(FormatMap::value_type(stdWStringTypeC, format)); rc.insert(FormatMap::value_type(stdWStringTypeC, format));
@@ -334,7 +332,7 @@ DumpParameters::FormatMap DumpParameters::decodeFormatArgument(const std::string
return rc; 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()) { if (!individualFormats.empty()) {
const FormatMap::const_iterator iit = individualFormats.find(iname); 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()) if (tit != typeFormats.end())
return tit->second; 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 /* Recode arrays/pointers of char*, wchar_t according to users
* specification. Handles char formats for 'char *', '0x834478 "hallo.."' * specification. Handles char formats for 'char *', '0x834478 "hallo.."'
* and 'wchar_t *', '0x834478 "hallo.."', 'wchar_t[56] "hallo"', etc. * and 'wchar_t *', '0x834478 "hallo.."', 'wchar_t[56] "hallo"', etc.
@@ -440,19 +427,13 @@ DumpParameters::checkRecode(const std::string &type,
if (!length) if (!length)
return result; return result;
// Choose format // 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 '?'/'.' // The user did not specify any format, still, there are '?'/'.'
// (indicating non-printable) in what the debugger prints. // (indicating non-printable) in what the debugger prints.
// Reformat in this case. If there are no '?'-> all happy. // Reformat in this case. If there are no '?'-> all happy.
if (result.recommendedFormat < FormatLatin1String) { if (result.recommendedFormat.empty())
const bool hasNonPrintable = value.find(L'?', quote1 + 1) != std::wstring::npos result.recommendedFormat = "latin1";
|| 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;
}
// Get address from value if it is a pointer. // Get address from value if it is a pointer.
if (reformatType == ReformatPointer) { if (reformatType == ReformatPointer) {
address = 0; address = 0;
@@ -468,16 +449,6 @@ DumpParameters::checkRecode(const std::string &type,
if (!elementSize) if (!elementSize)
return result; return result;
result.size = length * elementSize; 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]; result.buffer = new unsigned char[result.size];
std::fill(result.buffer, result.buffer + result.size, 0); std::fill(result.buffer, result.buffer + result.size, 0);
ULONG obtained = 0; ULONG obtained = 0;
@@ -506,25 +477,8 @@ bool DumpParameters::recode(const std::string &type,
= checkRecode(type, iname, *value, ctx, address, this); = checkRecode(type, iname, *value, ctx, address, this);
if (!check.buffer) if (!check.buffer)
return false; return false;
// Recode raw memory *value = dataToHexW(check.buffer, check.buffer + check.size);
switch (check.recommendedFormat) { *encoding = 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;
}
delete [] check.buffer; delete [] check.buffer;
return true; return true;
} }
@@ -1138,8 +1092,8 @@ int SymbolGroupNode::dumpNode(std::ostream &str,
str << ",valueencoded=\"utf16:2:0\",value=\""; str << ",valueencoded=\"utf16:2:0\",value=\"";
hexEncode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t)); hexEncode(str, reinterpret_cast<const unsigned char *>(value.c_str()), value.size() * sizeof(wchar_t));
str << '"'; str << '"';
const int format = dumpParameters.format(t, aFullIName); const std::string &format = dumpParameters.format(t, aFullIName);
if (format > 0) if (!format.empty())
dumpEditValue(this, ctx, format, str); dumpEditValue(this, ctx, format, str);
} }
// Children: Dump all known non-obscured or subelements // Children: Dump all known non-obscured or subelements

View File

@@ -45,17 +45,15 @@ class MemoryHandle;
// Helper struct used for check results when recoding CDB char pointer output. // Helper struct used for check results when recoding CDB char pointer output.
struct DumpParameterRecodeResult struct DumpParameterRecodeResult
{ {
DumpParameterRecodeResult() : buffer(0), size(0), recommendedFormat(0),isWide(false) {} unsigned char *buffer = 0;
size_t size = 0;
unsigned char *buffer; std::string recommendedFormat;
size_t size; bool isWide = false;
int recommendedFormat;
bool isWide;
}; };
struct DumpParameters struct DumpParameters
{ {
typedef std::map<std::string, int> FormatMap; // type or iname to format typedef std::map<std::string, std::string> FormatMap; // type or iname to format
enum DumpFlags enum DumpFlags
{ {
DumpHumanReadable = 0x1, DumpHumanReadable = 0x1,
@@ -80,7 +78,7 @@ struct DumpParameters
const SymbolGroupValueContext &ctx, const SymbolGroupValueContext &ctx,
ULONG64 address, ULONG64 address,
std::wstring *value, std::string *encoding) const; 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; unsigned dumpFlags;
FormatMap typeFormats; FormatMap typeFormats;

View File

@@ -3047,55 +3047,27 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
return rc; 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=\"" str << "editformat=\"" << displayFormat << "\",editvalue=\""
<< mh->toHex() << "\","; << mh->toHex() << "\",";
} }
bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, void dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &,
int desiredFormat, std::ostream &str) 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) if (SymbolGroupValue::verbose)
DebugPrint() << __FUNCTION__ << ' ' << n->name() << '/' << desiredFormat; DebugPrint() << __FUNCTION__ << ' ' << n->name() << '/' << desiredFormat;
switch (n->dumperType()) { auto separatorPos = desiredFormat.find(':');
case KT_QString: if (separatorPos == std::string::npos)
case KT_StdWString: return;
if (desiredFormat == StringSeparateWindow)
if (const MemoryHandle *mh = n->memory()) if (desiredFormat.substr(separatorPos) != "separate")
formatEditValue(DisplayUtf16String, mh, str); return;
break;
case KT_QByteArray: if (const MemoryHandle *mh = n->memory())
case KT_StdString: formatEditValue(desiredFormat, mh, str);
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;
} }
// Dump of QByteArray: Display as an array of unsigned chars. // Dump of QByteArray: Display as an array of unsigned chars.

View File

@@ -255,8 +255,8 @@ unsigned dumpSimpleType(SymbolGroupNode *n, const SymbolGroupValueContext &ctx,
void **specialInfoIn = 0, void **specialInfoIn = 0,
MemoryHandle **memoryHandleIn = 0); MemoryHandle **memoryHandleIn = 0);
bool dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &, void dumpEditValue(const SymbolGroupNode *n, const SymbolGroupValueContext &,
int desiredFormat, std::ostream &str); const std::string &desiredFormat, std::ostream &str);
enum AssignEncoding enum AssignEncoding
{ {

View File

@@ -877,5 +877,27 @@ QString DebuggerEncoding::toString() const
return QString::fromLatin1("%1:%2:%3").arg(type).arg(size).arg(quotes); 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 Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -241,15 +241,24 @@ enum DisplayFormat
// They are never stored in settings. // They are never stored in settings.
// Keep in sync with dumper.py, symbolgroupvalue.cpp of CDB // Keep in sync with dumper.py, symbolgroupvalue.cpp of CDB
enum DebuggerDisplay class DebuggerDisplay
{ {
StopDisplay = 0, public:
DisplayImageData = 1, enum DisplayType {
DisplayUtf16String = 2, StopDisplay = 0,
DisplayImageFile = 3, DisplayImageData = 1,
DisplayLatin1String = 4, DisplayUtf16String = 2,
DisplayUtf8String = 5, DisplayImageFile = 3,
DisplayPlotData = 6 DisplayLatin1String = 4,
DisplayUtf8String = 5,
DisplayPlotData = 6
};
DebuggerDisplay() {}
DebuggerDisplay(const QByteArray &data);
DisplayType type = StopDisplay;
bool separate = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -110,7 +110,7 @@ bool isIntOrFloatType(const QByteArray &type)
WatchItem::WatchItem() : WatchItem::WatchItem() :
id(WatchItem::InvalidId), id(WatchItem::InvalidId),
state(InitialState), state(InitialState),
editformat(StopDisplay), editformat(),
address(0), address(0),
origaddr(0), origaddr(0),
size(0), size(0),
@@ -389,7 +389,7 @@ void WatchItem::parseHelper(const GdbMi &input)
setType(mi.data()); setType(mi.data());
editvalue = input["editvalue"].data(); editvalue = input["editvalue"].data();
editformat = DebuggerDisplay(input["editformat"].toInt()); editformat = DebuggerDisplay(input["editformat"].data());
editencoding = DebuggerEncoding(input["editencoding"].data()); editencoding = DebuggerEncoding(input["editencoding"].data());
mi = input["valueelided"]; mi = input["valueelided"];

View File

@@ -1466,16 +1466,16 @@ static void swapEndian(char *d, int nchar)
void WatchModel::showEditValue(const WatchItem *item) void WatchModel::showEditValue(const WatchItem *item)
{ {
const QByteArray key = item->address ? item->hexAddress() : item->iname; const QByteArray key = item->address ? item->hexAddress() : item->iname;
switch (item->editformat) { switch (item->editformat.type) {
case StopDisplay: case DebuggerDisplay::StopDisplay:
m_separatedView->removeObject(key); m_separatedView->removeObject(key);
break; break;
case DisplayImageData: case DebuggerDisplay::DisplayImageData:
case DisplayImageFile: { // QImage case DebuggerDisplay::DisplayImageFile: { // QImage
int width = 0, height = 0, nbytes = 0, format = 0; int width = 0, height = 0, nbytes = 0, format = 0;
QByteArray ba; QByteArray ba;
uchar *bits = 0; uchar *bits = 0;
if (item->editformat == DisplayImageData) { if (item->editformat.type == DebuggerDisplay::DisplayImageData) {
ba = QByteArray::fromHex(item->editvalue); ba = QByteArray::fromHex(item->editvalue);
QTC_ASSERT(ba.size() > 16, return); QTC_ASSERT(ba.size() > 16, return);
const int *header = (int *)(ba.data()); const int *header = (int *)(ba.data());
@@ -1486,7 +1486,7 @@ void WatchModel::showEditValue(const WatchItem *item)
height = header[1]; height = header[1];
nbytes = header[2]; nbytes = header[2];
format = header[3]; format = header[3];
} else if (item->editformat == DisplayImageFile) { } else if (item->editformat.type == DebuggerDisplay::DisplayImageFile) {
QTextStream ts(item->editvalue); QTextStream ts(item->editvalue);
QString fileName; QString fileName;
ts >> width >> height >> nbytes >> format >> fileName; ts >> width >> height >> nbytes >> format >> fileName;
@@ -1515,23 +1515,23 @@ void WatchModel::showEditValue(const WatchItem *item)
v->setImage(im); v->setImage(im);
break; break;
} }
case DisplayUtf16String: case DebuggerDisplay::DisplayUtf16String:
case DisplayLatin1String: case DebuggerDisplay::DisplayLatin1String:
case DisplayUtf8String: { // String data. case DebuggerDisplay::DisplayUtf8String: { // String data.
QByteArray ba = QByteArray::fromHex(item->editvalue); QByteArray ba = QByteArray::fromHex(item->editvalue);
QString str; QString str;
if (item->editformat == DisplayUtf16String) if (item->editformat.type == DebuggerDisplay::DisplayUtf16String)
str = QString::fromUtf16((ushort *)ba.constData(), ba.size()/2); 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()); 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()); str = QString::fromUtf8(ba.constData(), ba.size());
QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, item->name); QTextEdit *t = m_separatedView->prepareObject<QTextEdit>(key, item->name);
t->setProperty(INameProperty, item->iname); t->setProperty(INameProperty, item->iname);
t->setText(str); t->setText(str);
break; break;
} }
case DisplayPlotData: { // Plots case DebuggerDisplay::DisplayPlotData: { // Plots
std::vector<double> data; std::vector<double> data;
readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding); readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding);
PlotViewer *v = m_separatedView->prepareObject<PlotViewer>(key, item->name); PlotViewer *v = m_separatedView->prepareObject<PlotViewer>(key, item->name);
@@ -1540,7 +1540,7 @@ void WatchModel::showEditValue(const WatchItem *item)
break; break;
} }
default: default:
QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat); QTC_ASSERT(false, qDebug() << "Display format: " << item->editformat.type);
break; break;
} }
} }
@@ -1681,6 +1681,24 @@ QString WatchHandler::nameForFormat(int format)
return WatchModel::nameForFormat(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 WatchHandler::typeFormatRequests() const
{ {
QByteArray ba; QByteArray ba;
@@ -1692,7 +1710,7 @@ QByteArray WatchHandler::typeFormatRequests() const
if (format != AutomaticFormat) { if (format != AutomaticFormat) {
ba.append(it.key().toHex()); ba.append(it.key().toHex());
ba.append('='); ba.append('=');
ba.append(QByteArray::number(format)); ba.append(formatStringFromFormatCode(format));
ba.append(','); ba.append(',');
} }
} }
@@ -1712,7 +1730,7 @@ QByteArray WatchHandler::individualFormatRequests() const
if (format != AutomaticFormat) { if (format != AutomaticFormat) {
ba.append(it.key()); ba.append(it.key());
ba.append('='); ba.append('=');
ba.append(QByteArray::number(it.value())); ba.append(formatStringFromFormatCode(it.value()));
ba.append(','); ba.append(',');
} }
} }