mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
Add option for not loading plugins (#2160)
* Separate commandline parsing from rest of logic. * Add options for not loading plugins.
This commit is contained in:
parent
aa8ecee8e2
commit
6135fc7024
@ -61,3 +61,15 @@ Options
|
||||
Disable output redirection. Some of the output in console widget will not
|
||||
be visible. Use this option when debuging a crash or freeze and output
|
||||
redirection is causing some messages to be lost.
|
||||
|
||||
.. option:: --no-plugins
|
||||
|
||||
Start cutter with all plugins disabled. Implies :option:`--no-cutter-plugins` and :option:`--no-r2-plugins`.
|
||||
|
||||
.. option:: --no-cutter-plugins
|
||||
|
||||
Start cutter with cutter plugins disabled.
|
||||
|
||||
.. option:: --no-r2-plugins
|
||||
|
||||
Start cutter with r2 plugins disabled.
|
||||
|
@ -68,47 +68,10 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
QCommandLineParser cmd_parser;
|
||||
cmd_parser.setApplicationDescription(
|
||||
QObject::tr("A Qt and C++ GUI for radare2 reverse engineering framework"));
|
||||
cmd_parser.addHelpOption();
|
||||
cmd_parser.addVersionOption();
|
||||
cmd_parser.addPositionalArgument("filename", QObject::tr("Filename to open."));
|
||||
|
||||
QCommandLineOption analOption({"A", "anal"},
|
||||
QObject::tr("Automatically open file and optionally start analysis. Needs filename to be specified. May be a value between 0 and 2: 0 = no analysis, 1 = aaa, 2 = aaaa (experimental)"),
|
||||
QObject::tr("level"));
|
||||
cmd_parser.addOption(analOption);
|
||||
|
||||
QCommandLineOption formatOption({"F", "format"},
|
||||
QObject::tr("Force using a specific file format (bin plugin)"),
|
||||
QObject::tr("name"));
|
||||
cmd_parser.addOption(formatOption);
|
||||
|
||||
QCommandLineOption baddrOption({"B", "base"},
|
||||
QObject::tr("Load binary at a specific base address"),
|
||||
QObject::tr("base address"));
|
||||
cmd_parser.addOption(baddrOption);
|
||||
|
||||
QCommandLineOption scriptOption("i",
|
||||
QObject::tr("Run script file"),
|
||||
QObject::tr("file"));
|
||||
cmd_parser.addOption(scriptOption);
|
||||
|
||||
QCommandLineOption pythonHomeOption("pythonhome", QObject::tr("PYTHONHOME to use for embedded python interpreter"),
|
||||
"PYTHONHOME");
|
||||
cmd_parser.addOption(pythonHomeOption);
|
||||
|
||||
QCommandLineOption disableRedirectOption("no-output-redirect",
|
||||
QObject::tr("Disable output redirection."
|
||||
" Some of the output in console widget will not be visible."
|
||||
" Use this option when debuging a crash or freeze and output "
|
||||
" redirection is causing some messages to be lost."));
|
||||
cmd_parser.addOption(disableRedirectOption);
|
||||
|
||||
cmd_parser.process(*this);
|
||||
|
||||
QStringList args = cmd_parser.positionalArguments();
|
||||
if (!parseCommandLineOptions()) {
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
// Check r2 version
|
||||
QString r2version = r_core_version();
|
||||
@ -128,8 +91,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
|
||||
#ifdef CUTTER_ENABLE_PYTHON
|
||||
// Init python
|
||||
if (cmd_parser.isSet(pythonHomeOption)) {
|
||||
Python()->setPythonHome(cmd_parser.value(pythonHomeOption));
|
||||
if (!clOptions.pythonHome.isEmpty()) {
|
||||
Python()->setPythonHome(clOptions.pythonHome);
|
||||
}
|
||||
Python()->initialize();
|
||||
#endif
|
||||
@ -139,14 +102,12 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
qputenv("R_ALT_SRC_DIR", "1");
|
||||
#endif
|
||||
|
||||
Core()->initialize();
|
||||
Core()->initialize(clOptions.enableR2Plugins);
|
||||
Core()->setSettings();
|
||||
Config()->loadInitial();
|
||||
Core()->loadCutterRC();
|
||||
|
||||
if (cmd_parser.isSet(disableRedirectOption)) {
|
||||
Config()->setOutputRedirectionEnabled(false);
|
||||
}
|
||||
Config()->setOutputRedirectionEnabled(clOptions.outputRedirectionEnabled);
|
||||
|
||||
if (R2DecDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2DecDecompiler(Core()));
|
||||
@ -156,20 +117,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
Core()->registerDecompiler(new R2GhidraDecompiler(Core()));
|
||||
#endif
|
||||
|
||||
bool analLevelSpecified = false;
|
||||
int analLevel = 0;
|
||||
|
||||
if (cmd_parser.isSet(analOption)) {
|
||||
analLevel = cmd_parser.value(analOption).toInt(&analLevelSpecified);
|
||||
|
||||
if (!analLevelSpecified || analLevel < 0 || analLevel > 2) {
|
||||
printf("%s\n",
|
||||
QObject::tr("Invalid Analysis Level. May be a value between 0 and 2.").toLocal8Bit().constData());
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Plugins()->loadPlugins();
|
||||
Plugins()->loadPlugins(clOptions.enableCutterPlugins);
|
||||
|
||||
for (auto &plugin : Plugins()->getPlugins()) {
|
||||
plugin->registerDecompilers();
|
||||
@ -183,46 +131,16 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
setStyle(new CutterProxyStyle());
|
||||
#endif // QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
|
||||
|
||||
if (args.empty()) {
|
||||
if (analLevelSpecified) {
|
||||
printf("%s\n",
|
||||
QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
if (clOptions.args.empty()) {
|
||||
// check if this is the first execution of Cutter in this computer
|
||||
// Note: the execution after the preferences benn reset, will be considered as first-execution
|
||||
// Note: the execution after the preferences been reset, will be considered as first-execution
|
||||
if (Config()->isFirstExecution()) {
|
||||
mainWindow->displayWelcomeDialog();
|
||||
}
|
||||
mainWindow->displayNewFileDialog();
|
||||
} else { // filename specified as positional argument
|
||||
InitialOptions options;
|
||||
options.filename = args[0];
|
||||
options.forceBinPlugin = cmd_parser.value(formatOption);
|
||||
if (cmd_parser.isSet(baddrOption)) {
|
||||
bool ok;
|
||||
RVA baddr = cmd_parser.value(baddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
options.binLoadAddr = baddr;
|
||||
}
|
||||
}
|
||||
if (analLevelSpecified) {
|
||||
switch (analLevel) {
|
||||
case 0:
|
||||
default:
|
||||
options.analCmd = {};
|
||||
break;
|
||||
case 1:
|
||||
options.analCmd = { {"aaa", "Auto analysis"} };
|
||||
break;
|
||||
case 2:
|
||||
options.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
|
||||
break;
|
||||
}
|
||||
}
|
||||
options.script = cmd_parser.value(scriptOption);
|
||||
mainWindow->openNewFile(options, analLevelSpecified);
|
||||
bool askOptions = clOptions.analLevel != AutomaticAnalysisLevel::Ask;
|
||||
mainWindow->openNewFile(clOptions.fileOpenOptions, askOptions);
|
||||
}
|
||||
|
||||
#ifdef CUTTER_APPVEYOR_R2DEC
|
||||
@ -278,6 +196,21 @@ CutterApplication::~CutterApplication()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CutterApplication::launchNewInstance(const QStringList &args)
|
||||
{
|
||||
QProcess process(this);
|
||||
process.setEnvironment(QProcess::systemEnvironment());
|
||||
QStringList allArgs;
|
||||
if (!clOptions.enableCutterPlugins) {
|
||||
allArgs.push_back("--no-cutter-plugins");
|
||||
}
|
||||
if (!clOptions.enableR2Plugins) {
|
||||
allArgs.push_back("--no-r2-plugins");
|
||||
}
|
||||
allArgs.append(args);
|
||||
process.startDetached(qApp->applicationFilePath(), allArgs);
|
||||
}
|
||||
|
||||
bool CutterApplication::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::FileOpen) {
|
||||
@ -287,10 +220,7 @@ bool CutterApplication::event(QEvent *e)
|
||||
// We already dropped a file in macOS, let's spawn another instance
|
||||
// (Like the File -> Open)
|
||||
QString fileName = openEvent->file();
|
||||
QProcess process(this);
|
||||
process.setEnvironment(QProcess::systemEnvironment());
|
||||
QStringList args = QStringList(fileName);
|
||||
process.startDetached(qApp->applicationFilePath(), args);
|
||||
launchNewInstance({fileName});
|
||||
} else {
|
||||
QString fileName = openEvent->file();
|
||||
m_FileAlreadyDropped = true;
|
||||
@ -362,6 +292,145 @@ bool CutterApplication::loadTranslations()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CutterApplication::parseCommandLineOptions()
|
||||
{
|
||||
// Keep this function in sync with documentation
|
||||
|
||||
QCommandLineParser cmd_parser;
|
||||
cmd_parser.setApplicationDescription(
|
||||
QObject::tr("A Qt and C++ GUI for radare2 reverse engineering framework"));
|
||||
cmd_parser.addHelpOption();
|
||||
cmd_parser.addVersionOption();
|
||||
cmd_parser.addPositionalArgument("filename", QObject::tr("Filename to open."));
|
||||
|
||||
QCommandLineOption analOption({"A", "anal"},
|
||||
QObject::tr("Automatically open file and optionally start analysis. "
|
||||
"Needs filename to be specified. May be a value between 0 and 2:"
|
||||
" 0 = no analysis, 1 = aaa, 2 = aaaa (experimental)"),
|
||||
QObject::tr("level"));
|
||||
cmd_parser.addOption(analOption);
|
||||
|
||||
QCommandLineOption formatOption({"F", "format"},
|
||||
QObject::tr("Force using a specific file format (bin plugin)"),
|
||||
QObject::tr("name"));
|
||||
cmd_parser.addOption(formatOption);
|
||||
|
||||
QCommandLineOption baddrOption({"B", "base"},
|
||||
QObject::tr("Load binary at a specific base address"),
|
||||
QObject::tr("base address"));
|
||||
cmd_parser.addOption(baddrOption);
|
||||
|
||||
QCommandLineOption scriptOption("i",
|
||||
QObject::tr("Run script file"),
|
||||
QObject::tr("file"));
|
||||
cmd_parser.addOption(scriptOption);
|
||||
|
||||
QCommandLineOption pythonHomeOption("pythonhome",
|
||||
QObject::tr("PYTHONHOME to use for embedded python interpreter"),
|
||||
"PYTHONHOME");
|
||||
cmd_parser.addOption(pythonHomeOption);
|
||||
|
||||
QCommandLineOption disableRedirectOption("no-output-redirect",
|
||||
QObject::tr("Disable output redirection."
|
||||
" Some of the output in console widget will not be visible."
|
||||
" Use this option when debuging a crash or freeze and output "
|
||||
" redirection is causing some messages to be lost."));
|
||||
cmd_parser.addOption(disableRedirectOption);
|
||||
|
||||
QCommandLineOption disablePlugins("no-plugins",
|
||||
QObject::tr("Do not load plugins"));
|
||||
cmd_parser.addOption(disablePlugins);
|
||||
|
||||
QCommandLineOption disableCutterPlugins("no-cutter-plugins",
|
||||
QObject::tr("Do not load Cutter plugins"));
|
||||
cmd_parser.addOption(disableCutterPlugins);
|
||||
|
||||
QCommandLineOption disableR2Plugins("no-r2-plugins",
|
||||
QObject::tr("Do not load radare2 plugins"));
|
||||
cmd_parser.addOption(disableR2Plugins);
|
||||
|
||||
cmd_parser.process(*this);
|
||||
|
||||
CutterCommandLineOptions opts;
|
||||
opts.args = cmd_parser.positionalArguments();
|
||||
|
||||
if (cmd_parser.isSet(analOption)) {
|
||||
bool analLevelSpecified = false;
|
||||
int analLevel = cmd_parser.value(analOption).toInt(&analLevelSpecified);
|
||||
|
||||
if (!analLevelSpecified || analLevel < 0 || analLevel > 2) {
|
||||
fprintf(stderr, "%s\n",
|
||||
QObject::tr("Invalid Analysis Level. May be a value between 0 and 2.").toLocal8Bit().constData());
|
||||
return false;
|
||||
}
|
||||
switch (analLevel) {
|
||||
case 0:
|
||||
opts.analLevel = AutomaticAnalysisLevel::None;
|
||||
break;
|
||||
case 1:
|
||||
opts.analLevel = AutomaticAnalysisLevel::AAA;
|
||||
break;
|
||||
case 2:
|
||||
opts.analLevel = AutomaticAnalysisLevel::AAAA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.args.empty() && opts.analLevel != AutomaticAnalysisLevel::Ask) {
|
||||
fprintf(stderr, "%s\n",
|
||||
QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
InitialOptions options;
|
||||
if (!opts.args.isEmpty()) {
|
||||
opts.fileOpenOptions.filename = opts.args[0];
|
||||
opts.fileOpenOptions.forceBinPlugin = cmd_parser.value(formatOption);
|
||||
if (cmd_parser.isSet(baddrOption)) {
|
||||
bool ok;
|
||||
RVA baddr = cmd_parser.value(baddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
options.binLoadAddr = baddr;
|
||||
}
|
||||
}
|
||||
switch (opts.analLevel) {
|
||||
case AutomaticAnalysisLevel::Ask:
|
||||
break;
|
||||
case AutomaticAnalysisLevel::None:
|
||||
opts.fileOpenOptions.analCmd = {};
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAA:
|
||||
opts.fileOpenOptions.analCmd = { {"aaa", "Auto analysis"} };
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAAA:
|
||||
opts.fileOpenOptions.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
|
||||
break;
|
||||
}
|
||||
opts.fileOpenOptions.script = cmd_parser.value(scriptOption);
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(pythonHomeOption)) {
|
||||
opts.pythonHome = cmd_parser.value(pythonHomeOption);
|
||||
}
|
||||
|
||||
opts.outputRedirectionEnabled = !cmd_parser.isSet(disableRedirectOption);
|
||||
if (cmd_parser.isSet(disablePlugins)) {
|
||||
opts.enableCutterPlugins = false;
|
||||
opts.enableR2Plugins = false;
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(disableCutterPlugins)) {
|
||||
opts.enableCutterPlugins = false;
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(disableR2Plugins)) {
|
||||
opts.enableR2Plugins = false;
|
||||
}
|
||||
|
||||
this->clOptions = opts;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CutterProxyStyle::polish(QWidget *widget)
|
||||
{
|
||||
@ -370,7 +439,7 @@ void CutterProxyStyle::polish(QWidget *widget)
|
||||
// HACK: This is the only way I've found to force Qt (5.10 and newer) to
|
||||
// display shortcuts in context menus on all platforms. It's ugly,
|
||||
// but it gets the job done.
|
||||
if (auto menu = qobject_cast<QMenu*>(widget)) {
|
||||
if (auto menu = qobject_cast<QMenu *>(widget)) {
|
||||
const auto &actions = menu->actions();
|
||||
for (auto action : actions) {
|
||||
action->setShortcutVisibleInContextMenu(true);
|
||||
|
@ -8,6 +8,19 @@
|
||||
|
||||
#include "core/MainWindow.h"
|
||||
|
||||
enum class AutomaticAnalysisLevel {
|
||||
Ask, None, AAA, AAAA
|
||||
};
|
||||
|
||||
struct CutterCommandLineOptions {
|
||||
QStringList args;
|
||||
AutomaticAnalysisLevel analLevel = AutomaticAnalysisLevel::Ask;
|
||||
InitialOptions fileOpenOptions;
|
||||
QString pythonHome;
|
||||
bool outputRedirectionEnabled = true;
|
||||
bool enableCutterPlugins = true;
|
||||
bool enableR2Plugins = true;
|
||||
};
|
||||
|
||||
class CutterApplication : public QApplication
|
||||
{
|
||||
@ -22,6 +35,7 @@ public:
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
void launchNewInstance(const QStringList &args = {});
|
||||
protected:
|
||||
bool event(QEvent *e);
|
||||
|
||||
@ -31,10 +45,15 @@ private:
|
||||
* @return true on success
|
||||
*/
|
||||
bool loadTranslations();
|
||||
|
||||
/**
|
||||
* @brief Parse commandline options and store them in a structure.
|
||||
* @return false if options have error
|
||||
*/
|
||||
bool parseCommandLineOptions();
|
||||
private:
|
||||
bool m_FileAlreadyDropped;
|
||||
MainWindow *mainWindow;
|
||||
CutterCommandLineOptions clOptions;
|
||||
};
|
||||
|
||||
|
||||
|
@ -174,7 +174,7 @@ CutterCore *CutterCore::instance()
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
void CutterCore::initialize()
|
||||
void CutterCore::initialize(bool loadPlugins)
|
||||
{
|
||||
r_cons_new(); // initialize console
|
||||
core_ = r_core_new();
|
||||
@ -208,7 +208,12 @@ void CutterCore::initialize()
|
||||
}
|
||||
#endif
|
||||
|
||||
r_core_loadlibs(this->core_, R_CORE_LOADLIBS_ALL, NULL);
|
||||
if (!loadPlugins) {
|
||||
setConfig("cfg.plugins", 0);
|
||||
}
|
||||
if (getConfigi("cfg.plugins")) {
|
||||
r_core_loadlibs(this->core_, R_CORE_LOADLIBS_ALL, nullptr);
|
||||
}
|
||||
// IMPLICIT r_bin_iobind (core_->bin, core_->io);
|
||||
|
||||
// Otherwise r2 may ask the user for input and Cutter would freeze
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
~CutterCore();
|
||||
static CutterCore *instance();
|
||||
|
||||
void initialize();
|
||||
void initialize(bool loadPlugins = true);
|
||||
void loadCutterRC();
|
||||
|
||||
AsyncTaskManager *getAsyncTaskManager() { return asyncTaskManager; }
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "common/PythonManager.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
#include "CutterConfig.h"
|
||||
#include "CutterApplication.h"
|
||||
|
||||
// Dialogs
|
||||
#include "dialogs/WelcomeDialog.h"
|
||||
@ -1349,9 +1350,7 @@ void MainWindow::on_actionDefault_triggered()
|
||||
void MainWindow::on_actionNew_triggered()
|
||||
{
|
||||
// Create a new Cutter process
|
||||
QProcess process(this);
|
||||
process.setEnvironment(QProcess::systemEnvironment());
|
||||
process.startDetached(qApp->applicationFilePath());
|
||||
static_cast<CutterApplication*>(qApp)->launchNewInstance();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionSave_triggered()
|
||||
|
@ -31,10 +31,15 @@ PluginManager::~PluginManager()
|
||||
{
|
||||
}
|
||||
|
||||
void PluginManager::loadPlugins()
|
||||
void PluginManager::loadPlugins(bool enablePlugins)
|
||||
{
|
||||
assert(plugins.empty());
|
||||
|
||||
if (!enablePlugins) {
|
||||
// [#2159] list but don't enable the plugins
|
||||
return;
|
||||
}
|
||||
|
||||
QString userPluginDir = getUserPluginsDirectory();
|
||||
if (!userPluginDir.isEmpty()) {
|
||||
loadPluginsFromDir(QDir(userPluginDir), true);
|
||||
|
@ -28,8 +28,9 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Load all plugins, should be called once on application start
|
||||
* @param enablePlugins set to false if plugin code shouldn't be started
|
||||
*/
|
||||
void loadPlugins();
|
||||
void loadPlugins(bool enablePlugins = true);
|
||||
|
||||
/**
|
||||
* @brief Destroy all loaded plugins, should be called once on application shutdown
|
||||
|
Loading…
Reference in New Issue
Block a user