forked from qt-creator/qt-creator
Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
@@ -94,10 +94,10 @@ int qtGhVersion = QT_VERSION;
|
||||
\c{qDumpObjectData440()}.
|
||||
|
||||
In any case, dumper processesing should end up in
|
||||
\c{handleProtocolVersion2and3()} and needs an entry in the bis switch there.
|
||||
\c{handleProtocolVersion2and3()} and needs an entry in the big switch there.
|
||||
|
||||
Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
|
||||
function. At the bare minimum it should contain something like:
|
||||
function. At the bare minimum it should contain something like this:
|
||||
|
||||
|
||||
\c{
|
||||
@@ -127,7 +127,7 @@ int qtGhVersion = QT_VERSION;
|
||||
\endlist
|
||||
|
||||
If the current item has children, it might be queried to produce information
|
||||
about thes children. In this case the dumper should use something like
|
||||
about these children. In this case the dumper should use something like this:
|
||||
|
||||
\c{
|
||||
if (d.dumpChildren) {
|
||||
@@ -221,16 +221,19 @@ Q_DECL_EXPORT char qDumpOutBuffer[100000];
|
||||
|
||||
namespace {
|
||||
|
||||
static QByteArray strPtrConst = "* const";
|
||||
|
||||
static bool isPointerType(const QByteArray &type)
|
||||
{
|
||||
return type.endsWith("*") || type.endsWith("* const");
|
||||
return type.endsWith('*') || type.endsWith(strPtrConst);
|
||||
}
|
||||
|
||||
static QByteArray stripPointerType(QByteArray type)
|
||||
static QByteArray stripPointerType(const QByteArray &_type)
|
||||
{
|
||||
if (type.endsWith("*"))
|
||||
QByteArray type = _type;
|
||||
if (type.endsWith('*'))
|
||||
type.chop(1);
|
||||
if (type.endsWith("* const"))
|
||||
if (type.endsWith(strPtrConst))
|
||||
type.chop(7);
|
||||
if (type.endsWith(' '))
|
||||
type.chop(1);
|
||||
@@ -279,7 +282,10 @@ static bool isEqual(const char *s, const char *t)
|
||||
|
||||
static bool startsWith(const char *s, const char *t)
|
||||
{
|
||||
return qstrncmp(s, t, qstrlen(t)) == 0;
|
||||
while (char c = *t++)
|
||||
if (c != *s++)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check memory for read access and provoke segfault if nothing else helps.
|
||||
@@ -293,11 +299,18 @@ static bool startsWith(const char *s, const char *t)
|
||||
# define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef QT_NAMESPACE
|
||||
const char *stripNamespace(const char *type)
|
||||
{
|
||||
static const size_t nslen = qstrlen(NS);
|
||||
static const size_t nslen = strlen(NS);
|
||||
return startsWith(type, NS) ? type + nslen : type;
|
||||
}
|
||||
#else
|
||||
inline const char *stripNamespace(const char *type)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool isSimpleType(const char *type)
|
||||
{
|
||||
@@ -1168,7 +1181,7 @@ static void qDumpQHashNode(QDumper &d)
|
||||
|
||||
P(d, "numchild", 2);
|
||||
if (d.dumpChildren) {
|
||||
// there is a hash specialization in cast the key are integers or shorts
|
||||
// there is a hash specialization in case the keys are integers or shorts
|
||||
d << ",children=[";
|
||||
d.beginHash();
|
||||
P(d, "name", "key");
|
||||
@@ -2679,7 +2692,7 @@ void *qDumpObjectData440(
|
||||
|
||||
// This is a list of all available dumpers. Note that some templates
|
||||
// currently require special hardcoded handling in the debugger plugin.
|
||||
// They are mentioned here nevertheless. For types that not listed
|
||||
// They are mentioned here nevertheless. For types that are not listed
|
||||
// here, dumpers won't be used.
|
||||
d << "dumpers=["
|
||||
"\""NS"QByteArray\","
|
||||
|
||||
@@ -571,7 +571,7 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
|
||||
if (der == DumpExecuteSizeFailed)
|
||||
m_failedTypes.push_back(wd.type);
|
||||
// log error
|
||||
*errorMessage = *errorMessage = msgDumpFailed(wd, errorMessage);
|
||||
*errorMessage = msgDumpFailed(wd, errorMessage);
|
||||
m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
|
||||
return DumpError;
|
||||
}
|
||||
|
||||
@@ -1824,9 +1824,9 @@ void GdbEngine::sendInsertBreakpoint(int index)
|
||||
//if (where.isEmpty())
|
||||
// where = data->fileName;
|
||||
#endif
|
||||
// we need something like "\"file name.cpp\":100" to
|
||||
// survive the gdb command line parser with file names intact
|
||||
where = _("\"\\\"") + where + _("\\\":") + data->lineNumber + _c('"');
|
||||
// The argument is simply a C-quoted version of the argument to the
|
||||
// non-MI "break" command, including the "original" quoting it wants.
|
||||
where = _("\"\\\"") + GdbMi::escapeCString(where) + _("\\\":") + data->lineNumber + _c('"');
|
||||
} else {
|
||||
where = data->funcName;
|
||||
}
|
||||
@@ -1987,6 +1987,8 @@ void GdbEngine::handleBreakInsert(const GdbResultRecord &record, const QVariant
|
||||
handler->updateMarkers();
|
||||
} else if (record.resultClass == GdbResultError) {
|
||||
const BreakpointData *data = handler->at(index);
|
||||
// Note that it is perfectly correct that the file name is put
|
||||
// in quotes but not escaped. GDB simply is like that.
|
||||
#ifdef Q_OS_LINUX
|
||||
//QString where = "\"\\\"" + data->fileName + "\\\":"
|
||||
// + data->lineNumber + "\"";
|
||||
@@ -3098,8 +3100,7 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const
|
||||
QByteArray out = output.data();
|
||||
out = out.mid(out.indexOf('"') + 2); // + 1 is success marker
|
||||
out = out.left(out.lastIndexOf('"'));
|
||||
//out.replace('\'', '"');
|
||||
out.replace("\\", "");
|
||||
out.replace('\\', ""); // optimization: dumper output never needs real C unquoting
|
||||
out = "dummy={" + out + "}";
|
||||
//qDebug() << "OUTPUT: " << out;
|
||||
|
||||
@@ -3302,7 +3303,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record,
|
||||
QByteArray out = output.data();
|
||||
|
||||
int markerPos = out.indexOf('"') + 1; // position of 'success marker'
|
||||
if (markerPos == -1 || out.at(markerPos) == 'f') { // 't' or 'f'
|
||||
if (markerPos == 0 || out.at(markerPos) == 'f') { // 't' or 'f'
|
||||
// custom dumper produced no output
|
||||
data.setError(strNotInScope);
|
||||
insertData(data);
|
||||
@@ -3311,7 +3312,7 @@ void GdbEngine::handleDebuggingHelperValue2(const GdbResultRecord &record,
|
||||
|
||||
out = out.mid(markerPos + 1);
|
||||
out = out.left(out.lastIndexOf('"'));
|
||||
out.replace("\\", "");
|
||||
out.replace('\\', ""); // optimization: dumper output never needs real C unquoting
|
||||
out = "dummy={" + out + "}";
|
||||
|
||||
GdbMi contents;
|
||||
@@ -3848,13 +3849,13 @@ void GdbEngine::tryLoadDebuggingHelpers()
|
||||
execCommand(_("sharedlibrary .*")); // for LoadLibraryA
|
||||
//execCommand(_("handle SIGSEGV pass stop print"));
|
||||
//execCommand(_("set unwindonsignal off"));
|
||||
execCommand(_("call LoadLibraryA(\"") + lib + _("\")"),
|
||||
execCommand(_("call LoadLibraryA(\"") + GdbMi::escapeCString(lib) + _("\")"),
|
||||
CB(handleDebuggingHelperSetup));
|
||||
execCommand(_("sharedlibrary ") + dotEscape(lib));
|
||||
#elif defined(Q_OS_MAC)
|
||||
//execCommand(_("sharedlibrary libc")); // for malloc
|
||||
//execCommand(_("sharedlibrary libdl")); // for dlopen
|
||||
execCommand(_("call (void)dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
execCommand(_("call (void)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
CB(handleDebuggingHelperSetup));
|
||||
//execCommand(_("sharedlibrary ") + dotEscape(lib));
|
||||
m_debuggingHelperState = DebuggingHelperLoadTried;
|
||||
@@ -3863,10 +3864,10 @@ void GdbEngine::tryLoadDebuggingHelpers()
|
||||
QString flag = QString::number(RTLD_NOW);
|
||||
execCommand(_("sharedlibrary libc")); // for malloc
|
||||
execCommand(_("sharedlibrary libdl")); // for dlopen
|
||||
execCommand(_("call (void*)dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
execCommand(_("call (void*)dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
CB(handleDebuggingHelperSetup));
|
||||
// some older systems like CentOS 4.6 prefer this:
|
||||
execCommand(_("call (void*)__dlopen(\"") + lib + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
execCommand(_("call (void*)__dlopen(\"") + GdbMi::escapeCString(lib) + _("\", " STRINGIFY(RTLD_NOW) ")"),
|
||||
CB(handleDebuggingHelperSetup));
|
||||
execCommand(_("sharedlibrary ") + dotEscape(lib));
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
@@ -44,7 +46,7 @@ QTextStream &operator<<(QTextStream &os, const GdbMi &mi)
|
||||
|
||||
void GdbMi::parseResultOrValue(const char *&from, const char *to)
|
||||
{
|
||||
while (from != to && QChar(*from).isSpace())
|
||||
while (from != to && isspace(*from))
|
||||
++from;
|
||||
|
||||
//qDebug() << "parseResultOrValue: " << QByteArray(from, to - from);
|
||||
@@ -74,6 +76,7 @@ QByteArray GdbMi::parseCString(const char *&from, const char *to)
|
||||
//qDebug() << "parseCString: " << QByteArray::fromUtf16(from, to - from);
|
||||
if (*from != '"') {
|
||||
qDebug() << "MI Parse Error, double quote expected";
|
||||
++from; // So we don't hang
|
||||
return QByteArray();
|
||||
}
|
||||
const char *ptr = from;
|
||||
@@ -84,22 +87,66 @@ QByteArray GdbMi::parseCString(const char *&from, const char *to)
|
||||
result = QByteArray(from + 1, ptr - from - 2);
|
||||
break;
|
||||
}
|
||||
if (*ptr == '\\' && ptr < to - 1)
|
||||
if (*ptr == '\\') {
|
||||
++ptr;
|
||||
if (ptr == to) {
|
||||
qDebug() << "MI Parse Error, unterminated backslash escape";
|
||||
from = ptr; // So we don't hang
|
||||
return QByteArray();
|
||||
}
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
from = ptr;
|
||||
|
||||
if (result.contains('\\')) {
|
||||
if (result.contains("\\032\\032"))
|
||||
result.clear();
|
||||
else {
|
||||
result = result.replace("\\n", "\n");
|
||||
result = result.replace("\\t", "\t");
|
||||
result = result.replace("\\\"", "\"");
|
||||
}
|
||||
int idx = result.indexOf('\\');
|
||||
if (idx >= 0) {
|
||||
char *dst = result.data() + idx;
|
||||
const char *src = dst + 1, *end = result.data() + result.length();
|
||||
do {
|
||||
char c = *src++;
|
||||
switch (c) {
|
||||
case 'a': *dst++ = '\a'; break;
|
||||
case 'b': *dst++ = '\b'; break;
|
||||
case 'f': *dst++ = '\f'; break;
|
||||
case 'n': *dst++ = '\n'; break;
|
||||
case 'r': *dst++ = '\r'; break;
|
||||
case 't': *dst++ = '\t'; break;
|
||||
case 'v': *dst++ = '\v'; break;
|
||||
case '"': *dst++ = '"'; break;
|
||||
case '\\': *dst++ = '\\'; break;
|
||||
default:
|
||||
{
|
||||
int chars = 0;
|
||||
uchar prod = 0;
|
||||
forever {
|
||||
if (c < '0' || c > '7') {
|
||||
--src;
|
||||
break;
|
||||
}
|
||||
prod = prod * 8 + c - '0';
|
||||
if (++chars == 3 || src == end)
|
||||
break;
|
||||
c = *src++;
|
||||
}
|
||||
if (!chars) {
|
||||
qDebug() << "MI Parse Error, unrecognized backslash escape";
|
||||
return QByteArray();
|
||||
}
|
||||
*dst++ = prod;
|
||||
}
|
||||
}
|
||||
while (src != end) {
|
||||
char c = *src++;
|
||||
if (c == '\\')
|
||||
break;
|
||||
*dst++ = c;
|
||||
}
|
||||
} while (src != end);
|
||||
*dst = 0;
|
||||
result.truncate(dst - result.data());
|
||||
}
|
||||
|
||||
from = ptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -203,10 +250,50 @@ void GdbMi::dumpChildren(QByteArray * str, bool multiline, int indent) const
|
||||
}
|
||||
}
|
||||
|
||||
static QByteArray escaped(QByteArray ba)
|
||||
class MyString : public QString {
|
||||
public:
|
||||
ushort at(int i) const { return constData()[i].unicode(); }
|
||||
};
|
||||
|
||||
template<class ST, typename CT>
|
||||
inline ST escapeCStringTpl(const ST &ba)
|
||||
{
|
||||
ba.replace("\"", "\\\"");
|
||||
return ba;
|
||||
ST ret;
|
||||
ret.reserve(ba.length() * 2);
|
||||
for (int i = 0; i < ba.length(); ++i) {
|
||||
CT c = ba.at(i);
|
||||
switch (c) {
|
||||
case '\\': ret += "\\\\"; break;
|
||||
case '\a': ret += "\\a"; break;
|
||||
case '\b': ret += "\\b"; break;
|
||||
case '\f': ret += "\\f"; break;
|
||||
case '\n': ret += "\\n"; break;
|
||||
case '\r': ret += "\\r"; break;
|
||||
case '\t': ret += "\\t"; break;
|
||||
case '\v': ret += "\\v"; break;
|
||||
case '"': ret += "\\\""; break;
|
||||
default:
|
||||
if (c < 32 || c == 127) {
|
||||
ret += '\\';
|
||||
ret += '0' + (c >> 6);
|
||||
ret += '0' + ((c >> 3) & 7);
|
||||
ret += '0' + (c & 7);
|
||||
} else {
|
||||
ret += c;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString GdbMi::escapeCString(const QString &ba)
|
||||
{
|
||||
return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba));
|
||||
}
|
||||
|
||||
QByteArray GdbMi::escapeCString(const QByteArray &ba)
|
||||
{
|
||||
return escapeCStringTpl<QByteArray, uchar>(ba);
|
||||
}
|
||||
|
||||
QByteArray GdbMi::toString(bool multiline, int indent) const
|
||||
@@ -222,7 +309,7 @@ QByteArray GdbMi::toString(bool multiline, int indent) const
|
||||
case Const:
|
||||
if (!m_name.isEmpty())
|
||||
result += m_name + "=";
|
||||
result += "\"" + escaped(m_data) + "\"";
|
||||
result += "\"" + escapeCString(m_data) + "\"";
|
||||
break;
|
||||
case Tuple:
|
||||
if (!m_name.isEmpty())
|
||||
|
||||
@@ -132,6 +132,8 @@ private:
|
||||
friend class GdbEngine;
|
||||
|
||||
static QByteArray parseCString(const char *&from, const char *to);
|
||||
static QByteArray escapeCString(const QByteArray &ba);
|
||||
static QString escapeCString(const QString &ba);
|
||||
void parseResultOrValue(const char *&from, const char *to);
|
||||
void parseValue(const char *&from, const char *to);
|
||||
void parseTuple(const char *&from, const char *to);
|
||||
|
||||
@@ -136,6 +136,7 @@ bool hasSideEffects(const QString &exp)
|
||||
return exp.contains(QLatin1String("-="))
|
||||
|| exp.contains(QLatin1String("+="))
|
||||
|| exp.contains(QLatin1String("/="))
|
||||
|| exp.contains(QLatin1String("%="))
|
||||
|| exp.contains(QLatin1String("*="))
|
||||
|| exp.contains(QLatin1String("&="))
|
||||
|| exp.contains(QLatin1String("|="))
|
||||
|
||||
@@ -52,7 +52,7 @@ static const char test11[] =
|
||||
"{name=\"0\",value=\"one\",type=\"QByteArray\"}]";
|
||||
|
||||
static const char test12[] =
|
||||
"[{iname=\"local.hallo\",value=\"\\\"\\\"\",type=\"QByteArray\","
|
||||
"[{iname=\"local.hallo\",value=\"\\\"\\\\\\00382\\t\\377\",type=\"QByteArray\","
|
||||
"numchild=\"0\"}]";
|
||||
|
||||
class tst_Debugger : public QObject
|
||||
|
||||
Reference in New Issue
Block a user