RedPanda-CPP/RedPandaIDE/debugger/gdbmiresultparser.cpp

500 lines
13 KiB
C++
Raw Permalink Normal View History

2021-12-26 23:18:28 +08:00
/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2021-11-12 10:51:00 +08:00
#include "gdbmiresultparser.h"
2021-11-23 21:08:33 +08:00
#include <QFileInfo>
2021-11-12 10:51:00 +08:00
#include <QList>
2021-11-24 17:53:25 +08:00
#include <QDebug>
2021-11-12 10:51:00 +08:00
GDBMIResultParser::GDBMIResultParser()
{
mResultTypes.insert("-break-insert",GDBMIResultType::Breakpoint);
//mResultTypes.insert("BreakpointTable",GDBMIResultType::BreakpointTable);
mResultTypes.insert("-stack-list-frames",GDBMIResultType::FrameStack);
mResultTypes.insert("-stack-list-variables", GDBMIResultType::LocalVariables);
//mResultTypes.insert("frame",GDBMIResultType::Frame);
mResultTypes.insert("-data-disassemble",GDBMIResultType::Disassembly);
mResultTypes.insert("-data-evaluate-expression",GDBMIResultType::Evaluation);
// mResultTypes.insert("register-names",GDBMIResultType::RegisterNames);
// mResultTypes.insert("register-values",GDBMIResultType::RegisterValues);
mResultTypes.insert("-data-read-memory",GDBMIResultType::Memory);
mResultTypes.insert("-data-read-memory-bytes",GDBMIResultType::MemoryBytes);
2021-11-25 09:05:45 +08:00
mResultTypes.insert("-data-list-register-names",GDBMIResultType::RegisterNames);
mResultTypes.insert("-data-list-register-values",GDBMIResultType::RegisterValues);
2021-11-25 20:26:43 +08:00
mResultTypes.insert("-var-create",GDBMIResultType::CreateVar);
mResultTypes.insert("-var-list-children",GDBMIResultType::ListVarChildren);
mResultTypes.insert("-var-update",GDBMIResultType::UpdateVarValue);
mResultTypes.insert("-stack-info-frame",GDBMIResultType::Frame);
2021-11-12 22:42:51 +08:00
}
bool GDBMIResultParser::parse(const QByteArray &record, const QString& command, GDBMIResultType &type, ParseObject& multiValues)
2021-11-12 22:42:51 +08:00
{
const char* p = record.data();
bool result = parseMultiValues(p,multiValues);
2021-11-12 22:42:51 +08:00
if (!result)
return false;
// if (*p!=0)
// return false;
if (!mResultTypes.contains(command))
2021-11-12 22:42:51 +08:00
return false;
type = mResultTypes[command];
2021-11-12 22:42:51 +08:00
return true;
}
2021-11-21 10:36:50 +08:00
bool GDBMIResultParser::parseAsyncResult(const QByteArray &record, QByteArray &result, ParseObject &multiValue)
{
const char* p =record.data();
if (*p!='*')
return false;
p++;
2021-11-24 17:53:25 +08:00
const char* start=p;
2021-11-21 10:36:50 +08:00
while (*p && *p!=',')
p++;
result = QByteArray(start,p-start);
if (*p==0)
return true;
2021-11-24 17:53:25 +08:00
p++;
2021-11-21 10:36:50 +08:00
return parseMultiValues(p,multiValue);
}
bool GDBMIResultParser::parseMultiValues(const char* p, ParseObject &multiValue)
{
while (*p) {
QByteArray propName;
ParseValue propValue;
bool result = parseNameAndValue(p,propName,propValue);
if (result) {
multiValue[propName]=propValue;
} else {
return false;
}
skipSpaces(p);
2021-11-24 17:53:25 +08:00
if (*p==0)
break;
2021-11-21 10:36:50 +08:00
if (*p!=',')
return false;
p++; //skip ','
skipSpaces(p);
}
return true;
}
2021-11-13 11:16:05 +08:00
bool GDBMIResultParser::parseNameAndValue(const char *&p, QByteArray &name, ParseValue &value)
2021-11-12 22:42:51 +08:00
{
skipSpaces(p);
2021-11-13 11:16:05 +08:00
const char* nameStart =p;
2021-11-12 22:42:51 +08:00
while (*p!=0 && isNameChar(*p)) {
p++;
}
if (*p==0)
return false;
2021-11-13 11:16:05 +08:00
name = QByteArray(nameStart,p-nameStart);
2021-11-12 22:42:51 +08:00
skipSpaces(p);
if (*p!='=')
return false;
2021-11-24 17:53:25 +08:00
p++;
2021-11-12 22:42:51 +08:00
return parseValue(p,value);
}
2021-11-13 11:16:05 +08:00
bool GDBMIResultParser::parseValue(const char *&p, ParseValue &value)
2021-11-12 22:42:51 +08:00
{
skipSpaces(p);
bool result;
switch (*p) {
case '{': {
ParseObject obj;
result = parseObject(p,obj);
value = obj;
break;
}
case '[': {
2021-11-24 17:53:25 +08:00
QList<ParseValue> array;
2021-11-12 22:42:51 +08:00
result = parseArray(p,array);
value = array;
break;
}
case '"': {
QByteArray s;
result = parseStringValue(p,s);
value = s;
break;
}
default:
return false;
}
if (!result)
return false;
skipSpaces(p);
return true;
}
2021-11-13 11:16:05 +08:00
bool GDBMIResultParser::parseStringValue(const char *&p, QByteArray& stringValue)
2021-11-12 22:42:51 +08:00
{
if (*p!='"')
return false;
p++;
2021-11-24 17:53:25 +08:00
stringValue.clear();
2021-11-12 22:42:51 +08:00
while (*p!=0) {
if (*p == '"') {
break;
} else if (*p=='\\' && *(p+1)!=0) {
2021-11-24 17:53:25 +08:00
p++;
switch (*p) {
case '\'':
stringValue+=0x27;
p++;
break;
case '"':
stringValue+=0x22;
p++;
break;
case '?':
stringValue+=0x3f;
p++;
break;
case '\\':
stringValue+=0x5c;
p++;
break;
case 'a':
stringValue+=0x07;
p++;
break;
case 'b':
stringValue+=0x08;
p++;
break;
case 'f':
stringValue+=0x0c;
p++;
break;
case 'n':
stringValue+=0x0a;
p++;
break;
case 'r':
stringValue+=0x0d;
p++;
break;
case 't':
stringValue+=0x09;
p++;
break;
case 'v':
stringValue+=0x0b;
p++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{
int i=0;
for (i=0;i<3;i++) {
if (*(p+i)<'0' || *(p+i)>'7')
break;
}
QByteArray numStr(p,i);
bool ok;
char ch = numStr.toInt(&ok,8);
stringValue.append(ch);
2021-11-24 17:53:25 +08:00
p+=i;
break;
}
}
2021-11-12 22:42:51 +08:00
} else {
2021-11-24 17:53:25 +08:00
stringValue+=*p;
2021-11-12 22:42:51 +08:00
p++;
}
}
if (*p=='"') {
p++; //skip '"'
return true;
}
return false;
}
2021-11-13 11:16:05 +08:00
bool GDBMIResultParser::parseObject(const char *&p, ParseObject &obj)
2021-11-12 22:42:51 +08:00
{
if (*p!='{')
return false;
p++;
if (*p!='}') {
while (*p!=0) {
QByteArray propName;
ParseValue propValue;
bool result = parseNameAndValue(p,propName,propValue);
if (result) {
obj[propName]=propValue;
} else {
return false;
}
skipSpaces(p);
if (*p=='}')
break;
2021-11-24 17:53:25 +08:00
if (*p!=',') {
2021-11-12 22:42:51 +08:00
return false;
2021-11-24 17:53:25 +08:00
}
2021-11-12 22:42:51 +08:00
p++; //skip ','
skipSpaces(p);
}
}
if (*p=='}') {
p++; //skip '}'
return true;
}
return false;
}
2021-11-23 21:08:33 +08:00
bool GDBMIResultParser::parseArray(const char *&p, QList<GDBMIResultParser::ParseValue> &array)
2021-11-12 22:42:51 +08:00
{
if (*p!='[')
return false;
p++;
if (*p!=']') {
while (*p!=0) {
skipSpaces(p);
2021-11-24 21:22:01 +08:00
if (*p=='{' || *p=='"' || *p=='[') {
ParseValue val;
bool result = parseValue(p,val);
if (result) {
array.append(val);
} else {
return false;
}
2021-11-12 22:42:51 +08:00
} else {
2021-11-24 21:22:01 +08:00
QByteArray name;
ParseValue val;
bool result = parseNameAndValue(p,name,val);
if (result) {
array.append(val);
} else {
return false;
}
2021-11-12 22:42:51 +08:00
}
2021-11-24 21:22:01 +08:00
skipSpaces(p);
2021-11-12 22:42:51 +08:00
if (*p==']')
break;
if (*p!=',')
return false;
p++; //skip ','
skipSpaces(p);
}
}
if (*p==']') {
p++; //skip ']'
return true;
}
return false;
}
bool GDBMIResultParser::isNameChar(char ch)
{
if (ch=='-')
return true;
2021-11-25 20:26:43 +08:00
if (ch=='_')
return true;
2021-11-12 22:42:51 +08:00
if (ch>='a' && ch<='z')
return true;
if (ch>='A' && ch<='Z')
return true;
return false;
}
bool GDBMIResultParser::isSpaceChar(char ch)
{
switch(ch) {
case ' ':
case '\t':
return true;
}
return false;
}
2021-11-13 11:16:05 +08:00
void GDBMIResultParser::skipSpaces(const char *&p)
2021-11-12 22:42:51 +08:00
{
while (*p!=0 && isSpaceChar(*p))
p++;
}
2021-11-12 10:51:00 +08:00
2021-11-21 08:38:03 +08:00
const QByteArray &GDBMIResultParser::ParseValue::value() const
2021-11-12 22:42:51 +08:00
{
return mValue;
2021-11-12 10:51:00 +08:00
}
2021-11-23 21:08:33 +08:00
const QList<::GDBMIResultParser::ParseValue> &GDBMIResultParser::ParseValue::array() const
2021-11-12 10:51:00 +08:00
{
2021-11-12 22:42:51 +08:00
return mArray;
2021-11-12 10:51:00 +08:00
}
2021-11-12 22:42:51 +08:00
const GDBMIResultParser::ParseObject &GDBMIResultParser::ParseValue::object() const
{
return mObject;
}
2023-03-04 19:38:39 +08:00
qlonglong GDBMIResultParser::ParseValue::intValue(int defaultValue) const
2021-11-21 08:38:03 +08:00
{
//Q_ASSERT(mType == ParseValueType::Value);
2021-11-21 08:38:03 +08:00
bool ok;
qlonglong value = QString(mValue).toLongLong(&ok);
2021-11-21 08:38:03 +08:00
if (ok)
return value;
else
return defaultValue;
}
qulonglong GDBMIResultParser::ParseValue::hexValue(bool &ok) const
2021-11-24 17:53:25 +08:00
{
//Q_ASSERT(mType == ParseValueType::Value);
qulonglong value = QString(mValue).toULongLong(&ok,16);
return value;
2021-11-24 17:53:25 +08:00
}
2021-11-23 21:08:33 +08:00
QString GDBMIResultParser::ParseValue::pathValue() const
{
//Q_ASSERT(mType == ParseValueType::Value);
QByteArray value=mValue;
#ifdef Q_OS_WIN
if (value.startsWith("/") && !value.startsWith("//"))
value=value.mid(1);
#endif
return QFileInfo(QString::fromLocal8Bit(value)).absoluteFilePath();
2021-11-23 21:08:33 +08:00
}
QString GDBMIResultParser::ParseValue::utf8PathValue() const
{
QByteArray value=mValue;
#ifdef Q_OS_WIN
if (value.startsWith("/") && !value.startsWith("//"))
value=value.mid(1);
#endif
return QFileInfo(QString::fromUtf8(value)).absoluteFilePath();
}
2021-11-12 22:42:51 +08:00
GDBMIResultParser::ParseValueType GDBMIResultParser::ParseValue::type() const
{
return mType;
}
2021-11-24 17:53:25 +08:00
bool GDBMIResultParser::ParseValue::isValid() const
{
return mType!=ParseValueType::NotAssigned;
}
2021-11-12 22:42:51 +08:00
GDBMIResultParser::ParseValue::ParseValue():
mType(ParseValueType::NotAssigned) {
}
2021-11-21 08:38:03 +08:00
GDBMIResultParser::ParseValue::ParseValue(const QByteArray &value):
2021-11-12 22:42:51 +08:00
mValue(value),
mType(ParseValueType::Value)
{
}
GDBMIResultParser::ParseValue::ParseValue(const ParseObject &object):
2021-11-12 22:42:51 +08:00
mObject(object),
mType(ParseValueType::Object)
{
}
2021-11-23 21:08:33 +08:00
GDBMIResultParser::ParseValue::ParseValue(const QList<ParseValue> &array):
2021-11-12 22:42:51 +08:00
mArray(array),
mType(ParseValueType::Array)
{
}
2021-11-24 17:53:25 +08:00
GDBMIResultParser::ParseValue::ParseValue(const ParseValue &value):
mValue(value.mValue),
mArray(value.mArray),
mObject(value.mObject),
mType(value.mType)
{
}
GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const GDBMIResultParser::ParseValue &value)
{
mType = value.mType;
mValue = value.mValue;
mArray = value.mArray;
mObject = value.mObject;
return *this;
}
2021-11-21 08:38:03 +08:00
GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QByteArray &value)
2021-11-12 22:42:51 +08:00
{
Q_ASSERT(mType == ParseValueType::NotAssigned);
mType = ParseValueType::Value;
mValue = value;
2021-11-24 17:53:25 +08:00
return *this;
2021-11-12 22:42:51 +08:00
}
GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const ParseObject& object)
{
Q_ASSERT(mType == ParseValueType::NotAssigned);
mType = ParseValueType::Object;
mObject = object;
2021-11-24 17:53:25 +08:00
return *this;
2021-11-12 22:42:51 +08:00
}
2021-11-23 21:08:33 +08:00
GDBMIResultParser::ParseValue &GDBMIResultParser::ParseValue::operator=(const QList<ParseValue>& array)
2021-11-12 22:42:51 +08:00
{
Q_ASSERT(mType == ParseValueType::NotAssigned);
mType = ParseValueType::Array;
mArray = array;
2021-11-24 17:53:25 +08:00
return *this;
}
GDBMIResultParser::ParseObject::ParseObject()
{
2021-11-12 22:42:51 +08:00
}
2021-11-24 17:53:25 +08:00
GDBMIResultParser::ParseObject::ParseObject(const ParseObject &object):
mProps(object.mProps)
{
}
2021-11-12 22:42:51 +08:00
2021-11-24 17:53:25 +08:00
GDBMIResultParser::ParseValue GDBMIResultParser::ParseObject::operator[](const QByteArray &name) const
2021-11-12 22:42:51 +08:00
{
2021-11-24 17:53:25 +08:00
if (mProps.contains(name)) {
ParseValue value(mProps[name]);
return value;
}
2021-11-13 11:16:05 +08:00
return ParseValue();
2021-11-12 22:42:51 +08:00
}
GDBMIResultParser::ParseObject &GDBMIResultParser::ParseObject::operator=(const ParseObject &object)
{
mProps = object.mProps;
2021-11-24 17:53:25 +08:00
return *this;
2021-11-12 22:42:51 +08:00
}
GDBMIResultParser::ParseValue &GDBMIResultParser::ParseObject::operator[](const QByteArray &name) {
if (!mProps.contains(name))
mProps[name]=ParseValue();
return mProps[name];
}