Implementation
This commit is contained in:
parent
b2be1cf2da
commit
62d8633113
@ -1,11 +1,6 @@
|
|||||||
PROJECT(dcc_original)
|
PROJECT(dcc_original)
|
||||||
cmake_minimum_required(VERSION 2.8.9)
|
cmake_minimum_required(VERSION 2.8.9)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
find_package(Qt5Core)
|
|
||||||
|
|
||||||
OPTION(dcc_build_tests "Enable unit tests." OFF)
|
|
||||||
#SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
|
|
||||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
|
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
|
||||||
IF(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
|
IF(CMAKE_BUILD_TOOL MATCHES "(msdev|devenv|nmake)")
|
||||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D_CRT_NONSTDC_NO_DEPRECATE -DNOMINMAX)
|
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D_CRT_NONSTDC_NO_DEPRECATE -DNOMINMAX)
|
||||||
@ -18,6 +13,13 @@ ENDIF()
|
|||||||
|
|
||||||
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH})
|
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH})
|
||||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
|
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
find_package(Qt5Core)
|
||||||
|
find_package(Qt5Widgets)
|
||||||
|
|
||||||
|
OPTION(dcc_build_tests "Enable unit tests." OFF)
|
||||||
include(cotire)
|
include(cotire)
|
||||||
FIND_PACKAGE(Boost)
|
FIND_PACKAGE(Boost)
|
||||||
IF(dcc_build_tests)
|
IF(dcc_build_tests)
|
||||||
@ -86,6 +88,11 @@ set(dcc_LIB_SOURCES
|
|||||||
src/udm.cpp
|
src/udm.cpp
|
||||||
src/BasicBlock.cpp
|
src/BasicBlock.cpp
|
||||||
src/dcc_interface.cpp
|
src/dcc_interface.cpp
|
||||||
|
|
||||||
|
src/Command.cpp
|
||||||
|
src/Command.h
|
||||||
|
src/Loaders.cpp
|
||||||
|
src/Loaders.h
|
||||||
)
|
)
|
||||||
set(dcc_SOURCES
|
set(dcc_SOURCES
|
||||||
src/dcc.cpp
|
src/dcc.cpp
|
||||||
@ -133,10 +140,10 @@ ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS})
|
|||||||
qt5_use_modules(dcc_lib Core)
|
qt5_use_modules(dcc_lib Core)
|
||||||
#cotire(dcc_lib)
|
#cotire(dcc_lib)
|
||||||
|
|
||||||
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_HEADERS})
|
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES})
|
||||||
ADD_DEPENDENCIES(dcc_original dcc_lib)
|
ADD_DEPENDENCIES(dcc_original dcc_lib)
|
||||||
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport)
|
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport)
|
||||||
qt5_use_modules(dcc_original Core)
|
qt5_use_modules(dcc_original Core Widgets)
|
||||||
#ADD_SUBDIRECTORY(gui)
|
#ADD_SUBDIRECTORY(gui)
|
||||||
if(dcc_build_tests)
|
if(dcc_build_tests)
|
||||||
ADD_SUBDIRECTORY(src)
|
ADD_SUBDIRECTORY(src)
|
||||||
|
|||||||
@ -1,15 +1,17 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QObject>
|
#include <QtCore/QObject>
|
||||||
class Project;
|
class Project;
|
||||||
class DccFrontend : public QObject
|
class DccFrontend : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
void LoadImage();
|
void LoadImage();
|
||||||
void parse(Project &proj);
|
void parse(Project &proj);
|
||||||
std::string m_fname;
|
|
||||||
public:
|
public:
|
||||||
explicit DccFrontend(QObject *parent = 0);
|
explicit DccFrontend(QObject *parent = 0);
|
||||||
bool FrontEnd(); /* frontend.c */
|
bool FrontEnd(); /* frontend.c */
|
||||||
|
void initializeMachineState(Project & proj);
|
||||||
|
|
||||||
|
void createEntryProc(Project &proj);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
|
|||||||
@ -1,51 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include <stdint.h>
|
#include "symtab.h"
|
||||||
#include <cassert>
|
#include "BinaryImage.h"
|
||||||
#include <list>
|
#include "Procedure.h"
|
||||||
|
#include "state.h"
|
||||||
|
#include "src/Command.h"
|
||||||
|
|
||||||
#include <llvm/ADT/ilist.h>
|
#include <llvm/ADT/ilist.h>
|
||||||
#include <boost/icl/interval.hpp>
|
#include <boost/icl/interval.hpp>
|
||||||
#include <boost/icl/interval_map.hpp>
|
#include <boost/icl/interval_map.hpp>
|
||||||
#include <boost/icl/split_interval_map.hpp>
|
#include <boost/icl/split_interval_map.hpp>
|
||||||
#include <unordered_set>
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include "symtab.h"
|
#include <list>
|
||||||
#include "BinaryImage.h"
|
#include <unordered_set>
|
||||||
#include "Procedure.h"
|
#include <string>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
class QString;
|
class QString;
|
||||||
class SourceMachine;
|
class SourceMachine;
|
||||||
struct CALL_GRAPH;
|
struct CALL_GRAPH;
|
||||||
class IProject
|
struct DosLoader;
|
||||||
{
|
|
||||||
virtual PROG *binary()=0;
|
|
||||||
virtual const QString & project_name() const =0;
|
|
||||||
virtual const QString & binary_path() const =0;
|
|
||||||
};
|
|
||||||
class Project : public IProject
|
|
||||||
{
|
|
||||||
static Project *s_instance;
|
|
||||||
QString m_fname;
|
|
||||||
QString m_project_name;
|
|
||||||
QString m_output_path;
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
class Project : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
typedef llvm::iplist<Function> FunctionListType;
|
typedef llvm::iplist<Function> FunctionListType;
|
||||||
typedef FunctionListType lFunction;
|
typedef FunctionListType lFunction;
|
||||||
typedef FunctionListType::iterator ilFunction;
|
typedef FunctionListType::iterator ilFunction;
|
||||||
|
|
||||||
SYMTAB symtab; /* Global symbol table */
|
public:
|
||||||
FunctionListType pProcList;
|
DosLoader * m_selected_loader;
|
||||||
CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */
|
uint32_t SynthLab; //!< Last snthetic lab idx
|
||||||
PROG prog; /* Loaded program image parameters */
|
SYMTAB symtab; //!< Global symbol table
|
||||||
// no copies
|
FunctionListType pProcList; //!< List of located functions
|
||||||
|
CALL_GRAPH * callGraph; //!< Pointer to the head of the call graph
|
||||||
|
STATE m_entry_state; //!< Machine state at program load
|
||||||
|
|
||||||
|
PROG prog; /* Loaded program image parameters */
|
||||||
|
CommandStream m_project_command_stream;
|
||||||
|
bool m_error_state;
|
||||||
|
public:
|
||||||
|
// prevent Project instance copying
|
||||||
Project(const Project&) = delete;
|
Project(const Project&) = delete;
|
||||||
const Project & operator=(const Project & l) =delete;
|
const Project & operator=(const Project & l) =delete;
|
||||||
// only moves
|
// only moves
|
||||||
Project(); // default constructor,
|
Project(); // default constructor,
|
||||||
|
|
||||||
public:
|
|
||||||
void create(const QString &a);
|
void create(const QString &a);
|
||||||
bool load();
|
|
||||||
|
bool addLoadCommands();
|
||||||
|
void processAllCommands();
|
||||||
|
void resetCommandsAndErrorState();
|
||||||
|
|
||||||
const QString & output_path() const {return m_output_path;}
|
const QString & output_path() const {return m_output_path;}
|
||||||
const QString & project_name() const {return m_project_name;}
|
const QString & project_name() const {return m_project_name;}
|
||||||
const QString & binary_path() const {return m_fname;}
|
const QString & binary_path() const {return m_fname;}
|
||||||
@ -68,8 +76,23 @@ public:
|
|||||||
|
|
||||||
const FunctionListType &functions() const { return pProcList; }
|
const FunctionListType &functions() const { return pProcList; }
|
||||||
FunctionListType &functions() { return pProcList; }
|
FunctionListType &functions() { return pProcList; }
|
||||||
|
template<class COMMANDCLASS>
|
||||||
|
bool addCommand() {
|
||||||
|
return m_project_command_stream.add(new COMMANDCLASS);
|
||||||
|
}
|
||||||
|
void dumpAllErrors();
|
||||||
|
public slots:
|
||||||
|
void onCommandStreamFinished(bool state);
|
||||||
protected:
|
protected:
|
||||||
void initialize();
|
void initialize();
|
||||||
void writeGlobSymTable();
|
void writeGlobSymTable();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static Project * s_instance;
|
||||||
|
QString m_fname;
|
||||||
|
QString m_project_name;
|
||||||
|
QString m_output_path;
|
||||||
|
CommandContext m_command_ctx;
|
||||||
|
|
||||||
};
|
};
|
||||||
//extern Project g_proj;
|
//extern Project g_proj;
|
||||||
|
|||||||
@ -3,21 +3,22 @@
|
|||||||
* (C) Cristina Cifuentes, Mike van Emmerik
|
* (C) Cristina Cifuentes, Mike van Emmerik
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
|
||||||
#include <cstring>
|
|
||||||
#include "machine_x86.h"
|
#include "machine_x86.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* STATE TABLE */
|
/* STATE TABLE */
|
||||||
struct STATE
|
struct STATE
|
||||||
{
|
{
|
||||||
uint32_t IP; /* Offset into Image */
|
uint32_t IP; /* Offset into Image */
|
||||||
int16_t r[INDEX_BX_SI]; /* Value of segs and AX */
|
int16_t r[INDEX_BX_SI]; /* Register values */
|
||||||
bool f[INDEX_BX_SI]; /* True if r[.] has a value */
|
bool f[INDEX_BX_SI]; /* True if r[.] has a value */
|
||||||
struct
|
struct
|
||||||
{ /* For case stmt indexed reg */
|
{ /* For case stmt indexed reg */
|
||||||
uint8_t regi; /* Last conditional jump */
|
uint8_t regi; /* Last conditional jump */
|
||||||
int16_t immed; /* Contents of the previous register */
|
int16_t immed; /* Contents of the previous register */
|
||||||
} JCond;
|
} JCond;
|
||||||
void setState(uint16_t reg, int16_t value);
|
void setState(uint16_t reg, int16_t value);
|
||||||
void checkStartup();
|
void checkStartup();
|
||||||
bool isKnown(eReg v) {return f[v];}
|
bool isKnown(eReg v) {return f[v];}
|
||||||
|
|||||||
@ -10,6 +10,9 @@
|
|||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class QTextStream;
|
||||||
|
|
||||||
struct Expr;
|
struct Expr;
|
||||||
struct AstIdent;
|
struct AstIdent;
|
||||||
struct TypeContainer;
|
struct TypeContainer;
|
||||||
|
|||||||
97
src/Command.cpp
Normal file
97
src/Command.cpp
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
#include "project.h"
|
||||||
|
#include "Loaders.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
bool LoaderSelection::execute(CommandContext * ctx, Project *p)
|
||||||
|
{
|
||||||
|
if(p->binary_path().isEmpty()) {
|
||||||
|
ctx->recordFailure(this,QString("No executable path set in project %1").arg(p->project_name()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile finfo(p->binary_path());
|
||||||
|
/* Open the input file */
|
||||||
|
if(not finfo.open(QFile::ReadOnly)) {
|
||||||
|
ctx->recordFailure(this,QString("Cannot open file %1").arg(p->binary_path()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Read in first 2 bytes to check EXE signature */
|
||||||
|
if (finfo.size()<=2)
|
||||||
|
{
|
||||||
|
ctx->recordFailure(this,QString("File %1 is too small").arg(p->binary_path()));
|
||||||
|
}
|
||||||
|
ComLoader com_loader;
|
||||||
|
ExeLoader exe_loader;
|
||||||
|
|
||||||
|
if(exe_loader.canLoad(finfo)) {
|
||||||
|
p->m_selected_loader = new ExeLoader;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(com_loader.canLoad(finfo)) {
|
||||||
|
p->m_selected_loader = new ComLoader;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ctx->recordFailure(this,QString("None of the available loaders can load file %1").arg(p->binary_path()));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoaderApplication::execute(CommandContext * ctx, Project *p)
|
||||||
|
{
|
||||||
|
if(!p)
|
||||||
|
return false;
|
||||||
|
if(!p->m_selected_loader) {
|
||||||
|
ctx->recordFailure(this,QString("No loader selected for project %1").arg(p->project_name()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QFile finfo(p->binary_path());
|
||||||
|
if(not finfo.open(QFile::ReadOnly)) {
|
||||||
|
ctx->recordFailure(this,QString("Cannot open file %1").arg(p->binary_path()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return p->m_selected_loader->load(p->prog,finfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommandStream::add(Command * c) {
|
||||||
|
if(m_commands.size()>=m_maximum_command_count)
|
||||||
|
return false;
|
||||||
|
m_commands.push_back(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandStream::setMaximumCommandCount(int maximum_command_count) {
|
||||||
|
m_maximum_command_count = maximum_command_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandStream::processAll(CommandContext *ctx)
|
||||||
|
{
|
||||||
|
while(not m_commands.isEmpty()) {
|
||||||
|
Command *cmd = m_commands.takeFirst();
|
||||||
|
if(false==cmd->execute(ctx,ctx->proj)) {
|
||||||
|
emit streamCompleted(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_recently_executed.push_back(cmd);
|
||||||
|
}
|
||||||
|
emit streamCompleted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandStream::clear()
|
||||||
|
{
|
||||||
|
qDeleteAll(m_commands);
|
||||||
|
qDeleteAll(m_recently_executed);
|
||||||
|
m_commands.clear();
|
||||||
|
m_recently_executed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CommandContext::reset()
|
||||||
|
{
|
||||||
|
for(int i=0; i<m_failures.size(); ++i) {
|
||||||
|
delete m_failures[i].first;
|
||||||
|
}
|
||||||
|
m_failures.clear();
|
||||||
|
}
|
||||||
81
src/Command.h
Normal file
81
src/Command.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#ifndef COMMAND_H
|
||||||
|
#define COMMAND_H
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QVector>
|
||||||
|
#include <QtCore/QPair>
|
||||||
|
|
||||||
|
class Project;
|
||||||
|
enum CommandLevel {
|
||||||
|
eProject,
|
||||||
|
eBinary,
|
||||||
|
eFunction,
|
||||||
|
eBasicBlock,
|
||||||
|
eInstruction
|
||||||
|
};
|
||||||
|
class Command;
|
||||||
|
|
||||||
|
class CommandContext {
|
||||||
|
public:
|
||||||
|
void recordFailure(Command *cmd,QString error_message) {
|
||||||
|
m_failures.push_back({cmd,error_message});
|
||||||
|
}
|
||||||
|
|
||||||
|
Project *proj;
|
||||||
|
QVector<QPair<Command *,QString>> m_failures;
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Command
|
||||||
|
{
|
||||||
|
QString m_command_name;
|
||||||
|
CommandLevel m_level;
|
||||||
|
public:
|
||||||
|
Command(QString n,CommandLevel level) : m_command_name(n),m_level(level) {}
|
||||||
|
QString name() const { return m_command_name;}
|
||||||
|
virtual bool execute(CommandContext *,Project *) { return false; }
|
||||||
|
};
|
||||||
|
class CompoundCommand : public Command {
|
||||||
|
QVector<Command *> m_contained;
|
||||||
|
public:
|
||||||
|
CompoundCommand(QString n,CommandLevel l) : Command(n,l) {
|
||||||
|
}
|
||||||
|
void addCommand(Command *c) {
|
||||||
|
m_contained.push_back(c);
|
||||||
|
}
|
||||||
|
bool execute(CommandContext * ctx,Project *v) {
|
||||||
|
for(Command * c : m_contained) {
|
||||||
|
if(!c->execute(ctx,v))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class CommandStream : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
int m_maximum_command_count;
|
||||||
|
public:
|
||||||
|
QVector<Command *> m_recently_executed;
|
||||||
|
QVector<Command *> m_commands;
|
||||||
|
bool add(Command *c);
|
||||||
|
void setMaximumCommandCount(int maximum_command_count);
|
||||||
|
void processAll(CommandContext *ctx);
|
||||||
|
void clear();
|
||||||
|
signals:
|
||||||
|
void streamCompleted(bool success);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoaderSelection : public Command {
|
||||||
|
public:
|
||||||
|
virtual ~LoaderSelection() {}
|
||||||
|
LoaderSelection() : Command("Select loader",eProject) {}
|
||||||
|
bool execute(CommandContext * ctx,Project *) override;
|
||||||
|
};
|
||||||
|
class LoaderApplication : public Command {
|
||||||
|
public:
|
||||||
|
virtual ~LoaderApplication() {}
|
||||||
|
LoaderApplication() : Command("Apply loader",eProject) {}
|
||||||
|
bool execute(CommandContext * ctx,Project *) override;
|
||||||
|
};
|
||||||
|
#endif // COMMAND_H
|
||||||
@ -11,11 +11,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
|
||||||
class Loader
|
|
||||||
{
|
|
||||||
bool loadIntoProject(IProject *);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PSP { /* PSP structure */
|
struct PSP { /* PSP structure */
|
||||||
uint16_t int20h; /* interrupt 20h */
|
uint16_t int20h; /* interrupt 20h */
|
||||||
uint16_t eof; /* segment, end of allocation block */
|
uint16_t eof; /* segment, end of allocation block */
|
||||||
@ -325,53 +320,21 @@ struct ExeLoader : public DosLoader {
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* LoadImage
|
* LoadImage
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
bool Project::load()
|
void DccFrontend::initializeMachineState(Project &proj)
|
||||||
{
|
{
|
||||||
// addTask(loaderSelection,PreCond(BinaryImage))
|
const PROG &prog(proj.prog);
|
||||||
// addTask(applyLoader,PreCond(Loader))
|
proj.m_entry_state.setState(rES, 0); /* PSP segment */
|
||||||
const char *fname = binary_path().toLocal8Bit().data();
|
proj.m_entry_state.setState(rDS, 0);
|
||||||
QFile finfo(binary_path());
|
proj.m_entry_state.setState(rCS, prog.initCS);
|
||||||
/* Open the input file */
|
proj.m_entry_state.setState(rSS, prog.initSS);
|
||||||
if(not finfo.open(QFile::ReadOnly)) {
|
proj.m_entry_state.setState(rSP, prog.initSP);
|
||||||
fatalError(CANNOT_OPEN, fname);
|
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
||||||
}
|
proj.SynthLab = SYNTHESIZED_MIN;
|
||||||
/* Read in first 2 bytes to check EXE signature */
|
|
||||||
if (finfo.size()<=2)
|
|
||||||
{
|
|
||||||
fatalError(CANNOT_READ, fname);
|
|
||||||
}
|
|
||||||
ComLoader com_loader;
|
|
||||||
ExeLoader exe_loader;
|
|
||||||
if(exe_loader.canLoad(finfo)) {
|
|
||||||
prog.fCOM = false;
|
|
||||||
return exe_loader.load(prog,finfo);
|
|
||||||
}
|
|
||||||
if(com_loader.canLoad(finfo)) {
|
|
||||||
prog.fCOM = true;
|
|
||||||
return com_loader.load(prog,finfo);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
uint32_t SynthLab;
|
|
||||||
/* Parses the program, builds the call graph, and returns the list of
|
void DccFrontend::createEntryProc(Project &proj)
|
||||||
* procedures found */
|
|
||||||
void DccFrontend::parse(Project &proj)
|
|
||||||
{
|
{
|
||||||
PROG &prog(proj.prog);
|
PROG &prog(proj.prog);
|
||||||
STATE state;
|
|
||||||
|
|
||||||
/* Set initial state */
|
|
||||||
state.setState(rES, 0); /* PSP segment */
|
|
||||||
state.setState(rDS, 0);
|
|
||||||
state.setState(rCS, prog.initCS);
|
|
||||||
state.setState(rSS, prog.initSS);
|
|
||||||
state.setState(rSP, prog.initSP);
|
|
||||||
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
|
||||||
SynthLab = SYNTHESIZED_MIN;
|
|
||||||
|
|
||||||
/* Check for special settings of initial state, based on idioms of the
|
|
||||||
startup code */
|
|
||||||
state.checkStartup();
|
|
||||||
ilFunction start_proc;
|
ilFunction start_proc;
|
||||||
/* Make a struct for the initial procedure */
|
/* Make a struct for the initial procedure */
|
||||||
if (prog.offMain != -1)
|
if (prog.offMain != -1)
|
||||||
@ -384,30 +347,43 @@ void DccFrontend::parse(Project &proj)
|
|||||||
start_proc->procEntry = prog.offMain;
|
start_proc->procEntry = prog.offMain;
|
||||||
/* In medium and large models, the segment of main may (will?) not be
|
/* In medium and large models, the segment of main may (will?) not be
|
||||||
the same as the initial CS segment (of the startup code) */
|
the same as the initial CS segment (of the startup code) */
|
||||||
state.setState(rCS, prog.segMain);
|
proj.m_entry_state.setState(rCS, prog.segMain);
|
||||||
state.IP = prog.offMain;
|
proj.m_entry_state.IP = prog.offMain;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start_proc = proj.createFunction(0,"start");
|
start_proc = proj.createFunction(0,"start");
|
||||||
/* Create initial procedure at program start address */
|
/* Create initial procedure at program start address */
|
||||||
start_proc->procEntry = (uint32_t)state.IP;
|
start_proc->procEntry = (uint32_t)proj.m_entry_state.IP;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The state info is for the first procedure */
|
/* The state info is for the first procedure */
|
||||||
start_proc->state = state;
|
start_proc->state = proj.m_entry_state;
|
||||||
|
|
||||||
/* Set up call graph initial node */
|
/* Set up call graph initial node */
|
||||||
proj.callGraph = new CALL_GRAPH;
|
proj.callGraph = new CALL_GRAPH;
|
||||||
proj.callGraph->proc = start_proc;
|
proj.callGraph->proc = start_proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parses the program, builds the call graph, and returns the list of
|
||||||
|
* procedures found */
|
||||||
|
void DccFrontend::parse(Project &proj)
|
||||||
|
{
|
||||||
|
/* Set initial state */
|
||||||
|
initializeMachineState(proj);
|
||||||
|
|
||||||
|
/* Check for special settings of initial state, based on idioms of the
|
||||||
|
startup code */
|
||||||
|
proj.m_entry_state.checkStartup();
|
||||||
|
|
||||||
|
createEntryProc(proj);
|
||||||
|
|
||||||
/* This proc needs to be called to set things up for LibCheck(), which
|
/* This proc needs to be called to set things up for LibCheck(), which
|
||||||
checks a proc to see if it is a know C (etc) library */
|
checks a proc to see if it is a know C (etc) library */
|
||||||
prog.bSigs = SetupLibCheck();
|
proj.prog.bSigs = SetupLibCheck();
|
||||||
//BUG: proj and g_proj are 'live' at this point !
|
//BUG: proj and g_proj are 'live' at this point !
|
||||||
|
|
||||||
/* Recursively build entire procedure list */
|
/* Recursively build entire procedure list */
|
||||||
start_proc->FollowCtrl(proj.callGraph, &state);
|
proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
|
||||||
|
|
||||||
/* This proc needs to be called to clean things up from SetupLibCheck() */
|
/* This proc needs to be called to clean things up from SetupLibCheck() */
|
||||||
CleanupLibCheck();
|
CleanupLibCheck();
|
||||||
|
|||||||
177
src/Loaders.cpp
Normal file
177
src/Loaders.cpp
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#include "Loaders.h"
|
||||||
|
|
||||||
|
#include "dcc.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
|
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
|
||||||
|
|
||||||
|
struct PSP { /* PSP structure */
|
||||||
|
uint16_t int20h; /* interrupt 20h */
|
||||||
|
uint16_t eof; /* segment, end of allocation block */
|
||||||
|
uint8_t res1; /* reserved */
|
||||||
|
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
|
||||||
|
uint8_t int22h[4]; /* vector for terminate routine */
|
||||||
|
uint8_t int23h[4]; /* vector for ctrl+break routine */
|
||||||
|
uint8_t int24h[4]; /* vector for error routine */
|
||||||
|
uint8_t res2[22]; /* reserved */
|
||||||
|
uint16_t segEnv; /* segment address of environment block */
|
||||||
|
uint8_t res3[34]; /* reserved */
|
||||||
|
uint8_t int21h[6]; /* opcode for int21h and far return */
|
||||||
|
uint8_t res4[6]; /* reserved */
|
||||||
|
uint8_t fcb1[16]; /* default file control block 1 */
|
||||||
|
uint8_t fcb2[16]; /* default file control block 2 */
|
||||||
|
uint8_t res5[4]; /* reserved */
|
||||||
|
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct MZHeader { /* EXE file header */
|
||||||
|
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
|
||||||
|
uint8_t sigHi;
|
||||||
|
uint16_t lastPageSize; /* Size of the last page */
|
||||||
|
uint16_t numPages; /* Number of pages in the file */
|
||||||
|
uint16_t numReloc; /* Number of relocation items */
|
||||||
|
uint16_t numParaHeader; /* # of paragraphs in the header */
|
||||||
|
uint16_t minAlloc; /* Minimum number of paragraphs */
|
||||||
|
uint16_t maxAlloc; /* Maximum number of paragraphs */
|
||||||
|
uint16_t initSS; /* Segment displacement of stack */
|
||||||
|
uint16_t initSP; /* Contents of SP at entry */
|
||||||
|
uint16_t checkSum; /* Complemented checksum */
|
||||||
|
uint16_t initIP; /* Contents of IP at entry */
|
||||||
|
uint16_t initCS; /* Segment displacement of code */
|
||||||
|
uint16_t relocTabOffset; /* Relocation table offset */
|
||||||
|
uint16_t overlayNum; /* Overlay number */
|
||||||
|
} header;
|
||||||
|
|
||||||
|
void DosLoader::prepareImage(PROG & prog, size_t sz, QFile & fp) {
|
||||||
|
/* Allocate a block of memory for the program. */
|
||||||
|
prog.cbImage = sz + sizeof(PSP);
|
||||||
|
prog.Imagez = new uint8_t [prog.cbImage];
|
||||||
|
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
|
||||||
|
prog.Imagez[1] = 0x20; /* for termination checking */
|
||||||
|
/* Read in the image past where a PSP would go */
|
||||||
|
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
|
||||||
|
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComLoader::canLoad(QFile & fp) {
|
||||||
|
fp.seek(0);
|
||||||
|
char sig[2];
|
||||||
|
if(2==fp.read(sig,2)) {
|
||||||
|
return not (sig[0] == 0x4D and sig[1] == 0x5A);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ComLoader::load(PROG & prog, QFile & fp) {
|
||||||
|
prog.fCOM = true;
|
||||||
|
fp.seek(0);
|
||||||
|
/* COM file
|
||||||
|
* In this case the load module size is just the file length
|
||||||
|
*/
|
||||||
|
auto cb = fp.size();
|
||||||
|
|
||||||
|
/* COM programs start off with an ORG 100H (to leave room for a PSP)
|
||||||
|
* This is also the implied start address so if we load the image
|
||||||
|
* at offset 100H addresses should all line up properly again.
|
||||||
|
*/
|
||||||
|
prog.initCS = 0;
|
||||||
|
prog.initIP = 0x100;
|
||||||
|
prog.initSS = 0;
|
||||||
|
prog.initSP = 0xFFFE;
|
||||||
|
prog.cReloc = 0;
|
||||||
|
|
||||||
|
prepareImage(prog,cb,fp);
|
||||||
|
|
||||||
|
|
||||||
|
/* Set up memory map */
|
||||||
|
cb = (prog.cbImage + 3) / 4;
|
||||||
|
prog.map = (uint8_t *)malloc(cb);
|
||||||
|
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExeLoader::canLoad(QFile & fp) {
|
||||||
|
if(fp.size()<sizeof(header))
|
||||||
|
return false;
|
||||||
|
MZHeader tmp_header;
|
||||||
|
fp.seek(0);
|
||||||
|
fp.read((char *)&tmp_header, sizeof(header));
|
||||||
|
if(not (tmp_header.sigLo == 0x4D and tmp_header.sigHi == 0x5A))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* This is a typical DOS kludge! */
|
||||||
|
if (LH(&header.relocTabOffset) == 0x40)
|
||||||
|
{
|
||||||
|
qDebug() << "Don't understand new EXE format";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExeLoader::load(PROG & prog, QFile & fp) {
|
||||||
|
prog.fCOM = false;
|
||||||
|
/* Read rest of header */
|
||||||
|
fp.seek(0);
|
||||||
|
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Calculate the load module size.
|
||||||
|
* This is the number of pages in the file
|
||||||
|
* less the length of the header and reloc table
|
||||||
|
* less the number of bytes unused on last page
|
||||||
|
*/
|
||||||
|
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
|
||||||
|
if (header.lastPageSize)
|
||||||
|
{
|
||||||
|
cb -= 512 - LH(&header.lastPageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We quietly ignore minAlloc and maxAlloc since for our
|
||||||
|
* purposes it doesn't really matter where in real memory
|
||||||
|
* the program would end up. EXE programs can't really rely on
|
||||||
|
* their load location so setting the PSP segment to 0 is fine.
|
||||||
|
* Certainly programs that prod around in DOS or BIOS are going
|
||||||
|
* to have to load DS from a constant so it'll be pretty
|
||||||
|
* obvious.
|
||||||
|
*/
|
||||||
|
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
|
||||||
|
prog.initIP = (int16_t)LH(&header.initIP);
|
||||||
|
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
|
||||||
|
prog.initSP = (int16_t)LH(&header.initSP);
|
||||||
|
prog.cReloc = (int16_t)LH(&header.numReloc);
|
||||||
|
|
||||||
|
/* Allocate the relocation table */
|
||||||
|
if (prog.cReloc)
|
||||||
|
{
|
||||||
|
prog.relocTable.resize(prog.cReloc);
|
||||||
|
fp.seek(LH(&header.relocTabOffset));
|
||||||
|
|
||||||
|
/* Read in seg:offset pairs and convert to Image ptrs */
|
||||||
|
uint8_t buf[4];
|
||||||
|
for (int i = 0; i < prog.cReloc; i++)
|
||||||
|
{
|
||||||
|
fp.read((char *)buf,4);
|
||||||
|
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Seek to start of image */
|
||||||
|
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
|
||||||
|
fp.seek(start_of_image);
|
||||||
|
/* Allocate a block of memory for the program. */
|
||||||
|
prepareImage(prog,cb,fp);
|
||||||
|
|
||||||
|
/* Set up memory map */
|
||||||
|
cb = (prog.cbImage + 3) / 4;
|
||||||
|
prog.map = (uint8_t *)malloc(cb);
|
||||||
|
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||||
|
|
||||||
|
/* Relocate segment constants */
|
||||||
|
for(uint32_t v : prog.relocTable) {
|
||||||
|
uint8_t *p = &prog.Imagez[v];
|
||||||
|
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
|
||||||
|
*p++ = (uint8_t)(w & 0x00FF);
|
||||||
|
*p = (uint8_t)((w & 0xFF00) >> 8);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
31
src/Loaders.h
Normal file
31
src/Loaders.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef LOADERS_H
|
||||||
|
#define LOADERS_H
|
||||||
|
|
||||||
|
#include "BinaryImage.h"
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
struct DosLoader {
|
||||||
|
protected:
|
||||||
|
void prepareImage(PROG &prog,size_t sz,QFile &fp);
|
||||||
|
public:
|
||||||
|
virtual bool canLoad(QFile &fp)=0;
|
||||||
|
virtual QString loaderName() const =0;
|
||||||
|
virtual bool load(PROG &prog,QFile &fp)=0;
|
||||||
|
};
|
||||||
|
struct ComLoader : public DosLoader {
|
||||||
|
virtual ~ComLoader() {}
|
||||||
|
|
||||||
|
bool canLoad(QFile &fp) override;
|
||||||
|
bool load(PROG &prog,QFile &fp) override;
|
||||||
|
QString loaderName() const override { return "16-bit DOS - COM loader"; }
|
||||||
|
};
|
||||||
|
struct ExeLoader : public DosLoader {
|
||||||
|
virtual ~ExeLoader() {}
|
||||||
|
|
||||||
|
bool canLoad(QFile &fp) override;
|
||||||
|
bool load(PROG &prog,QFile &fp) override;
|
||||||
|
QString loaderName() const override { return "16-bit DOS - EXE loader"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOADERS_H
|
||||||
14
src/dcc.cpp
14
src/dcc.cpp
@ -185,18 +185,22 @@ int main(int argc, char **argv)
|
|||||||
QCoreApplication::setApplicationVersion("0.1");
|
QCoreApplication::setApplicationVersion("0.1");
|
||||||
setupOptions(app);
|
setupOptions(app);
|
||||||
|
|
||||||
|
Project *proj = Project::get();
|
||||||
/* Front end reads in EXE or COM file, parses it into I-code while
|
/* Front end reads in EXE or COM file, parses it into I-code while
|
||||||
* building the call graph and attaching appropriate bits of code for
|
* building the call graph and attaching appropriate bits of code for
|
||||||
* each procedure.
|
* each procedure.
|
||||||
*/
|
*/
|
||||||
Project::get()->create(option.filename);
|
proj->create(option.filename);
|
||||||
|
|
||||||
DccFrontend fe(&app);
|
DccFrontend fe(&app);
|
||||||
if(not Project::get()->load()) {
|
proj->addLoadCommands();
|
||||||
|
proj->processAllCommands();
|
||||||
|
if(proj->m_error_state) {
|
||||||
|
proj->dumpAllErrors();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (option.verbose)
|
if (option.verbose)
|
||||||
Project::get()->prog.displayLoadInfo();
|
proj->prog.displayLoadInfo();
|
||||||
if(false==fe.FrontEnd ())
|
if(false==fe.FrontEnd ())
|
||||||
return -1;
|
return -1;
|
||||||
if(option.asm1)
|
if(option.asm1)
|
||||||
@ -213,9 +217,9 @@ int main(int argc, char **argv)
|
|||||||
* analysis, data flow etc. and outputs it to output file ready for
|
* analysis, data flow etc. and outputs it to output file ready for
|
||||||
* re-compilation.
|
* re-compilation.
|
||||||
*/
|
*/
|
||||||
BackEnd(Project::get()->callGraph);
|
BackEnd(proj->callGraph);
|
||||||
|
|
||||||
Project::get()->callGraph->write();
|
proj->callGraph->write();
|
||||||
|
|
||||||
if (option.Stats)
|
if (option.Stats)
|
||||||
displayTotalStats();
|
displayTotalStats();
|
||||||
|
|||||||
@ -24,8 +24,6 @@ static void setBits(int16_t type, uint32_t start, uint32_t len);
|
|||||||
static void process_MOV(LLInst &ll, STATE * pstate);
|
static void process_MOV(LLInst &ll, STATE * pstate);
|
||||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||||
void interactDis(Function * initProc, int ic);
|
void interactDis(Function * initProc, int ic);
|
||||||
extern uint32_t SynthLab;
|
|
||||||
|
|
||||||
|
|
||||||
/* Returns the size of the string pointed by sym and delimited by delim.
|
/* Returns the size of the string pointed by sym and delimited by delim.
|
||||||
* Size includes delimiter. */
|
* Size includes delimiter. */
|
||||||
@ -57,7 +55,7 @@ ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
|
|||||||
eIcode.setRegDU( rAX, eUSE);
|
eIcode.setRegDU( rAX, eUSE);
|
||||||
eIcode.setRegDU( rTMP, eDEF);
|
eIcode.setRegDU( rTMP, eDEF);
|
||||||
eIcode.ll()->setFlags( SYNTHETIC );
|
eIcode.ll()->setFlags( SYNTHETIC );
|
||||||
/* eIcode.ll()->label = SynthLab++; */
|
/* eIcode.ll()->label = Project::get()->SynthLab++; */
|
||||||
eIcode.ll()->label = _Icode.ll()->label;
|
eIcode.ll()->label = _Icode.ll()->label;
|
||||||
Icode.addIcode(&eIcode);
|
Icode.addIcode(&eIcode);
|
||||||
|
|
||||||
@ -70,7 +68,7 @@ ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
|
|||||||
eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
|
eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
|
||||||
eIcode.ll()->replaceSrc(_Icode.ll()->src());
|
eIcode.ll()->replaceSrc(_Icode.ll()->src());
|
||||||
eIcode.du = _Icode.du;
|
eIcode.du = _Icode.du;
|
||||||
eIcode.ll()->label = SynthLab++;
|
eIcode.ll()->label = Project::get()->SynthLab++;
|
||||||
return Icode.addIcode(&eIcode);
|
return Icode.addIcode(&eIcode);
|
||||||
}
|
}
|
||||||
ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
|
ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
|
||||||
@ -108,7 +106,7 @@ ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
|
|||||||
}
|
}
|
||||||
eIcode.ll()->replaceSrc(rTMP);
|
eIcode.ll()->replaceSrc(rTMP);
|
||||||
eIcode.setRegDU( rTMP, eUSE);
|
eIcode.setRegDU( rTMP, eUSE);
|
||||||
eIcode.ll()->label = SynthLab++;
|
eIcode.ll()->label = Project::get()->SynthLab++;
|
||||||
return Icode.addIcode(&eIcode);
|
return Icode.addIcode(&eIcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +158,7 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
|
|||||||
_Icode.type = LOW_LEVEL;
|
_Icode.type = LOW_LEVEL;
|
||||||
ll->set(iJMP,I | SYNTHETIC | NO_OPS);
|
ll->set(iJMP,I | SYNTHETIC | NO_OPS);
|
||||||
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
|
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
|
||||||
ll->label = SynthLab++;
|
ll->label = Project::get()->SynthLab++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy Icode to Proc */
|
/* Copy Icode to Proc */
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
#include <QtCore/QString>
|
|
||||||
#include <QtCore/QDir>
|
|
||||||
#include <utility>
|
|
||||||
#include "dcc.h"
|
#include "dcc.h"
|
||||||
#include "CallGraph.h"
|
#include "CallGraph.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "Procedure.h"
|
#include "Procedure.h"
|
||||||
|
|
||||||
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QDir>
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
//Project g_proj;
|
//Project g_proj;
|
||||||
QString asm1_name, asm2_name; /* Assembler output filenames */
|
QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||||
@ -15,10 +18,13 @@ OPTION option; /* Command line options */
|
|||||||
Project *Project::s_instance = nullptr;
|
Project *Project::s_instance = nullptr;
|
||||||
Project::Project() : callGraph(nullptr)
|
Project::Project() : callGraph(nullptr)
|
||||||
{
|
{
|
||||||
|
m_project_command_stream.setMaximumCommandCount(10);
|
||||||
|
connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool)));
|
||||||
memset(&prog,0,sizeof(prog));
|
memset(&prog,0,sizeof(prog));
|
||||||
}
|
}
|
||||||
void Project::initialize()
|
void Project::initialize()
|
||||||
{
|
{
|
||||||
|
resetCommandsAndErrorState();
|
||||||
delete callGraph;
|
delete callGraph;
|
||||||
callGraph = nullptr;
|
callGraph = nullptr;
|
||||||
}
|
}
|
||||||
@ -106,3 +112,38 @@ SourceMachine *Project::machine()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::onCommandStreamFinished(bool state)
|
||||||
|
{
|
||||||
|
if(false==state) {
|
||||||
|
m_error_state = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Project::dumpAllErrors() {
|
||||||
|
for(QPair<Command *,QString> v : m_command_ctx.m_failures) {
|
||||||
|
qDebug() << QString("%1 command failed with : %2").arg(v.first->name()).arg(v.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool Project::addLoadCommands()
|
||||||
|
{
|
||||||
|
if(!addCommand<LoaderSelection>())
|
||||||
|
return false;
|
||||||
|
if(!addCommand<LoaderApplication>()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::processAllCommands()
|
||||||
|
{
|
||||||
|
m_command_ctx.proj = this;
|
||||||
|
m_project_command_stream.processAll(&m_command_ctx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Project::resetCommandsAndErrorState()
|
||||||
|
{
|
||||||
|
m_error_state = false;
|
||||||
|
m_command_ctx.reset();
|
||||||
|
m_command_ctx.proj = this;
|
||||||
|
m_project_command_stream.clear();
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user