Function's command queue implemented, flow control scanning starts to
work.
This commit is contained in:
parent
c8fd3a01df
commit
6ade935e37
@ -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;
|
||||
};
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user