Merge branch 'master' of github.com:royqh1979/RedPanda-CPP

This commit is contained in:
Roy Qu 2023-03-17 20:37:19 +08:00
commit fdc7bce147
23 changed files with 4008 additions and 918 deletions

19
NEWS.md
View File

@ -8,9 +8,22 @@ Red Panda C++ Version 2.18
- enhancement: Warn user and stop compile if project has missing files. - enhancement: Warn user and stop compile if project has missing files.
- enhancement: Warn user when exit and save settings failed. - enhancement: Warn user when exit and save settings failed.
- change: Remove compiler set options that's rarely used. - change: Remove compiler set options that's rarely used.
- enhancement: Options in compiler set settings, to generate syntax error for large stack objects. Enable for Debug settings by default) - enhancement: Add option in the compiler set settings, to generate syntax error for large stack objects. Enable for Debug settings by default)
- enhancement: Options in compiler set settings, to generate protection code for stack smashing attack. Enable for Debug settings by default) - enhancement: Add option in the compiler set settings, to generate protection code for stack smashing attack. Enable for Debug settings by default)
- enhancement: Options in compiler set settings, to enable address sanitizer. Not available in windows.Enable for Debug settings by default) - enhancement: Add option in the compiler set settings, to enable address sanitizer. Not available in windows.Enable for Debug settings by default)
- fix: The comboxbox to input search keyword in the search dialog is case insensitive.
- fix: The comboxbox to input replace text in the search dialog is case insensitive.
- fix: The comboxbox to input search keyword in the search in files dialog is case insensitive.
- fix: The comboxbox to input address expression in the debug panel's memory view is case insensitive.
- fix: The comboxbox to input evaluation expression in the debug panel is case insensitive.
- fix: The comboxbox to input replace text in the search panel is case insensitive.
- fix: None initialized std::vector is not correctly displayed in the gdb of the gcc distributed with redpanda-c++ (Windows 64bit).
- fix: Don't show completion info when input parameters for function definitions.
- fix: Don't show function info tips when typing class variable definitions.
- enhancement: Add option in the debug settings, to limit the length of the ouput generated by gdb for arrays.
- enhancement: Show shortcut info in toolbar's tooltip.
- change: Use F11 as the shortcut for "Run". (It's the old shortcut for "Compile&Run")
Red Panda C++ Version 2.17 Red Panda C++ Version 2.17

View File

@ -1780,7 +1780,7 @@ void Editor::onStatusChanged(QSynedit::StatusChanges changes)
} }
} }
if (changes.testFlag(QSynedit::scInsertMode) | changes.testFlag(QSynedit::scReadOnly)) if (changes.testFlag(QSynedit::scInsertMode) || changes.testFlag(QSynedit::scReadOnly))
pMainWindow->updateForStatusbarModeInfo(); pMainWindow->updateForStatusbarModeInfo();
pMainWindow->updateEditorActions(); pMainWindow->updateEditorActions();
@ -3573,45 +3573,71 @@ void Editor::cleanAutoBackup()
} }
} }
bool Editor::testInFunc(int x, int y) bool Editor::testInFunc(const QSynedit::BufferCoord& pos)
{ {
bool result = false; int y=pos.line-1;
QString s = document()->getLine(y); int x=pos.ch;
int posY = y; if (!syntaxer() || syntaxer()->language()!=QSynedit::ProgrammingLanguage::CPP)
int posX = std::min(x,s.length()-1); // x is started from 1
int bracketLevel=0;
while (true) {
while (posX < 0) {
posY--;
if (posY < 0)
return false; return false;
s = document()->getLine(posY); if (y==0)
posX = s.length()-1; syntaxer()->resetState();
else
syntaxer()->setState(document()->getSyntaxState(y-1));
syntaxer()->setLine(document()->getLine(y),y);
// qDebug()<<x<<document()->getLine(y).length();
QSynedit::SyntaxState state = syntaxer()->getState();
while(!syntaxer()->eol()) {
int start = syntaxer()->getTokenPos();
QString token = syntaxer()->getToken();
int end = start + token.length();
// qDebug()<<syntaxer()->getToken()<<start<<end;
if (end>=x)
break;
state = syntaxer()->getState();
syntaxer()->next();
} }
if (s[posX] == '>' // qDebug()<<state.parenthesisLevel;
|| s[posX] == ']') { return state.parenthesisLevel>0;
bracketLevel++;
} else if (s[posX] == '<'
|| s[posX] == '[') { // bool result = false;
bracketLevel--; // QString s = document()->getLine(y);
} else if (bracketLevel==0) { // int posY = y;
switch (s[posX].unicode()) { // int posX = std::min(x,s.length()-1); // x is started from 1
case '(': // int bracketLevel=0;
return true;
case ';': // while (true) {
case '{': // while (posX < 0) {
return false; // posY--;
} // if (posY < 0)
if (!(isIdentChar(s[posX]) // return false;
|| s[posX] == ' ' // s = document()->getLine(posY);
|| s[posX] == '\t' // posX = s.length()-1;
|| s[posX] == '*' // }
|| s[posX] == '&')) // if (s[posX] == '>'
break;; // || s[posX] == ']') {
} // bracketLevel++;
posX--; // } else if (s[posX] == '<'
} // || s[posX] == '[') {
return result; // bracketLevel--;
// } else if (bracketLevel==0) {
// switch (s[posX].unicode()) {
// case '(':
// return true;
// case ';':
// case '{':
// return false;
// }
// if (!(isIdentChar(s[posX])
// || s[posX] == ' '
// || s[posX] == '\t'
// || s[posX] == '*'
// || s[posX] == '&'))
// break;;
// }
// posX--;
// }
// return result;
} }
void Editor::completionInsert(bool appendFunc) void Editor::completionInsert(bool appendFunc)
@ -4188,7 +4214,6 @@ void Editor::updateFunctionTip(bool showTip)
QSynedit::BufferCoord pWordBegin, pWordEnd; QSynedit::BufferCoord pWordBegin, pWordEnd;
QString s = getWordAtPosition(this, functionNamePos, pWordBegin,pWordEnd, WordPurpose::wpInformation); QString s = getWordAtPosition(this, functionNamePos, pWordBegin,pWordEnd, WordPurpose::wpInformation);
int x = pWordBegin.ch-1-1; int x = pWordBegin.ch-1-1;
QString line = document()->getLine(pWordBegin.line-1); QString line = document()->getLine(pWordBegin.line-1);
bool hasPreviousWord=false; bool hasPreviousWord=false;
@ -4206,9 +4231,10 @@ void Editor::updateFunctionTip(bool showTip)
break; break;
} }
//handle class initializer
if (x >= 0 && hasPreviousWord) { if (x >= 0 && hasPreviousWord) {
QSynedit::BufferCoord pos = pWordBegin; QSynedit::BufferCoord pos = pWordBegin;
pos.ch = x+1; pos.ch = pWordBegin.ch;
QString previousWord = getPreviousWordAtPositionForSuggestion(pos); QString previousWord = getPreviousWordAtPositionForSuggestion(pos);
PStatement statement = mParser->findStatementOf( PStatement statement = mParser->findStatementOf(
@ -4779,7 +4805,7 @@ QString Editor::getPreviousWordAtPositionForSuggestion(const QSynedit::BufferCoo
if ((p.line<1) || (p.line>document()->count())) { if ((p.line<1) || (p.line>document()->count())) {
return ""; return "";
} }
bool inFunc = testInFunc(p.ch-1,p.line-1); bool inFunc = testInFunc(p);
QString s = document()->getLine(p.line - 1); QString s = document()->getLine(p.line - 1);
int wordBegin; int wordBegin;
@ -4800,7 +4826,7 @@ QString Editor::getPreviousWordAtPositionForSuggestion(const QSynedit::BufferCoo
else else
return ""; return "";
} else if (bracketLevel==0) { } else if (bracketLevel==0) {
//we can't differentiate multiple definition and function parameter define here , so we don't handle ',' //Differentiate multiple definition and function parameter define here
if (s[wordEnd] == ',') { if (s[wordEnd] == ',') {
if (inFunc) // in func, dont skip ',' if (inFunc) // in func, dont skip ','
break; break;

View File

@ -271,7 +271,7 @@ private:
void saveAutoBackup(); void saveAutoBackup();
void cleanAutoBackup(); void cleanAutoBackup();
bool testInFunc(int x,int y); bool testInFunc(const QSynedit::BufferCoord& pos);
void completionInsert(bool appendFunc=false); void completionInsert(bool appendFunc=false);

View File

@ -77,6 +77,7 @@
#include <QMimeDatabase> #include <QMimeDatabase>
#include <QMimeType> #include <QMimeType>
#include <QToolTip> #include <QToolTip>
#include <QCompleter>
#include "mainwindow.h" #include "mainwindow.h"
#include <QScrollBar> #include <QScrollBar>
@ -260,6 +261,11 @@ MainWindow::MainWindow(QWidget *parent)
// updateEditorActions(); // updateEditorActions();
// updateCaretActions(); // updateCaretActions();
ui->cbReplaceInHistory->completer()->setCaseSensitivity(Qt::CaseSensitive);
ui->cbEvaluate->completer()->setCaseSensitivity(Qt::CaseSensitive);
ui->cbMemoryAddress->completer()->setCaseSensitivity(Qt::CaseSensitive);
ui->cbFilesPath->completer()->setCaseSensitivity(Qt::CaseInsensitive);
connect(ui->debugConsole,&QConsole::commandInput,this,&MainWindow::onDebugCommandInput); connect(ui->debugConsole,&QConsole::commandInput,this,&MainWindow::onDebugCommandInput);
connect(ui->cbEvaluate->lineEdit(), &QLineEdit::returnPressed, connect(ui->cbEvaluate->lineEdit(), &QLineEdit::returnPressed,
this, &MainWindow::onDebugEvaluateInput); this, &MainWindow::onDebugEvaluateInput);
@ -2389,7 +2395,7 @@ void MainWindow::debug()
mDebugger->sendCommand("-gdb-set", "width 0"); // don't wrap output, very annoying mDebugger->sendCommand("-gdb-set", "width 0"); // don't wrap output, very annoying
mDebugger->sendCommand("-gdb-set", "confirm off"); mDebugger->sendCommand("-gdb-set", "confirm off");
mDebugger->sendCommand("-gdb-set", "print repeats 0"); // don't repeat elements mDebugger->sendCommand("-gdb-set", "print repeats 0"); // don't repeat elements
mDebugger->sendCommand("-gdb-set", "print elements 0"); // don't limit elements mDebugger->sendCommand("-gdb-set", QString("print elements %1").arg(pSettings->debugger().arrayElements())); // limit array elements to 500
mDebugger->sendCommand("-environment-cd", QString("\"%1\"").arg(extractFileDir(filePath))); // restore working directory mDebugger->sendCommand("-environment-cd", QString("\"%1\"").arg(extractFileDir(filePath))); // restore working directory
if (pSettings->debugger().useGDBServer()) { if (pSettings->debugger().useGDBServer()) {
mDebugger->sendCommand("-target-select",QString("remote localhost:%1").arg(pSettings->debugger().GDBServerPort())); mDebugger->sendCommand("-target-select",QString("remote localhost:%1").arg(pSettings->debugger().GDBServerPort()));

View File

@ -487,7 +487,7 @@
<enum>QTabWidget::West</enum> <enum>QTabWidget::West</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>0</number>
</property> </property>
<property name="usesScrollButtons"> <property name="usesScrollButtons">
<bool>true</bool> <bool>true</bool>
@ -971,7 +971,6 @@
<widget class="IssuesTable" name="tableIssues"> <widget class="IssuesTable" name="tableIssues">
<property name="font"> <property name="font">
<font> <font>
<weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </property>
@ -1133,7 +1132,7 @@
<enum>QTabWidget::North</enum> <enum>QTabWidget::North</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>1</number> <number>2</number>
</property> </property>
<widget class="QWidget" name="tabDebugConsole"> <widget class="QWidget" name="tabDebugConsole">
<attribute name="title"> <attribute name="title">
@ -2167,7 +2166,7 @@
<string>Run</string> <string>Run</string>
</property> </property>
<property name="shortcut"> <property name="shortcut">
<string>F10</string> <string>F11</string>
</property> </property>
</action> </action>
<action name="actionUndo"> <action name="actionUndo">

View File

@ -84,6 +84,7 @@ void StatementModel::clear() {
#endif #endif
} }
#ifdef QT_DEBUG
void StatementModel::dump(const QString &logFile) void StatementModel::dump(const QString &logFile)
{ {
QFile file(logFile); QFile file(logFile);
@ -93,7 +94,6 @@ void StatementModel::dump(const QString &logFile)
} }
} }
#ifdef QT_DEBUG
void StatementModel::dumpAll(const QString &logFile) void StatementModel::dumpAll(const QString &logFile)
{ {
QFile file(logFile); QFile file(logFile);
@ -104,11 +104,16 @@ void StatementModel::dumpAll(const QString &logFile)
.arg(statement->command).arg(int(statement->kind)) .arg(statement->command).arg(int(statement->kind))
.arg(statement->type).arg(statement->fullName) .arg(statement->type).arg(statement->fullName)
.arg((size_t)(statement->parentScope.lock().get())) .arg((size_t)(statement->parentScope.lock().get()))
.arg((int)statement->classScope) .arg((int)statement->accessibility)
.arg(statement->fileName) .arg(statement->fileName)
.arg(statement->line) .arg(statement->line)
.arg(statement->definitionFileName) .arg(statement->definitionFileName)
.arg(statement->definitionLine)<<endl; .arg(statement->definitionLine)<<
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
Qt::endl;
#else
endl;
#endif
} }
} }
} }

View File

@ -36,8 +36,8 @@ public:
const StatementMap& childrenStatements(const PStatement& statement = PStatement()) const; const StatementMap& childrenStatements(const PStatement& statement = PStatement()) const;
const StatementMap& childrenStatements(std::weak_ptr<Statement> statement) const; const StatementMap& childrenStatements(std::weak_ptr<Statement> statement) const;
void clear(); void clear();
void dump(const QString& logFile);
#ifdef QT_DEBUG #ifdef QT_DEBUG
void dump(const QString& logFile);
void dumpAll(const QString& logFile); void dumpAll(const QString& logFile);
#endif #endif
private: private:

View File

@ -4020,6 +4020,16 @@ void Settings::Debugger::setAutosave(bool newAutosave)
mAutosave = newAutosave; mAutosave = newAutosave;
} }
int Settings::Debugger::arrayElements() const
{
return mArrayElements;
}
void Settings::Debugger::setArrayElements(int newArrayElements)
{
mArrayElements = newArrayElements;
}
bool Settings::Debugger::useIntelStyle() const bool Settings::Debugger::useIntelStyle() const
{ {
return mUseIntelStyle; return mUseIntelStyle;
@ -4068,6 +4078,7 @@ void Settings::Debugger::doSave()
saveValue("gdb_server_port",mGDBServerPort); saveValue("gdb_server_port",mGDBServerPort);
saveValue("memory_view_rows",mMemoryViewRows); saveValue("memory_view_rows",mMemoryViewRows);
saveValue("memory_view_columns",mMemoryViewColumns); saveValue("memory_view_columns",mMemoryViewColumns);
saveValue("array_elements",mArrayElements);
} }
void Settings::Debugger::doLoad() void Settings::Debugger::doLoad()
@ -4096,6 +4107,7 @@ void Settings::Debugger::doLoad()
mGDBServerPort = intValue("gdb_server_port",41234); mGDBServerPort = intValue("gdb_server_port",41234);
mMemoryViewRows = intValue("memory_view_rows",16); mMemoryViewRows = intValue("memory_view_rows",16);
mMemoryViewColumns = intValue("memory_view_columns",16); mMemoryViewColumns = intValue("memory_view_columns",16);
mArrayElements = intValue("array_elements",300);
} }
Settings::CodeCompletion::CodeCompletion(Settings *settings):_Base(settings, SETTING_CODE_COMPLETION) Settings::CodeCompletion::CodeCompletion(Settings *settings):_Base(settings, SETTING_CODE_COMPLETION)

