forked from qt-creator/qt-creator
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:
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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"];
|
||||
|
@@ -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(',');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user