1
0
Fork 0

Browse dialog and goto dialog support auto-complete (#1738)

* Browse dialog and goto dialog supports auto-complete
* don't use unicode string size
* Auto complete only when expression is valid symbol name
* use dbgfunctions for better flexibility and performance
* buffer last auto complete
* disable auto completion
This commit is contained in:
Torusrxxx 2017-11-07 19:24:51 +00:00 committed by Duncan Ogilvie
parent 3116b3dde0
commit 4cf0844255
16 changed files with 228 additions and 4 deletions

View File

@ -308,7 +308,7 @@ typedef enum
DBG_GET_PEB_ADDRESS, // param1=DWORD ProcessId, param2=unused
DBG_GET_TEB_ADDRESS, // param1=DWORD ThreadId, param2=unused
DBG_ANALYZE_FUNCTION, // param1=BridgeCFGraphList* graph, param2=duint entry
DBG_MENU_PREPARE, // param1=int hMenu, param2=unused
DBG_MENU_PREPARE // param1=int hMenu, param2=unused
} DBGMSG;
typedef enum

View File

@ -30,6 +30,7 @@
#include "comment.h"
#include "exception.h"
#include "database.h"
#include "dbghelp_safe.h"
static DBGFUNCTIONS _dbgfunctions;
@ -370,6 +371,41 @@ static bool _modrelocationsinrange(duint addr, duint size, ListOf(DBGRELOCATIONI
return true;
}
typedef struct _SYMAUTOCOMPLETECALLBACKPARAM
{
char** Buffer;
int* count;
int MaxSymbols;
} SYMAUTOCOMPLETECALLBACKPARAM;
static BOOL CALLBACK SymAutoCompleteCallback(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
{
SYMAUTOCOMPLETECALLBACKPARAM* param = reinterpret_cast<SYMAUTOCOMPLETECALLBACKPARAM*>(UserContext);
if(param->Buffer)
{
param->Buffer[*param->count] = (char*)BridgeAlloc(pSymInfo->NameLen + 1);
memcpy(param->Buffer[*param->count], pSymInfo->Name, pSymInfo->NameLen + 1);
param->Buffer[*param->count][pSymInfo->NameLen] = 0;
}
if(++*param->count >= param->MaxSymbols)
return FALSE;
else
return TRUE;
}
static int SymAutoComplete(const char* Search, char** Buffer, int MaxSymbols)
{
//debug
int count = 0;
SYMAUTOCOMPLETECALLBACKPARAM param;
param.Buffer = Buffer;
param.count = &count;
param.MaxSymbols = MaxSymbols;
if(!SafeSymEnumSymbols(fdProcessInfo->hProcess, 0, Search, SymAutoCompleteCallback, &param))
dputs(QT_TRANSLATE_NOOP("DBG", "SymEnumSymbols failed!"));
return count;
}
void dbgfunctionsinit()
{
_dbgfunctions.AssembleAtEx = _assembleatex;
@ -441,4 +477,5 @@ void dbgfunctionsinit()
_dbgfunctions.ModRelocationAtAddr = (MODRELOCATIONATADDR)ModRelocationAtAddr;
_dbgfunctions.ModRelocationsInRange = _modrelocationsinrange;
_dbgfunctions.DbGetHash = DbGetHash;
_dbgfunctions.SymAutoComplete = SymAutoComplete;
}

View File

@ -196,6 +196,7 @@ typedef bool(*MODRELOCATIONSFROMADDR)(duint addr, ListOf(DBGRELOCATIONINFO) relo
typedef bool(*MODRELOCATIONATADDR)(duint addr, DBGRELOCATIONINFO* relocation);
typedef bool(*MODRELOCATIONSINRANGE)(duint addr, duint size, ListOf(DBGRELOCATIONINFO) relocations);
typedef duint(*DBGETHASH)();
typedef int(*SYMAUTOCOMPLETE)(const char* Search, char** Buffer, int MaxSymbols);
//The list of all the DbgFunctions() return value.
//WARNING: This list is append only. Do not insert things in the middle or plugins would break.
@ -270,6 +271,7 @@ typedef struct DBGFUNCTIONS_
MODRELOCATIONATADDR ModRelocationAtAddr;
MODRELOCATIONSINRANGE ModRelocationsInRange;
DBGETHASH DbGetHash;
SYMAUTOCOMPLETE SymAutoComplete;
} DBGFUNCTIONS;
#ifdef BUILD_DBG

View File

@ -37,11 +37,11 @@ void HistoryLineEdit::saveSettings(QString sectionPrefix)
void HistoryLineEdit::addLineToHistory(QString parLine)
{
mCmdHistory.prepend(parLine);
if(mCmdHistory.size() > mCmdHistoryMaxSize)
mCmdHistory.removeLast();
mCmdHistory.prepend(parLine);
mCmdIndex = -1;
}

View File

@ -1,6 +1,8 @@
#include "BrowseDialog.h"
#include "ui_BrowseDialog.h"
#include "MiscUtil.h"
#include <QDirModel>
#include <QCompleter>
#include <QFileDialog>
#include <Configuration.h>
@ -13,6 +15,9 @@ BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString
setWindowTitle(title);
ui->label->setText(text);
ui->lineEdit->setText(QDir::toNativeSeparators(defaultPath));
QCompleter* completer = new QCompleter(ui->lineEdit);
completer->setModel(new QDirModel(completer));
ui->lineEdit->setCompleter(completer);
Config()->setupWindowPos(this);
}

View File

@ -3,6 +3,8 @@
#include "ui_GotoDialog.h"
#include "StringUtil.h"
#include "Configuration.h"
#include "QCompleter"
#include "SymbolAutoCompleteModel.h"
GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowInvalidAddress)
: QDialog(parent),
@ -22,6 +24,13 @@ GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowI
ui->labelError->setText(tr("<font color='red'><b>Invalid expression...</b></font>"));
setOkEnabled(false);
ui->editExpression->setFocus();
completer = new QCompleter(this);
completer->setModel(new SymbolAutoCompleteModel([this]
{
return ui->editExpression->text();
}, completer));
if(!Config()->getBool("Gui", "DisableAutoComplete"))
ui->editExpression->setCompleter(completer);
validRangeStart = 0;
validRangeEnd = ~0;
fileOffset = false;
@ -31,6 +40,7 @@ GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowI
connect(mValidateThread, SIGNAL(expressionChanged(bool, bool, dsint)), this, SLOT(expressionChanged(bool, bool, dsint)));
connect(ui->editExpression, SIGNAL(textChanged(QString)), mValidateThread, SLOT(textChanged(QString)));
connect(this, SIGNAL(finished(int)), this, SLOT(finishedSlot(int)));
connect(Config(), SIGNAL(disableAutoCompleteUpdated()), this, SLOT(disableAutoCompleteUpdated()));
Config()->setupWindowPos(this);
}
@ -175,3 +185,11 @@ void GotoDialog::finishedSlot(int result)
ui->editExpression->setText("");
ui->editExpression->setFocus();
}
void GotoDialog::disableAutoCompleteUpdated()
{
if(Config()->getBool("Gui", "DisableAutoComplete"))
ui->editExpression->setCompleter(nullptr);
else
ui->editExpression->setCompleter(completer);
}

