diff --git a/include/dcc_interface.h b/include/dcc_interface.h index 8421104..a587642 100644 --- a/include/dcc_interface.h +++ b/include/dcc_interface.h @@ -11,14 +11,12 @@ struct IDcc { static IDcc *get(); virtual void BaseInit()=0; virtual void Init(QObject *tgt)=0; - virtual PtrFunction GetCurFuncHandle()=0; virtual void analysis_Once()=0; virtual bool load(QString name)=0; // load and preprocess -> find entry point - virtual void prtout_asm(IStructuredTextTarget *,int level=0)=0; - virtual void prtout_cpp(IStructuredTextTarget *,int level=0)=0; + virtual void prtout_asm(PtrFunction f,IStructuredTextTarget *,int level=0)=0; + virtual void prtout_cpp(PtrFunction f,IStructuredTextTarget *,int level=0)=0; virtual size_t getFuncCount()=0; virtual const lFunction &validFunctions() const =0; - virtual void SetCurFunc_by_Name(QString )=0; virtual QDir installDir()=0; virtual QDir dataDir(QString kind)=0; }; diff --git a/include/project.h b/include/project.h index e037fef..2847963 100644 --- a/include/project.h +++ b/include/project.h @@ -148,9 +148,12 @@ public: bool addCommand(Command *cmd); bool addCommand(PtrFunction f, Command *cmd); // Add function level command + bool hasCommands(const PtrFunction &f); + CommandStream *functionCommands(const PtrFunction &f); void dumpAllErrors(); void setLoader(DosLoader *ins); void processCommands(int count=1); + void processFunctionCommands(const PtrFunction & func, int count); public slots: void onCommandStreamFinished(bool state); signals: diff --git a/src/AutomatedPlanner.cpp b/src/AutomatedPlanner.cpp index c954dd6..ea6fb60 100644 --- a/src/AutomatedPlanner.cpp +++ b/src/AutomatedPlanner.cpp @@ -3,6 +3,7 @@ #include "project.h" #include "FollowControlFlow.h" +#include /** * @class AutomatedPlanner * @brief Class responsible for building command lists @@ -28,6 +29,11 @@ void AutomatedPlanner::planFor(Project &project) { void AutomatedPlanner::planFor(Function & func) { if(func.doNotDecompile()) return; // for functions marked as non-decompileable we don't add any commands + //TODO: Consider cases where commands are queued, but we can still plan some additional steps + bool function_has_commands = Project::get()->hasCommands(func.shared_from_this()); + if(function_has_commands) { + qDebug() << "Function "< m_recently_executed; QVector m_commands; @@ -70,6 +70,7 @@ public: bool processOne(CommandContext *ctx); void processAll(CommandContext *ctx); void clear(); + bool isEmpty() const { return m_commands.isEmpty(); } signals: void streamCompleted(bool success); void streamChanged(); diff --git a/src/DccFrontend.cpp b/src/DccFrontend.cpp index 3aacc33..62e7dfa 100644 --- a/src/DccFrontend.cpp +++ b/src/DccFrontend.cpp @@ -212,10 +212,12 @@ bool CreateFunction::execute(CommandContext *ctx) { the same as the initial CS segment (of the startup code) */ proj.m_entry_state.setState(rCS, prog.segMain); proj.m_entry_state.IP = prog.offMain; + func->state = proj.m_entry_state; } if(m_name=="start") { proj.addCommand(new MachineStateInitialization); proj.addCommand(new FindMain); + func->state = proj.m_entry_state; // just in case we fail to find main, initialize 'state' } // proj.addCommand(new ProcessFunction); diff --git a/src/dcc.cpp b/src/dcc.cpp index 2172006..788d633 100644 --- a/src/dcc.cpp +++ b/src/dcc.cpp @@ -92,7 +92,7 @@ void setupOptions(QCoreApplication &app) { int main(int argc, char **argv) { QCoreApplication::setApplicationName("dcc"); - QCoreApplication::setApplicationVersion("0.1"); + QCoreApplication::setApplicationVersion("0.2"); if(argc==1) { QApplication app(argc,argv); DccMainWindow win; diff --git a/src/dcc_interface.cpp b/src/dcc_interface.cpp index 654bdc9..95fe957 100644 --- a/src/dcc_interface.cpp +++ b/src/dcc_interface.cpp @@ -28,7 +28,7 @@ public: Project::get()->create(name); return Project::get()->addLoadCommands(name); } - void prtout_asm(IStructuredTextTarget *tgt, int level) + void prtout_asm(PtrFunction f,IStructuredTextTarget *tgt, int level) override { // if (m_current_func->nStep == 0) // return; @@ -36,9 +36,9 @@ public: // XmlOutPro out(iOut); // FuncLL the(m_Cur_Func->ll.m_asmlist); // the.prtout_asm(m_Cur_Func, &m_Cur_Func->m_varll, &out); - m_current_func->toStructuredText(tgt,level); + f->toStructuredText(tgt,level); } - void prtout_cpp(IStructuredTextTarget *, int level) + void prtout_cpp(PtrFunction f,IStructuredTextTarget *, int level) override { } bool isValidFuncHandle(ilFunction f) { diff --git a/src/project.cpp b/src/project.cpp index 404064d..fcab187 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -154,6 +154,26 @@ bool Project::addCommand(PtrFunction f, Command *cmd) return res; } +bool Project::hasCommands(const PtrFunction & f) +{ + auto iter = m_function_streams.find(f); + if(iter!=m_function_streams.end()) { + return not iter->second.isEmpty(); + } + return false; +} + +CommandStream *Project::functionCommands(const PtrFunction & f) +{ + if(f==nullptr) + return nullptr; + auto iter = m_function_streams.find(f); + if(iter!=m_function_streams.end()) { + return &iter->second; + } + return nullptr; +} + void Project::onCommandStreamFinished(bool state) { if(false==state) { @@ -196,6 +216,19 @@ void Project::processCommands(int count) { } emit commandListChanged(); } +void Project::processFunctionCommands(const PtrFunction &func,int count) { + m_command_ctx.m_project = this; + m_command_ctx.m_func = func; + CommandStream *cs = functionCommands(func); + if(nullptr==cs) + return; + while(count--) { + if(false==cs->processOne(&m_command_ctx)) { + break; + } + } + emit commandListChanged(); +} void Project::resetCommandsAndErrorState() { m_error_state = false; diff --git a/src/ui/CommandQueueView.cpp b/src/ui/CommandQueueView.cpp index 00b867e..0a10e3b 100644 --- a/src/ui/CommandQueueView.cpp +++ b/src/ui/CommandQueueView.cpp @@ -33,21 +33,39 @@ void CommandQueueView::changeEvent(QEvent *e) void CommandQueueView::onCommandListChanged() { Project &project(*Project::get()); ui->lstQueuedCommands->clear(); - const CommandStream& cs(project.m_project_command_stream); - for(const Command * cmd : cs.m_commands) { + CommandStream * func_stream = project.functionCommands(m_current_function); + if(func_stream) { + for(const Command * cmd : func_stream->m_commands) { + ui->lstQueuedCommands->addItem(cmd->instanceDescription()); + } + } + const CommandStream& project_commands(project.m_project_command_stream); + for(const Command * cmd : project_commands.m_commands) { ui->lstQueuedCommands->addItem(cmd->instanceDescription()); } } +void CommandQueueView::onCurrentFunctionChanged(PtrFunction func) +{ + m_current_function=func; + onCommandListChanged(); +} + void CommandQueueView::on_btnStep_clicked() { Project &project(*Project::get()); - project.processCommands(1); + if(nullptr!=m_current_function and project.hasCommands(m_current_function)) + project.processFunctionCommands(m_current_function,1); + else + project.processCommands(1); } void CommandQueueView::on_btnPlan_clicked() { AutomatedPlanner planner; - // TODO: Use some kind of UI context to retrieve currently selected function - //planner.planFor(func); + if(m_current_function!=nullptr) { + planner.planFor(*m_current_function); + } + else + planner.planFor(*Project::get()); } diff --git a/src/ui/CommandQueueView.h b/src/ui/CommandQueueView.h index c5c49e1..7d29d62 100644 --- a/src/ui/CommandQueueView.h +++ b/src/ui/CommandQueueView.h @@ -2,6 +2,8 @@ #define COMMANDQUEUEVIEW_H #include +#include "Procedure.h" + namespace Ui { class CommandQueueView; @@ -17,6 +19,7 @@ public: public slots: void onCommandListChanged(); + void onCurrentFunctionChanged(PtrFunction func); protected: void changeEvent(QEvent *e); @@ -28,6 +31,7 @@ private slots: private: Ui::CommandQueueView *ui; + PtrFunction m_current_function; }; #endif // COMMANDQUEUEVIEW_H diff --git a/src/ui/DccMainWindow.cpp b/src/ui/DccMainWindow.cpp index 13ddb02..00fd6ed 100644 --- a/src/ui/DccMainWindow.cpp +++ b/src/ui/DccMainWindow.cpp @@ -30,13 +30,17 @@ DccMainWindow::DccMainWindow(QWidget *parent) : m_command_queue = new CommandQueueView(this); m_functionlist_widget = new FunctionListDockWidget(this); m_functionlist_widget->setWindowTitle(QApplication::tr("Function list")); + connect(m_functionlist_widget,SIGNAL(selectFunction(PtrFunction)),SLOT(onFunctionSelected(PtrFunction))); connect(m_functionlist_widget,SIGNAL(displayRequested()), SLOT(displayCurrentFunction())); + // we are beeing signalled when display is requested connect(this,SIGNAL(functionListChanged()), m_functionlist_widget->model(),SLOT(updateFunctionList())); connect(Project::get(),SIGNAL(newFunctionCreated(PtrFunction)),SLOT(onNewFunction(PtrFunction))); this->addDockWidget(Qt::RightDockWidgetArea,m_functionlist_widget); this->addDockWidget(Qt::LeftDockWidgetArea,m_command_queue); + connect(m_functionlist_widget,&FunctionListDockWidget::selectFunction, + m_command_queue, &CommandQueueView::onCurrentFunctionChanged); m_asm_view = new FunctionViewWidget(this); m_asm_view->setWindowTitle(tr("Assembly listing")); ui->mdiArea->addSubWindow(m_asm_view); @@ -64,6 +68,9 @@ void DccMainWindow::changeEvent(QEvent *e) break; } } +void DccMainWindow::onFunctionSelected(PtrFunction func) { + m_selected_func = func; +} void DccMainWindow::onNewFunction(PtrFunction f) { emit functionListChanged(); } @@ -72,7 +79,7 @@ void DccMainWindow::onOptim() Project::get()->processCommands(); g_EXE2C->analysis_Once(); emit functionListChanged(); - if(m_last_display==g_EXE2C->GetCurFuncHandle()) + if(m_last_display==m_selected_func) { displayCurrentFunction(); } @@ -82,7 +89,7 @@ void DccMainWindow::onOptim10() for(int i=0; i<10; i++) g_EXE2C->analysis_Once(); emit functionListChanged(); - if(m_last_display==g_EXE2C->GetCurFuncHandle()) + if(m_last_display==m_selected_func) { displayCurrentFunction(); } @@ -103,11 +110,11 @@ void DccMainWindow::onOpenFile_Action() void DccMainWindow::displayCurrentFunction() { - if(m_last_display!=g_EXE2C->GetCurFuncHandle()) - m_last_display=g_EXE2C->GetCurFuncHandle(); - g_EXE2C->prtout_asm(m_asm_view); + if(m_last_display!=m_selected_func) + m_last_display=m_selected_func; + g_EXE2C->prtout_asm(m_last_display, m_asm_view); //g_EXE2C->prtout_itn(m_internal_view); - g_EXE2C->prtout_cpp(m_c_view); + g_EXE2C->prtout_cpp(m_last_display,m_c_view); } void DccMainWindow::prt_log(const char *v) { diff --git a/src/ui/DccMainWindow.h b/src/ui/DccMainWindow.h index daf2aa1..3f5d0e0 100644 --- a/src/ui/DccMainWindow.h +++ b/src/ui/DccMainWindow.h @@ -35,6 +35,7 @@ protected: private slots: void on_actionExit_triggered(); void onNewFunction(PtrFunction f); + void onFunctionSelected(PtrFunction func); private: FunctionViewWidget *m_asm_view; @@ -44,6 +45,7 @@ private: FunctionListDockWidget *m_functionlist_widget; Ui::DccMainWindow *ui; PtrFunction m_last_display; + PtrFunction m_selected_func; }; #endif // EXE2C_MAINWINDOW_H diff --git a/src/ui/FunctionListDockWidget.cpp b/src/ui/FunctionListDockWidget.cpp index 34fee5e..6fe9832 100644 --- a/src/ui/FunctionListDockWidget.cpp +++ b/src/ui/FunctionListDockWidget.cpp @@ -21,15 +21,16 @@ FunctionListDockWidget::~FunctionListDockWidget() { delete ui; } -void FunctionListDockWidget::functionSelected(const QModelIndex &idx) +void FunctionListDockWidget::onFunctionSelected(const QModelIndex &idx) { QVariant v=m_list_model.data(m_list_model.index(idx.row(),0),Qt::DisplayRole); qDebug()<<"changed function to "<SetCurFunc_by_Name(v.toString()); + PtrFunction p(Project::get()->findByName(v.toString())); + emit selectFunction(p); } // signalled by m_func_list_view accepted signal -void FunctionListDockWidget::displayRequest(const QModelIndex &) +void FunctionListDockWidget::onDisplayRequested(const QModelIndex &) { // argument ignored since functionSelected must've been called before us emit displayRequested(); @@ -38,6 +39,17 @@ void FunctionListModel::updateFunctionList() { rebuildFunctionList(); } + +void FunctionListModel::add_function(const QString & name, DecompilationStep step, int start_off, int end_off, int stack_purge) +{ + function_info info; + info.m_name=name; + info.m_decoding_step=step; + info.m_start_off=start_off; + info.m_end_off=end_off; + info.m_stack_purge=stack_purge; + m_list.push_back(info); +} void FunctionListModel::rebuildFunctionList() { Project &project(*Project::get()); diff --git a/src/ui/FunctionListDockWidget.h b/src/ui/FunctionListDockWidget.h index c882e6f..289c2e9 100644 --- a/src/ui/FunctionListDockWidget.h +++ b/src/ui/FunctionListDockWidget.h @@ -3,7 +3,9 @@ #include #include -//#include "exe2c.h" + +#include "Procedure.h" + enum DecompilationStep : uint32_t; class FunctionListModel : public QAbstractTableModel { @@ -31,17 +33,7 @@ public slots: void updateFunctionList(); protected: - void add_function(const QString &name,DecompilationStep step,int start_off,int end_off,int stack_purge) - { - - function_info info; - info.m_name=name; - info.m_decoding_step=step; - info.m_start_off=start_off; - info.m_end_off=end_off; - info.m_stack_purge=stack_purge; - m_list.push_back(info); - } + void add_function(const QString &name,DecompilationStep step,int start_off,int end_off,int stack_purge); void rebuildFunctionList(); }; @@ -59,11 +51,12 @@ public: ~FunctionListDockWidget(); FunctionListModel *model() {return &m_list_model;} public slots: - void displayRequest(const QModelIndex &idx); - void functionSelected(const QModelIndex &idx); + void onDisplayRequested(const QModelIndex &idx); + void onFunctionSelected(const QModelIndex &idx); signals: void displayRequested(); + void selectFunction(PtrFunction p); private: Ui::FunctionListDockWidget *ui; FunctionListModel m_list_model; diff --git a/src/ui/FunctionListDockWidget.ui b/src/ui/FunctionListDockWidget.ui index 50efeb7..e9e12c2 100644 --- a/src/ui/FunctionListDockWidget.ui +++ b/src/ui/FunctionListDockWidget.ui @@ -32,10 +32,43 @@ - + + + m_func_list_view + activated(QModelIndex) + FunctionListDockWidget + onDisplayRequested(QModelIndex) + + + 267 + 97 + + + 573 + 154 + + + + + m_func_list_view + clicked(QModelIndex) + FunctionListDockWidget + onFunctionSelected(QModelIndex) + + + 283 + 211 + + + 508 + 253 + + + + displayRequested() - displayRequest(QModelIndex) - functionSelected(QModelIndex) + onDisplayRequested(QModelIndex) + onFunctionSelected(QModelIndex)