Function's command queue implemented, flow control scanning starts to

work.
This commit is contained in:
nemerle 2016-05-05 14:28:25 +02:00
parent c8fd3a01df
commit 6ade935e37
15 changed files with 152 additions and 40 deletions

View File

@ -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;
};

View File

@ -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:

View File

@ -3,6 +3,7 @@
#include "project.h"
#include "FollowControlFlow.h"
#include <QtCore/QDebug>
/**
* @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 "<<func.name<<"still has some commands queued, planning skipped";
}
switch(func.nStep) {
case eNotDecoded:
addAction(func,new FollowControlFlow(func.state));

View File

@ -61,7 +61,7 @@ public:
class CommandStream : public QObject
{
Q_OBJECT
int m_maximum_command_count;
int m_maximum_command_count=5;
public:
QVector<Command *> m_recently_executed;
QVector<Command *> 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();

View File

@ -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);

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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());
}

View File

@ -2,6 +2,8 @@
#define COMMANDQUEUEVIEW_H
#include <QtWidgets/QDockWidget>
#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

View File

@ -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)
{

View File

@ -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

View File

@ -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 "<<v;
g_EXE2C->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());

View File

@ -3,7 +3,9 @@
#include <QAbstractTableModel>
#include <QDockWidget>
//#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;

View File

@ -32,10 +32,43 @@
</widget>
</widget>
<resources/>
<connections/>
<connections>
<connection>
<sender>m_func_list_view</sender>
<signal>activated(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>onDisplayRequested(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>267</x>
<y>97</y>
</hint>
<hint type="destinationlabel">
<x>573</x>
<y>154</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_func_list_view</sender>
<signal>clicked(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>onFunctionSelected(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>283</x>
<y>211</y>
</hint>
<hint type="destinationlabel">
<x>508</x>
<y>253</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<signal>displayRequested()</signal>
<slot>displayRequest(QModelIndex)</slot>
<slot>functionSelected(QModelIndex)</slot>
<slot>onDisplayRequested(QModelIndex)</slot>
<slot>onFunctionSelected(QModelIndex)</slot>
</slots>
</ui>