View File

@ -5,6 +5,7 @@
#include "Imports.h"
class ValidateExpressionThread;
class QCompleter;
namespace Ui
{
@ -32,12 +33,14 @@ public:
private slots:
void expressionChanged(bool validExpression, bool validPointer, dsint value);
void disableAutoCompleteUpdated();
void on_buttonOk_clicked();
void finishedSlot(int result);
private:
Ui::GotoDialog* ui;
ValidateExpressionThread* mValidateThread;
QCompleter* completer;
bool IsValidMemoryRange(duint addr);
void setOkEnabled(bool enabled);
};

View File

@ -15,6 +15,7 @@ SettingsDialog::SettingsDialog(QWidget* parent) :
setModal(true);
adjustSize();
bTokenizerConfigUpdated = false;
bDisableAutoCompleteUpdated = false;
LoadSettings(); //load settings from file
connect(Bridge::getBridge(), SIGNAL(setLastException(uint)), this, SLOT(setLastException(uint)));
lastException = 0;
@ -74,6 +75,7 @@ void SettingsDialog::LoadSettings()
settings.disasmNoSourceLineAutoComments = false;
settings.disasmMaxModuleSize = -1;
settings.guiNoForegroundWindow = true;
settings.guiDisableAutoComplete = false;
//Events tab
GetSettingBool("Events", "SystemBreakpoint", &settings.eventSystemBreakpoint);
@ -225,6 +227,7 @@ void SettingsDialog::LoadSettings()
GetSettingBool("Gui", "LoadSaveTabOrder", &settings.guiLoadSaveTabOrder);
GetSettingBool("Gui", "ShowGraphRva", &settings.guiShowGraphRva);
GetSettingBool("Gui", "ShowExitConfirmation", &settings.guiShowExitConfirmation);
GetSettingBool("Gui", "DisableAutoComplete", &settings.guiDisableAutoComplete);
ui->chkFpuRegistersLittleEndian->setChecked(settings.guiFpuRegistersLittleEndian);
ui->chkSaveColumnOrder->setChecked(settings.guiSaveColumnOrder);
ui->chkNoCloseDialog->setChecked(settings.guiNoCloseDialog);
@ -234,6 +237,7 @@ void SettingsDialog::LoadSettings()
ui->chkSaveLoadTabOrder->setChecked(settings.guiLoadSaveTabOrder);
ui->chkShowGraphRva->setChecked(settings.guiShowGraphRva);
ui->chkShowExitConfirmation->setChecked(settings.guiShowExitConfirmation);
ui->chkDisableAutoComplete->setChecked(settings.guiDisableAutoComplete);
//Misc tab
if(DbgFunctions()->GetJit)
@ -370,6 +374,7 @@ void SettingsDialog::SaveSettings()
BridgeSettingSetUint("Gui", "LoadSaveTabOrder", settings.guiLoadSaveTabOrder);
BridgeSettingSetUint("Gui", "ShowGraphRva", settings.guiShowGraphRva);
BridgeSettingSetUint("Gui", "ShowExitConfirmation", settings.guiShowExitConfirmation);
BridgeSettingSetUint("Gui", "DisableAutoComplete", settings.guiDisableAutoComplete);
//Misc tab
if(DbgFunctions()->GetJit)
@ -407,6 +412,11 @@ void SettingsDialog::SaveSettings()
Config()->emitTokenizerConfigUpdated();
bTokenizerConfigUpdated = false;
}
if(bDisableAutoCompleteUpdated)
{
Config()->emitDisableAutoCompleteUpdated();
bDisableAutoCompleteUpdated = false;
}
DbgSettingsUpdated();
GuiUpdateAllViews();
}
@ -831,6 +841,12 @@ void SettingsDialog::on_chkShowExitConfirmation_toggled(bool checked)
settings.guiShowExitConfirmation = checked;
}
void SettingsDialog::on_chkDisableAutoComplete_toggled(bool checked)
{
settings.guiDisableAutoComplete = checked;
bDisableAutoCompleteUpdated = true;
}
void SettingsDialog::on_chkUseLocalHelpFile_toggled(bool checked)
{
settings.miscUseLocalHelpFile = checked;

View File

@ -82,6 +82,7 @@ private slots:
void on_chkSidebarWatchLabels_stateChanged(int arg1);
void on_chkNoForegroundWindow_toggled(bool checked);
void on_chkShowExitConfirmation_toggled(bool checked);
void on_chkDisableAutoComplete_toggled(bool checked);
//Misc tab
void on_chkSetJIT_stateChanged(int arg1);
void on_chkConfirmBeforeAtt_stateChanged(int arg1);
@ -177,6 +178,7 @@ private:
bool guiLoadSaveTabOrder;
bool guiShowGraphRva;
bool guiShowExitConfirmation;
bool guiDisableAutoComplete;
//Misc Tab
bool miscSetJIT;
bool miscSetJITAuto;
@ -195,6 +197,7 @@ private:
bool bJitOld;
bool bJitAutoOld;
bool bTokenizerConfigUpdated;
bool bDisableAutoCompleteUpdated;
//functions
void GetSettingBool(const char* section, const char* name, bool* set);

View File

@ -33,7 +33,7 @@
<bool>true</bool>
</property>
<property name="currentIndex">
<number>0</number>
<number>4</number>
</property>
<widget class="QWidget" name="tabEvents">
<attribute name="title">
@ -685,6 +685,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkDisableAutoComplete">
<property name="text">
<string>Disable auto completion in goto dialog</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">

View File

@ -273,6 +273,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
guiBool.insert("LoadSaveTabOrder", false);
guiBool.insert("ShowGraphRva", false);
guiBool.insert("ShowExitConfirmation", true);
guiBool.insert("DisableAutoComplete", false);
//Named menu settings
insertMenuBuilderBools(&guiBool, "CPUDisassembly", 50); //CPUDisassembly
insertMenuBuilderBools(&guiBool, "CPUDump", 50); //CPUDump
@ -663,6 +664,11 @@ void Configuration::emitTokenizerConfigUpdated()
emit tokenizerConfigUpdated();
}
void Configuration::emitDisableAutoCompleteUpdated()
{
emit disableAutoCompleteUpdated();
}
void Configuration::readBools()
{
Bools = defaultBools;

View File

@ -49,6 +49,7 @@ public:
void writeColors();
void emitColorsUpdated();
void emitTokenizerConfigUpdated();
void emitDisableAutoCompleteUpdated();
void readBools();
void writeBools();
void readUints();
@ -115,6 +116,7 @@ signals:
void fontsUpdated();
void shortcutsUpdated();
void tokenizerConfigUpdated();
void disableAutoCompleteUpdated();
private:
QColor colorFromConfig(const QString id);

View File

@ -0,0 +1,89 @@
#include "SymbolAutoCompleteModel.h"
#include "MiscUtil.h"
#include "Configuration.h"
SymbolAutoCompleteModel::SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent) : QAbstractItemModel(parent), mGetTextProc(getTextProc), isValidReg("[\\w_@][\\w\\d_]*")
{
lastAutocompleteCount = 0;
disableAutoCompleteUpdated();
connect(Config(), SIGNAL(disableAutoCompleteUpdated()), this, SLOT(disableAutoCompleteUpdated()));
}
QModelIndex SymbolAutoCompleteModel::parent(const QModelIndex & child) const
{
return QModelIndex();
}
QModelIndex SymbolAutoCompleteModel::index(int row, int column, const QModelIndex & parent) const
{
return createIndex(row, column);
}
int SymbolAutoCompleteModel::rowCount(const QModelIndex & parent) const
{
if(DbgIsDebugging())
{
QString text = mGetTextProc();
auto match = isValidReg.match(text);
if(match.hasMatch())
{
update();
return lastAutocompleteCount;
}
else
return 0;
}
else
return 0;
}
int SymbolAutoCompleteModel::columnCount(const QModelIndex & parent) const
{
return 1;
}
QVariant SymbolAutoCompleteModel::data(const QModelIndex & index, int role) const
{
if(index.isValid() && DbgIsDebugging())
{
if(index.column() == 0)
{
if(role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::AccessibleTextRole)
{
//TODO
update();
if(index.row() < lastAutocompleteCount)
return QVariant(lastAutocomplete[index.row()]);
else
return QVariant();
}
else if(role == Qt::DecorationRole)
{
return QVariant(DIcon("functions.png"));
}
}
}
return QVariant();
}
void SymbolAutoCompleteModel::update() const
{
QString text = "*!" + mGetTextProc() + "*";
if(text == lastAutocompleteText)
return;
char* data[MAXAUTOCOMPLETEENTRY];
memset(data, 0, sizeof(data));
int count = DbgFunctions()->SymAutoComplete(text.toUtf8().constData(), (char**)data, MAXAUTOCOMPLETEENTRY);
for(int i = 0; i < count; i++)
{
lastAutocomplete[i] = QString::fromUtf8(data[i]);
BridgeFree(data[i]);
}
lastAutocompleteCount = count;
lastAutocompleteText = text;
}
void SymbolAutoCompleteModel::disableAutoCompleteUpdated()
{
lastAutocompleteText = "";
}