View File

@ -1281,6 +1281,9 @@ public:
bool autosave() const; bool autosave() const;
void setAutosave(bool newAutosave); void setAutosave(bool newAutosave);
int arrayElements() const;
void setArrayElements(int newArrayElements);
private: private:
bool mEnableDebugConsole; bool mEnableDebugConsole;
bool mShowDetailLog; bool mShowDetailLog;
@ -1298,6 +1301,7 @@ public:
int mGDBServerPort; int mGDBServerPort;
int mMemoryViewRows; int mMemoryViewRows;
int mMemoryViewColumns; int mMemoryViewColumns;
int mArrayElements;
// _Base interface // _Base interface
protected: protected:

View File

@ -56,6 +56,7 @@ void DebugGeneralWidget::doLoad()
ui->spinGDBServerPort->setValue(pSettings->debugger().GDBServerPort()); ui->spinGDBServerPort->setValue(pSettings->debugger().GDBServerPort());
ui->spinMemoryViewRows->setValue(pSettings->debugger().memoryViewRows()); ui->spinMemoryViewRows->setValue(pSettings->debugger().memoryViewRows());
ui->spinMemoryViewColumns->setValue(pSettings->debugger().memoryViewColumns()); ui->spinMemoryViewColumns->setValue(pSettings->debugger().memoryViewColumns());
ui->spinArrayElements->setValue(pSettings->debugger().arrayElements());
} }
void DebugGeneralWidget::doSave() void DebugGeneralWidget::doSave()
@ -78,6 +79,8 @@ void DebugGeneralWidget::doSave()
pSettings->debugger().setGDBServerPort(ui->spinGDBServerPort->value()); pSettings->debugger().setGDBServerPort(ui->spinGDBServerPort->value());
pSettings->debugger().setMemoryViewRows(ui->spinMemoryViewRows->value()); pSettings->debugger().setMemoryViewRows(ui->spinMemoryViewRows->value());
pSettings->debugger().setMemoryViewColumns(ui->spinMemoryViewColumns->value()); pSettings->debugger().setMemoryViewColumns(ui->spinMemoryViewColumns->value());
pSettings->debugger().setArrayElements(ui->spinArrayElements->value());
pSettings->debugger().save(); pSettings->debugger().save();
pMainWindow->updateDebuggerSettings(); pMainWindow->updateDebuggerSettings();
} }

