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);
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<const unsigned char *>(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

View File

@@ -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<std::string, int> FormatMap; // type or iname to format
typedef std::map<std::string, std::string> 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;

View File

@@ -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.

View File

@@ -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
{

View File

@@ -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

View File

@@ -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

View File

@@ -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"];

View File

@@ -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<QTextEdit>(key, item->name);
t->setProperty(INameProperty, item->iname);
t->setText(str);
break;
}
case DisplayPlotData: { // Plots
case DebuggerDisplay::DisplayPlotData: { // Plots
std::vector<double> data;
readNumericVector(&data, QByteArray::fromHex(item->editvalue), item->editencoding);
PlotViewer *v = m_separatedView->prepareObject<PlotViewer>(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(',');
}
}