View File

@ -0,0 +1,32 @@
#ifndef SYMBOLAUTOCOMPLETEMODEL
#define SYMBOLAUTOCOMPLETEMODEL
#include <functional>
#include <QAbstractItemModel>
#include <QRegularExpression>
#define MAXAUTOCOMPLETEENTRY 20
class SymbolAutoCompleteModel : public QAbstractItemModel
{
Q_OBJECT
public:
SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent = 0);
virtual QVariant data(const QModelIndex & index, int role) const override;
virtual QModelIndex index(int row, int column, const QModelIndex & parent) const override;
virtual int rowCount(const QModelIndex & parent) const override;
virtual int columnCount(const QModelIndex & parent) const override;
virtual QModelIndex parent(const QModelIndex & child) const override;
private slots:
void disableAutoCompleteUpdated();
private:
std::function<QString()> mGetTextProc;
QRegularExpression isValidReg;
mutable QString lastAutocompleteText;
mutable QString lastAutocomplete[MAXAUTOCOMPLETEENTRY];
mutable int lastAutocompleteCount;
void update() const;
};
#endif //SYMBOLAUTOCOMPLETEMODEL

View File

@ -185,6 +185,7 @@ SOURCES += \
Src/Gui/AboutDialog.cpp \
Src/Gui/BreakpointMenu.cpp \
Src/Gui/ComboBoxDialog.cpp \
Src/Utils/SymbolAutoCompleteModel.cpp \
Src/Tracer/TraceBrowser.cpp \
Src/Tracer/TraceFileReader.cpp \
Src/Tracer/TraceFileSearch.cpp
@ -306,6 +307,7 @@ HEADERS += \
Src/Gui/BreakpointMenu.h \
Src/Gui/ComboBoxDialog.h \
Src/Utils/VaHistory.h \
Src/Utils/SymbolAutoCompleteModel.h \
Src/Tracer/TraceBrowser.h \
Src/Tracer/TraceFileReader.h \
Src/Tracer/TraceFileReaderInternal.h \

View File

@ -220,6 +220,7 @@ SOURCES += \
gui/Src/Gui/MessagesBreakpoints.cpp \
gui/Src/Gui/AboutDialog.cpp \
gui/Src/Gui/BreakpointMenu.cpp \
gui/Src/Utils/SymbolAutoCompleteModel.cpp \
gui/Src/Tracer/TraceBrowser.cpp \
gui/Src/Tracer/TraceFileReader.cpp \
gui/Src/Tracer/TraceFileSearch.cpp
@ -453,6 +454,7 @@ HEADERS += \
gui/Src/Gui/MessagesBreakpoints.h \
gui/Src/Gui/AboutDialog.h \
gui/Src/Gui/BreakpointMenu.h \
gui/Src/Utils/SymbolAutoCompleteModel.h \
gui/Src/Tracer/TraceBrowser.h \
gui/Src/Tracer/TraceFileReader.h \
gui/Src/Tracer/TraceFileReaderInternal.h \