View File

@ -14,6 +14,58 @@
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QCheckBox" name="chkAutosave">
<property name="text">
<string>Autosave watches</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_5" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Max number of array elements displayed</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinArrayElements">
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="grpUseGDBServer"> <widget class="QGroupBox" name="grpUseGDBServer">
<property name="title"> <property name="title">
@ -23,6 +75,18 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
@ -56,27 +120,61 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Skip header files when step into</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item> <item>
<widget class="QCheckBox" name="chkSkipSystemLib"> <widget class="QCheckBox" name="chkSkipSystemLib">
<property name="text"> <property name="text">
<string>Skip system header and library files when step into</string> <string>System library</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="chkSkipProjectLib"> <widget class="QCheckBox" name="chkSkipProjectLib">
<property name="text"> <property name="text">
<string>Skip project header and library files when step into</string> <string>Project library</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="chkSkipCustomLib"> <widget class="QCheckBox" name="chkSkipCustomLib">
<property name="text"> <property name="text">
<string>Skip custom header and library files when step into</string> <string>Custom library</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="grpEnableDebugConsole"> <widget class="QGroupBox" name="grpEnableDebugConsole">
<property name="title"> <property name="title">
@ -87,16 +185,16 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin"> <property name="leftMargin">
<number>11</number> <number>7</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>11</number> <number>7</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>11</number> <number>7</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>11</number> <number>7</number>
</property> </property>
<item> <item>
<widget class="QWidget" name="widget" native="true"> <widget class="QWidget" name="widget" native="true">
@ -169,7 +267,11 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QSpinBox" name="sbFontSize"/> <widget class="QSpinBox" name="sbFontSize">
<property name="maximum">
<number>999</number>
</property>
</widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_2"> <spacer name="horizontalSpacer_2">
@ -202,32 +304,23 @@
<property name="title"> <property name="title">
<string>Memory View</string> <string>Memory View</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<item>
<widget class="QWidget" name="widget_5" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>7</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>7</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>0</number> <number>7</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>7</number>
</property> </property>
<item> <item>
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>Memory View Rows</string> <string>Rows</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -244,6 +337,23 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Columns</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinMemoryViewColumns">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item> <item>
<spacer name="horizontalSpacer_4"> <spacer name="horizontalSpacer_4">
<property name="orientation"> <property name="orientation">
@ -260,79 +370,24 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QWidget" name="widget_6" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Memory View Columns</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinMemoryViewColumns">
<property name="minimum">
<number>1</number>
</property>
<property name="value">
<number>8</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>437</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Autosave</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QCheckBox" name="chkAutosave">
<property name="text">
<string>Autosave breakpoints and watches</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_3"> <widget class="QGroupBox" name="groupBox_3">
<property name="title"> <property name="title">
<string>CPU Window</string> <string>CPU Window</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item> <item>
<widget class="QCheckBox" name="chkShowCPUWhenSignaled"> <widget class="QCheckBox" name="chkShowCPUWhenSignaled">
<property name="text"> <property name="text">
@ -340,6 +395,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="chkBlendMode">
<property name="text">
<string>Show disassembly code in blend mode</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QWidget" name="widget_3" native="true"> <widget class="QWidget" name="widget_3" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
@ -373,7 +435,7 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_5"> <layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -386,6 +448,16 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<widget class="QRadioButton" name="rbATT">
<property name="text">
<string>AT&amp;&amp;T</string>
</property>
<attribute name="buttonGroup">
<string notr="true">grpCPUDisassembly</string>
</attribute>
</widget>
</item>
<item> <item>
<widget class="QRadioButton" name="rbIntel"> <widget class="QRadioButton" name="rbIntel">
<property name="text"> <property name="text">
@ -397,14 +469,17 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QRadioButton" name="rbATT"> <spacer name="horizontalSpacer_7">
<property name="text"> <property name="orientation">
<string>AT&amp;&amp;T</string> <enum>Qt::Horizontal</enum>
</property> </property>
<attribute name="buttonGroup"> <property name="sizeHint" stdset="0">
<string notr="true">grpCPUDisassembly</string> <size>
</attribute> <width>40</width>
</widget> <height>20</height>
</size>
</property>
</spacer>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -412,13 +487,6 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="chkBlendMode">
<property name="text">
<string>Show disassembly code in blend mode</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -127,4 +127,9 @@ void ShortcutManager::applyTo(QAction *action)
if (item && item->isAction) { if (item && item->isAction) {
action->setShortcut(QKeySequence::fromString(item->shortcut)); action->setShortcut(QKeySequence::fromString(item->shortcut));
} }
if (!action->shortcut().isEmpty()){
action->setToolTip(action->text()+QString("(%1)").arg(action->shortcut().toString()));
} else {
action->setToolTip(action->text());
}
} }

View File

@ -818,15 +818,15 @@
</message> </message>
<message> <message>
<source>Skip system header and library files when step into</source> <source>Skip system header and library files when step into</source>
<translation>Ignorar os cabeçalho de sistema e os arquivos de biblioteca ao avançar</translation> <translation type="vanished">Ignorar os cabeçalho de sistema e os arquivos de biblioteca ao avançar</translation>
</message> </message>
<message> <message>
<source>Skip project header and library files when step into</source> <source>Skip project header and library files when step into</source>
<translation>Ignorar o cabeçalho de projeto e os arquivos de biblioteca ao avançar</translation> <translation type="vanished">Ignorar o cabeçalho de projeto e os arquivos de biblioteca ao avançar</translation>
</message> </message>
<message> <message>
<source>Skip custom header and library files when step into</source> <source>Skip custom header and library files when step into</source>
<translation>Ignorar o cabeçalho personalizado e os arquivos de biblioteca ao avançar</translation> <translation type="vanished">Ignorar o cabeçalho personalizado e os arquivos de biblioteca ao avançar</translation>
</message> </message>
<message> <message>
<source>Debug Console</source> <source>Debug Console</source>
@ -850,7 +850,7 @@
</message> </message>
<message> <message>
<source>Autosave</source> <source>Autosave</source>
<translation>Salvar automaticamente</translation> <translation type="vanished">Salvar automaticamente</translation>
</message> </message>
<message> <message>
<source>Autosave breakpoints</source> <source>Autosave breakpoints</source>
@ -858,7 +858,7 @@
</message> </message>
<message> <message>
<source>Autosave watches</source> <source>Autosave watches</source>
<translation type="vanished">Salvar automaticamente as observações</translation> <translation>Salvar automaticamente as observações</translation>
</message> </message>
<message> <message>
<source>Show CPU Window when signal received</source> <source>Show CPU Window when signal received</source>
@ -890,14 +890,38 @@
</message> </message>
<message> <message>
<source>Memory View Rows</source> <source>Memory View Rows</source>
<translation>Linhas da memória</translation> <translation type="vanished">Linhas da memória</translation>
</message> </message>
<message> <message>
<source>Memory View Columns</source> <source>Memory View Columns</source>
<translation>Colunas da memória</translation> <translation type="vanished">Colunas da memória</translation>
</message> </message>
<message> <message>
<source>Autosave breakpoints and watches</source> <source>Max number of array elements displayed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Skip header files when step into</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>System library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Project library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Custom library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Rows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Columns</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -3453,7 +3477,7 @@
</message> </message>
<message> <message>
<source>F10</source> <source>F10</source>
<translation>F10</translation> <translation type="vanished">F10</translation>
</message> </message>
<message> <message>
<source>Undo</source> <source>Undo</source>
@ -3561,7 +3585,7 @@
</message> </message>
<message> <message>
<source>F11</source> <source>F11</source>
<translation type="vanished">F11</translation> <translation>F11</translation>
</message> </message>
<message> <message>
<source>Rebuild All</source> <source>Rebuild All</source>

File diff suppressed because it is too large Load Diff

View File

@ -713,18 +713,6 @@
<source>GDB Server Port</source> <source>GDB Server Port</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Skip system header and library files when step into</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Skip project header and library files when step into</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Skip custom header and library files when step into</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Debug Console</source> <source>Debug Console</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -745,10 +733,6 @@
<source>Show detail debug logs</source> <source>Show detail debug logs</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Autosave</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Show CPU Window when signal received</source> <source>Show CPU Window when signal received</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -778,15 +762,35 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Memory View Rows</source> <source>Autosave watches</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Memory View Columns</source> <source>Max number of array elements displayed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Autosave breakpoints and watches</source> <source>Skip header files when step into</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>System library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Project library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Custom library</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Rows</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Columns</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>
@ -3284,10 +3288,6 @@
<source>Run</source> <source>Run</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>F10</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Undo</source> <source>Undo</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -4900,6 +4900,10 @@
<source>Save settings failed!</source> <source>Save settings failed!</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>F11</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>MemoryModel</name> <name>MemoryModel</name>

View File

@ -1,6 +1,7 @@
#include "searchdialog.h" #include "searchdialog.h"
#include "ui_searchdialog.h" #include "ui_searchdialog.h"
#include <QCompleter>
#include <QMessageBox> #include <QMessageBox>
#include <memory> #include <memory>
#include <qsynedit/searcher/basicsearcher.h> #include <qsynedit/searcher/basicsearcher.h>
@ -29,6 +30,8 @@ SearchDialog::SearchDialog(QWidget *parent) :
onTabBarCurrentChanged(mSearchTabIdx); onTabBarCurrentChanged(mSearchTabIdx);
mBasicSearchEngine = std::make_shared<QSynedit::BasicSearcher>(); mBasicSearchEngine = std::make_shared<QSynedit::BasicSearcher>();
mRegexSearchEngine = std::make_shared<QSynedit::RegexSearcher>(); mRegexSearchEngine = std::make_shared<QSynedit::RegexSearcher>();
ui->cbFind->completer()->setCaseSensitivity(Qt::CaseSensitive);
ui->cbReplace->completer()->setCaseSensitivity(Qt::CaseSensitive);
} }
SearchDialog::~SearchDialog() SearchDialog::~SearchDialog()

View File

@ -27,6 +27,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QDebug> #include <QDebug>
#include <QProgressDialog> #include <QProgressDialog>
#include <QCompleter>
SearchInFileDialog::SearchInFileDialog(QWidget *parent) : SearchInFileDialog::SearchInFileDialog(QWidget *parent) :
@ -38,6 +39,8 @@ SearchInFileDialog::SearchInFileDialog(QWidget *parent) :
mSearchOptions&=0; mSearchOptions&=0;
mBasicSearchEngine= QSynedit::PSynSearchBase(new QSynedit::BasicSearcher()); mBasicSearchEngine= QSynedit::PSynSearchBase(new QSynedit::BasicSearcher());
mRegexSearchEngine= QSynedit::PSynSearchBase(new QSynedit::RegexSearcher()); mRegexSearchEngine= QSynedit::PSynSearchBase(new QSynedit::RegexSearcher());
ui->cbFind->completer()->setCaseSensitivity(Qt::CaseSensitive);
} }
SearchInFileDialog::~SearchInFileDialog() SearchInFileDialog::~SearchInFileDialog()

View File

@ -59,7 +59,9 @@ echo "Making installer..."
pushd . pushd .
cd "${PACKAGE_DIR}" cd "${PACKAGE_DIR}"
ln -s "${MINGW}" $MinGW_NAME cp -a "${MINGW}" .
rm -rf "${MINGW_NAME}/share/gcc-11.2.0"
cp -a "${SOURCE_DIR}/tools/gdb-scripts/gcc-11.2.0" "${MINGW_NAME}/share"
cp "${SOURCE_DIR}/platform/windows/installer-scripts/lang.nsh" . cp "${SOURCE_DIR}/platform/windows/installer-scripts/lang.nsh" .
cp "${SOURCE_DIR}/platform/windows/installer-scripts/redpanda-x64.nsi" . cp "${SOURCE_DIR}/platform/windows/installer-scripts/redpanda-x64.nsi" .

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,33 @@
# Copyright (C) 2014-2021 Free Software Foundation, Inc.
# 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 <http://www.gnu.org/licenses/>.
import gdb
# Load the xmethods if GDB supports them.
def gdb_has_xmethods():
try:
import gdb.xmethod
return True
except ImportError:
return False
def register_libstdcxx_printers(obj):
# Load the pretty-printers.
from .printers import register_libstdcxx_printers
register_libstdcxx_printers(obj)
if gdb_has_xmethods():
from .xmethods import register_libstdcxx_xmethods
register_libstdcxx_xmethods(obj)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,805 @@
# Xmethods for libstdc++.
# Copyright (C) 2014-2021 Free Software Foundation, Inc.
# 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 <http://www.gnu.org/licenses/>.
import gdb
import gdb.xmethod
import re
matcher_name_prefix = 'libstdc++::'
def get_bool_type():
return gdb.lookup_type('bool')
def get_std_size_type():
return gdb.lookup_type('std::size_t')
class LibStdCxxXMethod(gdb.xmethod.XMethod):
def __init__(self, name, worker_class):
gdb.xmethod.XMethod.__init__(self, name)
self.worker_class = worker_class
# Xmethods for std::array
class ArrayWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type, size):
self._val_type = val_type
self._size = size
def null_value(self):
nullptr = gdb.parse_and_eval('(void *) 0')
return nullptr.cast(self._val_type.pointer()).dereference()
class ArraySizeWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self._size
class ArrayEmptyWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return (int(self._size) == 0)
class ArrayFrontWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
if int(self._size) > 0:
return obj['_M_elems'][0]
else:
return self.null_value()
class ArrayBackWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
if int(self._size) > 0:
return obj['_M_elems'][self._size - 1]
else:
return self.null_value()
class ArrayAtWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
def __call__(self, obj, index):
if int(index) >= int(self._size):
raise IndexError('Array index "%d" should not be >= %d.' %
((int(index), self._size)))
return obj['_M_elems'][index]
class ArraySubscriptWorker(ArrayWorkerBase):
def __init__(self, val_type, size):
ArrayWorkerBase.__init__(self, val_type, size)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
def __call__(self, obj, index):
if int(self._size) > 0:
return obj['_M_elems'][index]
else:
return self.null_value()
class ArrayMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'array')
self._method_dict = {
'size': LibStdCxxXMethod('size', ArraySizeWorker),
'empty': LibStdCxxXMethod('empty', ArrayEmptyWorker),
'front': LibStdCxxXMethod('front', ArrayFrontWorker),
'back': LibStdCxxXMethod('back', ArrayBackWorker),
'at': LibStdCxxXMethod('at', ArrayAtWorker),
'operator[]': LibStdCxxXMethod('operator[]', ArraySubscriptWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?array<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
try:
value_type = class_type.template_argument(0)
size = class_type.template_argument(1)
except:
return None
return method.worker_class(value_type, size)
# Xmethods for std::deque
class DequeWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type):
self._val_type = val_type
self._bufsize = 512 // val_type.sizeof or 1
def size(self, obj):
first_node = obj['_M_impl']['_M_start']['_M_node']
last_node = obj['_M_impl']['_M_finish']['_M_node']
cur = obj['_M_impl']['_M_finish']['_M_cur']
first = obj['_M_impl']['_M_finish']['_M_first']
return (last_node - first_node) * self._bufsize + (cur - first)
def index(self, obj, idx):
first_node = obj['_M_impl']['_M_start']['_M_node']
index_node = first_node + int(idx) // self._bufsize
return index_node[0][idx % self._bufsize]
class DequeEmptyWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return (obj['_M_impl']['_M_start']['_M_cur'] ==
obj['_M_impl']['_M_finish']['_M_cur'])
class DequeSizeWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self.size(obj)
class DequeFrontWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return obj['_M_impl']['_M_start']['_M_cur'][0]
class DequeBackWorker(DequeWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
if (obj['_M_impl']['_M_finish']['_M_cur'] ==
obj['_M_impl']['_M_finish']['_M_first']):
prev_node = obj['_M_impl']['_M_finish']['_M_node'] - 1
return prev_node[0][self._bufsize - 1]
else:
return obj['_M_impl']['_M_finish']['_M_cur'][-1]
class DequeSubscriptWorker(DequeWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, subscript):
return self._val_type
def __call__(self, obj, subscript):
return self.index(obj, subscript)
class DequeAtWorker(DequeWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
def __call__(self, obj, index):
deque_size = int(self.size(obj))
if int(index) >= deque_size:
raise IndexError('Deque index "%d" should not be >= %d.' %
(int(index), deque_size))
else:
return self.index(obj, index)
class DequeMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'deque')
self._method_dict = {
'empty': LibStdCxxXMethod('empty', DequeEmptyWorker),
'size': LibStdCxxXMethod('size', DequeSizeWorker),
'front': LibStdCxxXMethod('front', DequeFrontWorker),
'back': LibStdCxxXMethod('back', DequeBackWorker),
'operator[]': LibStdCxxXMethod('operator[]', DequeSubscriptWorker),
'at': LibStdCxxXMethod('at', DequeAtWorker)
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?deque<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
return method.worker_class(class_type.template_argument(0))
# Xmethods for std::forward_list
class ForwardListWorkerBase(gdb.xmethod.XMethodMatcher):
def __init__(self, val_type, node_type):
self._val_type = val_type
self._node_type = node_type
def get_arg_types(self):
return None
class ForwardListEmptyWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return obj['_M_impl']['_M_head']['_M_next'] == 0
class ForwardListFrontWorker(ForwardListWorkerBase):
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
node = obj['_M_impl']['_M_head']['_M_next'].cast(self._node_type)
val_address = node['_M_storage']['_M_storage'].address
return val_address.cast(self._val_type.pointer()).dereference()
class ForwardListMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
matcher_name = matcher_name_prefix + 'forward_list'
gdb.xmethod.XMethodMatcher.__init__(self, matcher_name)
self._method_dict = {
'empty': LibStdCxxXMethod('empty', ForwardListEmptyWorker),
'front': LibStdCxxXMethod('front', ForwardListFrontWorker)
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?forward_list<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
val_type = class_type.template_argument(0)
node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
return method.worker_class(val_type, node_type)
# Xmethods for std::list
class ListWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type, node_type):
self._val_type = val_type
self._node_type = node_type
def get_arg_types(self):
return None
def get_value_from_node(self, node):
node = node.dereference()
if node.type.fields()[1].name == '_M_data':
# C++03 implementation, node contains the value as a member
return node['_M_data']
# C++11 implementation, node stores value in __aligned_membuf
addr = node['_M_storage'].address
return addr.cast(self._val_type.pointer()).dereference()
class ListEmptyWorker(ListWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
base_node = obj['_M_impl']['_M_node']
if base_node['_M_next'] == base_node.address:
return True
else:
return False
class ListSizeWorker(ListWorkerBase):
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
begin_node = obj['_M_impl']['_M_node']['_M_next']
end_node = obj['_M_impl']['_M_node'].address
size = 0
while begin_node != end_node:
begin_node = begin_node['_M_next']
size += 1
return size
class ListFrontWorker(ListWorkerBase):
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
node = obj['_M_impl']['_M_node']['_M_next'].cast(self._node_type)
return self.get_value_from_node(node)
class ListBackWorker(ListWorkerBase):
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
prev_node = obj['_M_impl']['_M_node']['_M_prev'].cast(self._node_type)
return self.get_value_from_node(prev_node)
class ListMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'list')
self._method_dict = {
'empty': LibStdCxxXMethod('empty', ListEmptyWorker),
'size': LibStdCxxXMethod('size', ListSizeWorker),
'front': LibStdCxxXMethod('front', ListFrontWorker),
'back': LibStdCxxXMethod('back', ListBackWorker)
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?(__cxx11::)?list<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
val_type = class_type.template_argument(0)
node_type = gdb.lookup_type(str(class_type) + '::_Node').pointer()
return method.worker_class(val_type, node_type)
# Xmethods for std::vector
class VectorWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, val_type):
self._val_type = val_type
def size(self, obj):
if self._val_type.code == gdb.TYPE_CODE_BOOL:
start = obj['_M_impl']['_M_start']['_M_p']
finish = obj['_M_impl']['_M_finish']['_M_p']
finish_offset = obj['_M_impl']['_M_finish']['_M_offset']
bit_size = start.dereference().type.sizeof * 8
return (finish - start) * bit_size + finish_offset
else:
return obj['_M_impl']['_M_finish'] - obj['_M_impl']['_M_start']
def get(self, obj, index):
if self._val_type.code == gdb.TYPE_CODE_BOOL:
start = obj['_M_impl']['_M_start']['_M_p']
bit_size = start.dereference().type.sizeof * 8
valp = start + index // bit_size
offset = index % bit_size
return (valp.dereference() & (1 << offset)) > 0
else:
return obj['_M_impl']['_M_start'][index]
class VectorEmptyWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return int(self.size(obj)) == 0
class VectorSizeWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self.size(obj)
class VectorFrontWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return self.get(obj, 0)
class VectorBackWorker(VectorWorkerBase):
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._val_type
def __call__(self, obj):
return self.get(obj, int(self.size(obj)) - 1)
class VectorAtWorker(VectorWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._val_type
def __call__(self, obj, index):
size = int(self.size(obj))
if int(index) >= size:
raise IndexError('Vector index "%d" should not be >= %d.' %
((int(index), size)))
return self.get(obj, int(index))
class VectorSubscriptWorker(VectorWorkerBase):
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, subscript):
return self._val_type
def __call__(self, obj, subscript):
return self.get(obj, int(subscript))
class VectorMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'vector')
self._method_dict = {
'size': LibStdCxxXMethod('size', VectorSizeWorker),
'empty': LibStdCxxXMethod('empty', VectorEmptyWorker),
'front': LibStdCxxXMethod('front', VectorFrontWorker),
'back': LibStdCxxXMethod('back', VectorBackWorker),
'at': LibStdCxxXMethod('at', VectorAtWorker),
'operator[]': LibStdCxxXMethod('operator[]',
VectorSubscriptWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?vector<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
return method.worker_class(class_type.template_argument(0))
# Xmethods for associative containers
class AssociativeContainerWorkerBase(gdb.xmethod.XMethodWorker):
def __init__(self, unordered):
self._unordered = unordered
def node_count(self, obj):
if self._unordered:
return obj['_M_h']['_M_element_count']
else:
return obj['_M_t']['_M_impl']['_M_node_count']
def get_arg_types(self):
return None
class AssociativeContainerEmptyWorker(AssociativeContainerWorkerBase):
def get_result_type(self, obj):
return get_bool_type()
def __call__(self, obj):
return int(self.node_count(obj)) == 0
class AssociativeContainerSizeWorker(AssociativeContainerWorkerBase):
def get_result_type(self, obj):
return get_std_size_type()
def __call__(self, obj):
return self.node_count(obj)
class AssociativeContainerMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self, name):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + name)
self._name = name
self._method_dict = {
'size': LibStdCxxXMethod('size', AssociativeContainerSizeWorker),
'empty': LibStdCxxXMethod('empty',
AssociativeContainerEmptyWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?%s<.*>$' % self._name, class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
unordered = 'unordered' in self._name
return method.worker_class(unordered)
# Xmethods for std::unique_ptr
class UniquePtrGetWorker(gdb.xmethod.XMethodWorker):
"Implements std::unique_ptr<T>::get() and std::unique_ptr<T>::operator->()"
def __init__(self, elem_type):
self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
if self._is_array:
self._elem_type = elem_type.target()
else:
self._elem_type = elem_type
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._elem_type.pointer()
def _supports(self, method_name):
"operator-> is not supported for unique_ptr<T[]>"
return method_name == 'get' or not self._is_array
def __call__(self, obj):
impl_type = obj.dereference().type.fields()[0].type.tag
# Check for new implementations first:
if re.match('^std::(__\d+::)?__uniq_ptr_(data|impl)<.*>$', impl_type):
tuple_member = obj['_M_t']['_M_t']
elif re.match('^std::(__\d+::)?tuple<.*>$', impl_type):
tuple_member = obj['_M_t']
else:
return None
tuple_impl_type = tuple_member.type.fields()[0].type # _Tuple_impl
tuple_head_type = tuple_impl_type.fields()[1].type # _Head_base
head_field = tuple_head_type.fields()[0]
if head_field.name == '_M_head_impl':
return tuple_member['_M_head_impl']
elif head_field.is_base_class:
return tuple_member.cast(head_field.type)
else:
return None
class UniquePtrDerefWorker(UniquePtrGetWorker):
"Implements std::unique_ptr<T>::operator*()"
def __init__(self, elem_type):
UniquePtrGetWorker.__init__(self, elem_type)
def get_result_type(self, obj):
return self._elem_type
def _supports(self, method_name):
"operator* is not supported for unique_ptr<T[]>"
return not self._is_array
def __call__(self, obj):
return UniquePtrGetWorker.__call__(self, obj).dereference()
class UniquePtrSubscriptWorker(UniquePtrGetWorker):
"Implements std::unique_ptr<T>::operator[](size_t)"
def __init__(self, elem_type):
UniquePtrGetWorker.__init__(self, elem_type)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._elem_type
def _supports(self, method_name):
"operator[] is only supported for unique_ptr<T[]>"
return self._is_array
def __call__(self, obj, index):
return UniquePtrGetWorker.__call__(self, obj)[index]
class UniquePtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'unique_ptr')
self._method_dict = {
'get': LibStdCxxXMethod('get', UniquePtrGetWorker),
'operator->': LibStdCxxXMethod('operator->', UniquePtrGetWorker),
'operator*': LibStdCxxXMethod('operator*', UniquePtrDerefWorker),
'operator[]': LibStdCxxXMethod('operator[]', UniquePtrSubscriptWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?unique_ptr<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
worker = method.worker_class(class_type.template_argument(0))
if worker._supports(method_name):
return worker
return None
# Xmethods for std::shared_ptr
class SharedPtrGetWorker(gdb.xmethod.XMethodWorker):
"Implements std::shared_ptr<T>::get() and std::shared_ptr<T>::operator->()"
def __init__(self, elem_type):
self._is_array = elem_type.code == gdb.TYPE_CODE_ARRAY
if self._is_array:
self._elem_type = elem_type.target()
else:
self._elem_type = elem_type
def get_arg_types(self):
return None
def get_result_type(self, obj):
return self._elem_type.pointer()
def _supports(self, method_name):
"operator-> is not supported for shared_ptr<T[]>"
return method_name == 'get' or not self._is_array
def __call__(self, obj):
return obj['_M_ptr']
class SharedPtrDerefWorker(SharedPtrGetWorker):
"Implements std::shared_ptr<T>::operator*()"
def __init__(self, elem_type):
SharedPtrGetWorker.__init__(self, elem_type)
def get_result_type(self, obj):
return self._elem_type
def _supports(self, method_name):
"operator* is not supported for shared_ptr<T[]>"
return not self._is_array
def __call__(self, obj):
return SharedPtrGetWorker.__call__(self, obj).dereference()
class SharedPtrSubscriptWorker(SharedPtrGetWorker):
"Implements std::shared_ptr<T>::operator[](size_t)"
def __init__(self, elem_type):
SharedPtrGetWorker.__init__(self, elem_type)
def get_arg_types(self):
return get_std_size_type()
def get_result_type(self, obj, index):
return self._elem_type
def _supports(self, method_name):
"operator[] is only supported for shared_ptr<T[]>"
return self._is_array
def __call__(self, obj, index):
# Check bounds if _elem_type is an array of known bound
m = re.match('.*\[(\d+)]$', str(self._elem_type))
if m and index >= int(m.group(1)):
raise IndexError('shared_ptr<%s> index "%d" should not be >= %d.' %
(self._elem_type, int(index), int(m.group(1))))
return SharedPtrGetWorker.__call__(self, obj)[index]
class SharedPtrUseCountWorker(gdb.xmethod.XMethodWorker):
"Implements std::shared_ptr<T>::use_count()"
def __init__(self, elem_type):
SharedPtrUseCountWorker.__init__(self, elem_type)
def get_arg_types(self):
return None
def get_result_type(self, obj):
return gdb.lookup_type('long')
def __call__(self, obj):
refcounts = obj['_M_refcount']['_M_pi']
return refcounts['_M_use_count'] if refcounts else 0
class SharedPtrUniqueWorker(SharedPtrUseCountWorker):
"Implements std::shared_ptr<T>::unique()"
def __init__(self, elem_type):
SharedPtrUseCountWorker.__init__(self, elem_type)
def get_result_type(self, obj):
return gdb.lookup_type('bool')
def __call__(self, obj):
return SharedPtrUseCountWorker.__call__(self, obj) == 1
class SharedPtrMethodsMatcher(gdb.xmethod.XMethodMatcher):
def __init__(self):
gdb.xmethod.XMethodMatcher.__init__(self,
matcher_name_prefix + 'shared_ptr')
self._method_dict = {
'get': LibStdCxxXMethod('get', SharedPtrGetWorker),
'operator->': LibStdCxxXMethod('operator->', SharedPtrGetWorker),
'operator*': LibStdCxxXMethod('operator*', SharedPtrDerefWorker),
'operator[]': LibStdCxxXMethod('operator[]', SharedPtrSubscriptWorker),
'use_count': LibStdCxxXMethod('use_count', SharedPtrUseCountWorker),
'unique': LibStdCxxXMethod('unique', SharedPtrUniqueWorker),
}
self.methods = [self._method_dict[m] for m in self._method_dict]
def match(self, class_type, method_name):
if not re.match('^std::(__\d+::)?shared_ptr<.*>$', class_type.tag):
return None
method = self._method_dict.get(method_name)
if method is None or not method.enabled:
return None
worker = method.worker_class(class_type.template_argument(0))
if worker._supports(method_name):
return worker
return None
def register_libstdcxx_xmethods(locus):
gdb.xmethod.register_xmethod_matcher(locus, ArrayMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, ForwardListMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, DequeMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, ListMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, VectorMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('set'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('map'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('multiset'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('multimap'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('unordered_set'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('unordered_map'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('unordered_multiset'))
gdb.xmethod.register_xmethod_matcher(
locus, AssociativeContainerMethodsMatcher('unordered_multimap'))
gdb.xmethod.register_xmethod_matcher(locus, UniquePtrMethodsMatcher())
gdb.xmethod.register_xmethod_matcher(locus, SharedPtrMethodsMatcher())