Commit 6838223e authored by dt's avatar dt
Browse files

Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline

parents 3294f1f6 094c1bfc
......@@ -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)
{
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)
{
ba.replace("\"", "\\\"");
return 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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment