WIP: More GUI work, use shared_ptr to store Function references.
This commit is contained in:
parent
60a4fefe95
commit
0521206de5
@ -95,6 +95,8 @@ set(dcc_LIB_SOURCES
|
||||
src/Command.h
|
||||
src/Loaders.cpp
|
||||
src/Loaders.h
|
||||
src/FollowControlFlow.cpp
|
||||
src/FollowControlFlow.h
|
||||
)
|
||||
set(dcc_UI_SOURCES
|
||||
src/ui/DccMainWindow.ui
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* CALL GRAPH NODE */
|
||||
struct CALL_GRAPH
|
||||
{
|
||||
ilFunction proc; /* Pointer to procedure in pProcList */
|
||||
PtrFunction proc; /* Pointer to procedure in pProcList */
|
||||
std::vector<CALL_GRAPH *> outEdges; /* array of out edges */
|
||||
public:
|
||||
void write();
|
||||
@ -12,8 +12,8 @@ public:
|
||||
}
|
||||
public:
|
||||
void writeNodeCallGraph(int indIdx);
|
||||
bool insertCallGraph(ilFunction caller, ilFunction callee);
|
||||
bool insertCallGraph(Function *caller, ilFunction callee);
|
||||
void insertArc(ilFunction newProc);
|
||||
bool insertCallGraph(PtrFunction caller, PtrFunction callee);
|
||||
//bool insertCallGraph(PtrFunction caller, PtrFunction callee);
|
||||
void insertArc(PtrFunction newProc);
|
||||
};
|
||||
//extern CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
#include <QtCore/QObject>
|
||||
#include "src/Command.h"
|
||||
#include "project.h"
|
||||
|
||||
class Project;
|
||||
class DccFrontend : public QObject
|
||||
{
|
||||
@ -14,3 +17,28 @@ signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
struct MachineStateInitialization : public Command {
|
||||
|
||||
MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {}
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
|
||||
struct FindMain : public Command {
|
||||
FindMain() : Command("Locate the main entry point",eProject) {}
|
||||
bool execute(CommandContext *ctx);
|
||||
};
|
||||
|
||||
struct CreateFunction : public Command {
|
||||
QString m_name;
|
||||
SegOffAddr m_addr;
|
||||
FunctionType *m_type;
|
||||
CreateFunction(QString name,SegOffAddr address,FunctionType *f) : Command("Create function",eProject),
|
||||
m_name(name),
|
||||
m_addr(address),
|
||||
m_type(f)
|
||||
{}
|
||||
QString instanceDescription() const override;
|
||||
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
|
||||
@ -7,7 +7,8 @@
|
||||
#include "CallConvention.h"
|
||||
|
||||
#include <llvm/ADT/ilist.h>
|
||||
//#include <llvm/ADT/ilist_node.h>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <QtCore/QString>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
@ -22,7 +23,7 @@ struct Disassembler;
|
||||
struct Function;
|
||||
struct CALL_GRAPH;
|
||||
struct PROG;
|
||||
|
||||
struct IStructuredTextTarget;
|
||||
struct Function;
|
||||
|
||||
namespace llvm
|
||||
@ -55,15 +56,11 @@ enum PROC_FLAGS
|
||||
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
|
||||
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
|
||||
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
|
||||
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
|
||||
// CALL_C =0x00004000, /* Proc uses C calling convention */
|
||||
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
|
||||
PROC_NEAR =0x00010000, /* Proc exits with near return */
|
||||
PROC_FAR =0x00020000, /* Proc exits with far return */
|
||||
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
|
||||
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
|
||||
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
|
||||
//PROC_IS_FUNC=0x00800000, /* Proc is a function - determined by return type */
|
||||
REG_ARGS =0x01000000, /* Proc has registers as arguments */
|
||||
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
|
||||
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
|
||||
@ -146,7 +143,15 @@ public:
|
||||
}
|
||||
void push_back(BB *v) { m_listBB.push_back(v);}
|
||||
};
|
||||
struct Function : public llvm::ilist_node<Function>
|
||||
typedef std::shared_ptr<struct Function> PtrFunction;
|
||||
enum DecompilationStep : uint32_t {
|
||||
eNotDecoded, // no processing done yet
|
||||
eDisassemblyInProgress,
|
||||
eDissassembled, // low level disassembly done
|
||||
//eStackTracing, // tracing stack depth across function calls
|
||||
|
||||
};
|
||||
struct Function : public std::enable_shared_from_this<Function>
|
||||
{
|
||||
typedef llvm::iplist<BB> BasicBlockListType;
|
||||
// BasicBlock iterators...
|
||||
@ -154,7 +159,7 @@ struct Function : public llvm::ilist_node<Function>
|
||||
typedef BasicBlockListType::const_iterator const_iterator;
|
||||
protected:
|
||||
BasicBlockListType BasicBlocks; ///< The basic blocks
|
||||
Function(FunctionType *ty) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
Function(FunctionType *ty) : nStep(eNotDecoded),procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
hasCase(false),liveAnal(0)
|
||||
{
|
||||
type = ty;
|
||||
@ -164,7 +169,7 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
int nStep; // decompilation step number for this function
|
||||
DecompilationStep nStep; // decompilation step number for this function
|
||||
FunctionType * type;
|
||||
uint32_t procEntry; /* label number */
|
||||
QString name; /* Meaningful name for this proc */
|
||||
@ -193,9 +198,9 @@ public:
|
||||
delete type;
|
||||
}
|
||||
public:
|
||||
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
|
||||
static PtrFunction Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
|
||||
{
|
||||
Function *r=new Function(ty);
|
||||
PtrFunction r(new Function(ty));
|
||||
r->name = nm;
|
||||
return r;
|
||||
}
|
||||
@ -237,6 +242,7 @@ public:
|
||||
void controlFlowAnalysis();
|
||||
void newRegArg(iICODE picode, iICODE ticode);
|
||||
void writeProcComments(QTextStream & ostr);
|
||||
void toStructuredText(IStructuredTextTarget *out,int level);
|
||||
|
||||
void displayCFG();
|
||||
void displayStats();
|
||||
@ -283,25 +289,7 @@ private:
|
||||
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
};
|
||||
namespace llvm {
|
||||
template<> struct ilist_traits<typename ::Function>
|
||||
: public ilist_default_traits<typename ::Function> {
|
||||
|
||||
// createSentinel is used to get hold of the node that marks the end of the
|
||||
// list... (same trick used here as in ilist_traits<Instruction>)
|
||||
typename ::Function *createSentinel() const {
|
||||
return static_cast<typename ::Function*>(&Sentinel);
|
||||
}
|
||||
static void destroySentinel(typename ::Function*) {}
|
||||
|
||||
typename ::Function *provideInitialHead() const { return createSentinel(); }
|
||||
typename ::Function *ensureHead(::Function*) const { return createSentinel(); }
|
||||
static void noteHead(typename ::Function*, typename ::Function*) {}
|
||||
|
||||
private:
|
||||
mutable ilist_node<typename ::Function> Sentinel;
|
||||
};
|
||||
}
|
||||
typedef llvm::iplist<Function> FunctionListType;
|
||||
typedef std::list<PtrFunction> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef lFunction::iterator ilFunction;
|
||||
|
||||
@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon<STKSYM>
|
||||
//std::vector<STKSYM> sym;
|
||||
//STKSYM * sym; /* Symbols */
|
||||
int16_t m_minOff; /* Initial offset in stack frame*/
|
||||
int16_t maxOff; /* Maximum offset in stack frame*/
|
||||
int16_t m_maxOff; /* Maximum offset in stack frame*/
|
||||
int cb; /* Number of bytes in arguments */
|
||||
int numArgs; /* No. of arguments in the table*/
|
||||
void adjustForArgType(size_t numArg_, hlType actType_);
|
||||
STKFRAME() : m_minOff(0),maxOff(0),cb(0),numArgs(0)
|
||||
STKFRAME() : m_minOff(0),m_maxOff(0),cb(0),numArgs(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ void parse (CALL_GRAPH * *); /* parser.c */
|
||||
|
||||
extern int strSize (const uint8_t *, char); /* parser.c */
|
||||
//void disassem(int pass, Function * pProc); /* disassem.c */
|
||||
void interactDis(Function *, int initIC); /* disassem.c */
|
||||
void interactDis(const PtrFunction &, int initIC); /* disassem.c */
|
||||
bool JmpInst(llIcode opcode); /* idioms.c */
|
||||
queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */
|
||||
|
||||
|
||||
@ -11,10 +11,7 @@ struct IDcc {
|
||||
static IDcc *get();
|
||||
virtual void BaseInit()=0;
|
||||
virtual void Init(QObject *tgt)=0;
|
||||
virtual ilFunction GetFirstFuncHandle()=0;
|
||||
virtual ilFunction GetNextFuncHandle(ilFunction iter)=0;
|
||||
virtual ilFunction GetCurFuncHandle()=0;
|
||||
virtual bool isValidFuncHandle(ilFunction) = 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;
|
||||
|
||||
@ -7,12 +7,16 @@
|
||||
#pragma once
|
||||
#include "bundle.h"
|
||||
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
struct LLInst;
|
||||
struct Function;
|
||||
typedef std::shared_ptr<Function> PtrFunction;
|
||||
|
||||
struct Disassembler
|
||||
{
|
||||
protected:
|
||||
@ -30,8 +34,8 @@ public:
|
||||
g_lab=0;
|
||||
}
|
||||
public:
|
||||
void disassem(Function *ppProc);
|
||||
void disassem(Function *ppProc, int i);
|
||||
void disassem(PtrFunction ppProc);
|
||||
void disassem(PtrFunction ppProc, int i);
|
||||
void dis1Line(LLInst &inst, int loc_ip, int pass);
|
||||
};
|
||||
/* Definitions for extended keys (first key is zero) */
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
#include <QtCore/QString>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
@ -60,6 +61,8 @@ struct LoaderMetadata {
|
||||
return QString("b%1%2").arg(compiler_version).arg(codeModelChar());
|
||||
case ePascal:
|
||||
return QString("tp%1").arg(compiler_version);
|
||||
default:
|
||||
return "xxx";
|
||||
}
|
||||
case eMicrosoft:
|
||||
assert(compiler_language==eAnsiCorCPP);
|
||||
@ -67,6 +70,8 @@ struct LoaderMetadata {
|
||||
case eLogitech:
|
||||
assert(compiler_language==eModula2);
|
||||
return QString("l%1%2").arg(compiler_version).arg(codeModelChar());
|
||||
case eUnknownVendor:
|
||||
return "xxx";
|
||||
}
|
||||
return "xxx";
|
||||
}
|
||||
@ -84,11 +89,6 @@ struct LoaderMetadata {
|
||||
class Project : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
typedef llvm::iplist<Function> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef FunctionListType::iterator ilFunction;
|
||||
|
||||
public:
|
||||
DosLoader * m_selected_loader;
|
||||
bool m_metadata_available=false;
|
||||
@ -101,6 +101,8 @@ public:
|
||||
|
||||
PROG prog; /* Loaded program image parameters */
|
||||
CommandStream m_project_command_stream;
|
||||
std::unordered_map<PtrFunction,CommandStream> m_function_streams;
|
||||
|
||||
bool m_error_state;
|
||||
struct PatternLocator *m_pattern_locator;
|
||||
public:
|
||||
@ -122,8 +124,9 @@ public:
|
||||
const QString & binary_path() const {return m_fname;}
|
||||
QString output_name(const char *ext);
|
||||
ilFunction funcIter(Function *to_find);
|
||||
ilFunction findByEntry(uint32_t entry);
|
||||
ilFunction createFunction(FunctionType *f, const QString & name, SegOffAddr addr);
|
||||
PtrFunction findByEntry(uint32_t entry);
|
||||
PtrFunction findByName(const QString &name);
|
||||
PtrFunction createFunction(FunctionType *f, const QString & name, SegOffAddr addr);
|
||||
bool valid(ilFunction iter);
|
||||
|
||||
int getSymIdxByAdd(uint32_t adr);
|
||||
@ -142,14 +145,15 @@ public:
|
||||
const FunctionListType &functions() const { return pProcList; }
|
||||
FunctionListType &functions() { return pProcList; }
|
||||
|
||||
bool addCommand(Command *cmd) { return m_project_command_stream.add(cmd); emit commandListChanged(); }
|
||||
bool addCommand(Command *cmd);
|
||||
bool addCommand(PtrFunction f, Command *cmd); // Add function level command
|
||||
void dumpAllErrors();
|
||||
void setLoader(DosLoader *ins);
|
||||
void processCommands(int count=1);
|
||||
public slots:
|
||||
void onCommandStreamFinished(bool state);
|
||||
signals:
|
||||
void newFunctionCreated(Function &);
|
||||
void newFunctionCreated(PtrFunction);
|
||||
void loaderSelected();
|
||||
void commandListChanged();
|
||||
protected:
|
||||
|
||||
@ -49,6 +49,7 @@ struct STKSYM : public SymbolCommon
|
||||
bool hasMacro=false; /* This type needs a macro */
|
||||
QString macro; /* Macro name */
|
||||
bool invalid=false; /* Boolean: invalid entry in formal arg list*/
|
||||
int arrayMembers=1; // for local variables if >1 marks this stack symbol as an array
|
||||
void setArgName(int i)
|
||||
{
|
||||
char buf[32];
|
||||
|
||||
@ -35,7 +35,7 @@ static void calculateArgLocations_allOnStack(Function *func) {
|
||||
arg.type = argtype.dcc_type;
|
||||
arg.setArgName(func->args.numArgs);
|
||||
stack_offset+=arg.size;
|
||||
func->args.maxOff=stack_offset;
|
||||
func->args.m_maxOff=stack_offset;
|
||||
func->args.numArgs++;
|
||||
}
|
||||
func->cbParam = stack_offset;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#include "Command.h"
|
||||
|
||||
#include "DccFrontend.h"
|
||||
#include "dcc.h"
|
||||
#include "project.h"
|
||||
#include "Loaders.h"
|
||||
@ -69,6 +70,15 @@ bool LoaderApplication::execute(CommandContext * ctx)
|
||||
}
|
||||
if (option.verbose)
|
||||
proj->prog.displayLoadInfo();
|
||||
FunctionType *main_type = FunctionType::get(Type{TYPE_UNKNOWN},{ },false);
|
||||
main_type->setCallingConvention(CConv::UNKNOWN);
|
||||
/* Create initial procedure at program start address */
|
||||
PROG &prog(proj->prog);
|
||||
CreateFunction *cmd = new CreateFunction("start",
|
||||
SegOffAddr {prog.segMain,((uint32_t)prog.initCS << 4) + prog.initIP},
|
||||
main_type);
|
||||
proj->addCommand(cmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
#ifndef COMMAND_H
|
||||
#define COMMAND_H
|
||||
|
||||
#include <memory>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QPair>
|
||||
|
||||
class Project;
|
||||
struct Function;
|
||||
typedef std::shared_ptr<Function> PtrFunction;
|
||||
enum CommandLevel {
|
||||
eProject,
|
||||
eBinary,
|
||||
@ -22,6 +25,7 @@ public:
|
||||
}
|
||||
|
||||
Project *m_project;
|
||||
PtrFunction *m_func;
|
||||
QVector<QPair<Command *,QString>> m_failures;
|
||||
void reset();
|
||||
};
|
||||
@ -32,6 +36,8 @@ class Command
|
||||
CommandLevel m_level;
|
||||
public:
|
||||
Command(QString n,CommandLevel level) : m_command_name(n),m_level(level) {}
|
||||
virtual ~Command() {}
|
||||
|
||||
QString name() const { return m_command_name;}
|
||||
virtual QString instanceDescription() const { return m_command_name; }
|
||||
virtual bool execute(CommandContext *) { return false; }
|
||||
|
||||
@ -125,23 +125,23 @@ bool DccFrontend::FrontEnd ()
|
||||
|
||||
/* Search through code looking for impure references and flag them */
|
||||
Disassembler ds(1);
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
for(PtrFunction &f : Project::get()->pProcList)
|
||||
{
|
||||
f.markImpure();
|
||||
f->markImpure();
|
||||
if (option.asm1)
|
||||
{
|
||||
ds.disassem(&f);
|
||||
ds.disassem(f);
|
||||
}
|
||||
}
|
||||
if (option.Interact)
|
||||
{
|
||||
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
interactDis(Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
}
|
||||
|
||||
/* Converts jump target addresses to icode offsets */
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
for(PtrFunction &f : Project::get()->pProcList)
|
||||
{
|
||||
f.bindIcodeOff();
|
||||
f->bindIcodeOff();
|
||||
}
|
||||
/* Print memory bitmap */
|
||||
if (option.Map)
|
||||
@ -151,12 +151,17 @@ bool DccFrontend::FrontEnd ()
|
||||
/*****************************************************************************
|
||||
* LoadImage
|
||||
****************************************************************************/
|
||||
struct MachineStateInitialization : public Command {
|
||||
|
||||
public:
|
||||
MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {}
|
||||
/* Parses the program, builds the call graph, and returns the list of
|
||||
* procedures found */
|
||||
void DccFrontend::parse(Project &proj)
|
||||
{
|
||||
/* Set initial state */
|
||||
proj.addCommand(new MachineStateInitialization);
|
||||
proj.addCommand(new FindMain);
|
||||
}
|
||||
|
||||
bool execute(CommandContext *ctx) override
|
||||
bool MachineStateInitialization::execute(CommandContext *ctx)
|
||||
{
|
||||
assert(ctx && ctx->m_project);
|
||||
Project &proj(*ctx->m_project);
|
||||
@ -170,74 +175,52 @@ public:
|
||||
proj.SynthLab = SYNTHESIZED_MIN;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct CreateFunction : public Command {
|
||||
QString m_name;
|
||||
SegOffAddr m_addr;
|
||||
FunctionType *m_type;
|
||||
CreateFunction(QString name,SegOffAddr address,FunctionType *f) : Command("Create function",eProject),
|
||||
m_name(name),
|
||||
m_addr(address),
|
||||
m_type(f)
|
||||
{}
|
||||
bool execute(CommandContext *ctx) override {
|
||||
|
||||
bool FindMain::execute(CommandContext *ctx) {
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
|
||||
proj.createFunction(m_type,m_name,m_addr);
|
||||
PtrFunction start_func = proj.findByName("start");
|
||||
if(ctx->m_project->m_entry_state.IP==0) {
|
||||
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
|
||||
return false;
|
||||
}
|
||||
/* Check for special settings of initial state, based on idioms of the startup code */
|
||||
if(checkStartup(ctx->m_project->m_entry_state)) {
|
||||
proj.findByName("start")->markDoNotDecompile(); // we have main, do not decompile the start proc
|
||||
//TODO: main arguments and return values should depend on detected compiler/library
|
||||
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
|
||||
main_type->setCallingConvention(CConv::C);
|
||||
proj.addCommand(new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type));
|
||||
|
||||
proj.addCommand(new LoadPatternLibrary());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CreateFunction::instanceDescription() const {
|
||||
return QString("%1 \"%2\" @ 0x%3").arg(name()).arg(m_name).arg(m_addr.addr,0,16,QChar('0'));
|
||||
}
|
||||
|
||||
bool CreateFunction::execute(CommandContext *ctx) {
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
|
||||
PtrFunction func = proj.createFunction(m_type,m_name,m_addr);
|
||||
if(m_name=="main") {
|
||||
/* In medium and large models, the segment of main may (will?) not be
|
||||
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;
|
||||
}
|
||||
assert(false);
|
||||
if(m_name=="start") {
|
||||
proj.addCommand(new MachineStateInitialization);
|
||||
proj.addCommand(new FindMain);
|
||||
}
|
||||
|
||||
// proj.addCommand(new ProcessFunction);
|
||||
//proj.addCommand(new FollowControl());
|
||||
/* Recursively build entire procedure list */
|
||||
//proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
|
||||
|
||||
}
|
||||
};
|
||||
struct FindMain : public Command {
|
||||
FindMain() : Command("Locate the main entry point",eProject) {
|
||||
}
|
||||
bool execute(CommandContext *ctx) {
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
|
||||
if(ctx->m_project->m_entry_state.IP==0) {
|
||||
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
|
||||
return false;
|
||||
}
|
||||
/* Check for special settings of initial state, based on idioms of the startup code */
|
||||
checkStartup(ctx->m_project->m_entry_state);
|
||||
Command *cmd;
|
||||
if (prog.offMain != -1)
|
||||
{
|
||||
//TODO: main arguments and return values should depend on detected compiler/library
|
||||
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
|
||||
main_type->setCallingConvention(CConv::C);
|
||||
cmd = new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
FunctionType *main_type = FunctionType::get(Type{TYPE_UNKNOWN},{ Type{TYPE_UNKNOWN} },false);
|
||||
main_type->setCallingConvention(CConv::UNKNOWN);
|
||||
/* Create initial procedure at program start address */
|
||||
cmd = new CreateFunction("start",SegOffAddr {prog.segMain,proj.m_entry_state.IP},main_type);
|
||||
}
|
||||
proj.addCommand(cmd);
|
||||
proj.addCommand(new LoadPatternLibrary());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* Parses the program, builds the call graph, and returns the list of
|
||||
* procedures found */
|
||||
void DccFrontend::parse(Project &proj)
|
||||
{
|
||||
/* Set initial state */
|
||||
proj.addCommand(new MachineStateInitialization);
|
||||
proj.addCommand(new FindMain);
|
||||
}
|
||||
|
||||
11
src/FollowControlFlow.cpp
Normal file
11
src/FollowControlFlow.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "FollowControlFlow.h"
|
||||
|
||||
QString FollowControlFlow::instanceDescription() const
|
||||
{
|
||||
return name() + " @ 0x"+QString::number(m_address,16);
|
||||
}
|
||||
|
||||
bool FollowControlFlow::execute(CommandContext *ctx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
18
src/FollowControlFlow.h
Normal file
18
src/FollowControlFlow.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef FOLLOWCONTROLFLOW_H
|
||||
#define FOLLOWCONTROLFLOW_H
|
||||
|
||||
#include "Command.h"
|
||||
|
||||
class FollowControlFlow : public Command
|
||||
{
|
||||
uint32_t m_address;
|
||||
public:
|
||||
FollowControlFlow(uint32_t addr) : Command("Follow control flow",eFunction),m_address(addr) {}
|
||||
|
||||
// Command interface
|
||||
public:
|
||||
QString instanceDescription() const override;
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
|
||||
#endif // FOLLOWCONTROLFLOW_H
|
||||
@ -3,6 +3,9 @@
|
||||
#include "msvc_fixes.h"
|
||||
#include "project.h"
|
||||
#include "scanner.h"
|
||||
#include "ui/StructuredTextTarget.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
//FunctionType *Function::getFunctionType() const
|
||||
//{
|
||||
@ -39,6 +42,80 @@ void Function::callingConv(CConv::CC_Type v) {
|
||||
type->setCallingConvention(v);
|
||||
getFunctionType()->m_call_conv->calculateStackLayout(this);
|
||||
}
|
||||
static QString sizeToPtrName(int size)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1:
|
||||
return "BYTE ptr" ;
|
||||
case 2:
|
||||
return "WORD ptr";
|
||||
case 4:
|
||||
return "DWORD ptr";
|
||||
}
|
||||
return "UNKOWN ptr";
|
||||
}
|
||||
void toStructuredText(STKFRAME &stk,IStructuredTextTarget *out, int level) {
|
||||
int curlevel = 0;
|
||||
int maxlevel = stk.m_maxOff - stk.m_minOff;
|
||||
|
||||
for(STKSYM & p : stk)
|
||||
{
|
||||
if (curlevel > p.label)
|
||||
{
|
||||
qWarning() << "error, var collapse!!!";
|
||||
curlevel = p.label;
|
||||
}
|
||||
else if (curlevel < p.label)
|
||||
{
|
||||
out->addSpace(4);
|
||||
out->prtt(QString("gap len = %1").arg(p.label - curlevel,0,16));
|
||||
curlevel = p.label;
|
||||
out->addEOL();
|
||||
}
|
||||
out->addSpace(4);
|
||||
out->addTaggedString(XT_Symbol,p.name,&p);
|
||||
out->prtt("equ");
|
||||
out->addSpace();
|
||||
out->prtt(sizeToPtrName(p.size));
|
||||
out->addSpace();
|
||||
if (p.arrayMembers>1)
|
||||
{
|
||||
out->addTaggedString(XT_Number,QString::number(p.arrayMembers,16));
|
||||
out->prtt("dup (?)");
|
||||
out->addSpace();
|
||||
}
|
||||
out->TAGbegin(XT_Number, NULL);
|
||||
out->prtt(QString("%1h").arg(p.label,0,16));
|
||||
out->TAGend(XT_Number);
|
||||
out->addEOL();
|
||||
|
||||
curlevel += p.size * p.arrayMembers;
|
||||
}
|
||||
|
||||
if (curlevel < maxlevel)
|
||||
{
|
||||
out->prtt(QString(" gap len = %1h").arg(maxlevel - curlevel,0,16));
|
||||
}
|
||||
}
|
||||
void Function::toStructuredText(IStructuredTextTarget *out, int level)
|
||||
{
|
||||
|
||||
out->TAGbegin(XT_Function, this);
|
||||
out->addTaggedString(XT_FuncName,name);
|
||||
out->prtt(" proc");
|
||||
out->addEOL();
|
||||
::toStructuredText(args,out,level);
|
||||
out->addEOL();
|
||||
|
||||
// this->prtout_asm_1(pvarll, out);
|
||||
|
||||
out->addTaggedString(XT_FuncName,name);
|
||||
out->addSpace();
|
||||
out->prtt("endp");
|
||||
out->addEOL();
|
||||
out->TAGend(XT_Function);
|
||||
}
|
||||
|
||||
void FunctionType::setCallingConvention(CConv::CC_Type cc)
|
||||
{
|
||||
|
||||
@ -282,7 +282,7 @@ void Function::codeGen (QIODevice &fs)
|
||||
if (flg & PROC_ASM) /* generate assembler */
|
||||
{
|
||||
Disassembler ds(3);
|
||||
ds.disassem(this);
|
||||
ds.disassem(this->shared_from_this());
|
||||
}
|
||||
else /* generate C */
|
||||
{
|
||||
|
||||
@ -463,7 +463,7 @@ static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pa
|
||||
* pushing and popping of registers is implemented.
|
||||
* Also sets prog.offMain and prog.segMain if possible
|
||||
*/
|
||||
void checkStartup(STATE &state)
|
||||
bool checkStartup(STATE &state)
|
||||
{
|
||||
Project & proj(*Project::get());
|
||||
PROG & prog(Project::get()->prog);
|
||||
@ -491,7 +491,7 @@ void checkStartup(STATE &state)
|
||||
proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,4});
|
||||
prog.offMain = startOff; /* Code starts immediately */
|
||||
prog.segMain = prog.initCS; /* At the 5 uint8_t jump */
|
||||
return; /* Already have vendor */
|
||||
return true; /* Already have vendor */
|
||||
}
|
||||
else if (locatePattern(prog.image(), init, init+26, pattBorl5Init, sizeof(pattBorl5Init), &i))
|
||||
{
|
||||
@ -501,10 +501,9 @@ void checkStartup(STATE &state)
|
||||
proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,5});
|
||||
prog.offMain = startOff; /* Code starts immediately */
|
||||
prog.segMain = prog.initCS;
|
||||
return; /* Already have vendor */
|
||||
return true; /* Already have vendor */
|
||||
}
|
||||
else if (locatePattern(prog.image(), init, init+26, pattBorl7Init,
|
||||
sizeof(pattBorl7Init), &i))
|
||||
else if (locatePattern(prog.image(), init, init+26, pattBorl7Init, sizeof(pattBorl7Init), &i))
|
||||
{
|
||||
|
||||
state.setState( rDS, LH(&prog.image()[i+1]));
|
||||
@ -512,7 +511,7 @@ void checkStartup(STATE &state)
|
||||
proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,7});
|
||||
prog.offMain = startOff; /* Code starts immediately */
|
||||
prog.segMain = prog.initCS;
|
||||
return; /* Already have vendor */
|
||||
return true; /* Already have vendor */
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,16 +532,14 @@ void checkStartup(STATE &state)
|
||||
prog.segMain = (uint16_t)para;
|
||||
metadata.compiler_memory_model = eLarge;
|
||||
}
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainCompact,
|
||||
sizeof(pattMainCompact), &i))
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainCompact, sizeof(pattMainCompact), &i))
|
||||
{
|
||||
rel = LH_SIGNED(&prog.image()[i+OFFMAINCOMPACT]);/* This is the rel addr of main */
|
||||
prog.offMain = i+OFFMAINCOMPACT+2+rel; /* Save absolute image offset */
|
||||
prog.segMain = prog.initCS;
|
||||
metadata.compiler_memory_model = eCompact;
|
||||
}
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainMedium,
|
||||
sizeof(pattMainMedium), &i))
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainMedium, sizeof(pattMainMedium), &i))
|
||||
{
|
||||
rel = LH(&prog.image()[i+OFFMAINMEDIUM]); /* This is abs off of main */
|
||||
para= LH(&prog.image()[i+OFFMAINMEDIUM+2]);/* This is abs seg of main */
|
||||
@ -550,8 +547,7 @@ void checkStartup(STATE &state)
|
||||
prog.segMain = (uint16_t)para;
|
||||
metadata.compiler_memory_model = eMedium;
|
||||
}
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainSmall,
|
||||
sizeof(pattMainSmall), &i))
|
||||
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainSmall, sizeof(pattMainSmall), &i))
|
||||
{
|
||||
rel = LH_SIGNED(&prog.image()[i+OFFMAINSMALL]); /* This is rel addr of main */
|
||||
prog.offMain = i+OFFMAINSMALL+2+rel; /* Save absolute image offset */
|
||||
@ -567,7 +563,7 @@ void checkStartup(STATE &state)
|
||||
proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,3});
|
||||
printf("Turbo Pascal 3.0 detected\n");
|
||||
printf("Main at %04X\n", prog.offMain);
|
||||
return; /* Already have vendor */
|
||||
return true; /* Already have vendor */
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -646,6 +642,7 @@ void checkStartup(STATE &state)
|
||||
printf("Warning - compiler not recognised\n");
|
||||
}
|
||||
proj.setLoaderMetadata(metadata);
|
||||
return prog.offMain != -1;
|
||||
}
|
||||
|
||||
/* DCCLIBS.DAT is a data file sorted on function name containing names and
|
||||
|
||||
16
src/chklib.h
16
src/chklib.h
@ -20,11 +20,11 @@ struct LoadPatternLibrary : public Command {
|
||||
class PatternLocator {
|
||||
std::vector<hlType> pArg; /* Points to the array of param types */
|
||||
QString pattern_id;
|
||||
int numFunc; /* Number of func names actually stored */
|
||||
int numArg; /* Number of param names actually stored */
|
||||
int numFunc=0; /* Number of func names actually stored */
|
||||
int numArg=0; /* Number of param names actually stored */
|
||||
public:
|
||||
struct HT *ht; //!< The hash table
|
||||
struct PH_FUNC_STRUCT *pFunc; //!< Points to the array of func names
|
||||
struct HT *ht=nullptr; //!< The hash table
|
||||
struct PH_FUNC_STRUCT *pFunc=nullptr; //!< Points to the array of func names
|
||||
|
||||
|
||||
PatternLocator(QString name) : pattern_id(name) {}
|
||||
@ -41,9 +41,11 @@ private:
|
||||
int numVert; /* Number of vertices in the graph (also size of g[]) */
|
||||
unsigned PatLen; /* Size of the keys (pattern length) */
|
||||
unsigned SymLen; /* Max size of the symbols, including null */
|
||||
uint16_t * T1base, *T2base; /* Pointers to start of T1, T2 */
|
||||
uint16_t * g; /* g[] */
|
||||
/* Pointers to start of T1, T2 */
|
||||
uint16_t * T1base = nullptr;
|
||||
uint16_t * T2base = nullptr;
|
||||
uint16_t * g = nullptr; /* g[] */
|
||||
|
||||
};
|
||||
extern void checkStartup(struct STATE &state);
|
||||
extern bool checkStartup(struct STATE &state);
|
||||
#endif // CHKLIB_H
|
||||
|
||||
@ -2,33 +2,22 @@
|
||||
#include "dcc.h"
|
||||
#include "project.h"
|
||||
struct DccImpl : public IDcc {
|
||||
ilFunction m_current_func;
|
||||
PtrFunction m_current_func;
|
||||
// IDcc interface
|
||||
public:
|
||||
void BaseInit()
|
||||
{
|
||||
m_current_func = Project::get()->functions().end();
|
||||
m_current_func = nullptr;
|
||||
}
|
||||
void Init(QObject *tgt)
|
||||
{
|
||||
}
|
||||
ilFunction GetFirstFuncHandle()
|
||||
{
|
||||
return Project::get()->functions().begin();
|
||||
}
|
||||
ilFunction GetNextFuncHandle(ilFunction iter)
|
||||
{
|
||||
if(iter!=Project::get()->functions().end())
|
||||
++iter;
|
||||
return iter;
|
||||
}
|
||||
ilFunction GetCurFuncHandle()
|
||||
{
|
||||
PtrFunction GetCurFuncHandle() {
|
||||
return m_current_func;
|
||||
}
|
||||
void analysis_Once()
|
||||
{
|
||||
if(m_current_func==Project::get()->functions().end())
|
||||
if(m_current_func==nullptr)
|
||||
return;
|
||||
if(m_current_func->nStep==0) { // unscanned function
|
||||
}
|
||||
@ -39,14 +28,15 @@ public:
|
||||
Project::get()->create(name);
|
||||
return Project::get()->addLoadCommands(name);
|
||||
}
|
||||
void prtout_asm(IStructuredTextTarget *, int level)
|
||||
void prtout_asm(IStructuredTextTarget *tgt, int level)
|
||||
{
|
||||
// if (m_Cur_Func->m_nStep == 0)
|
||||
// if (m_current_func->nStep == 0)
|
||||
// return;
|
||||
|
||||
// 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);
|
||||
}
|
||||
void prtout_cpp(IStructuredTextTarget *, int level)
|
||||
{
|
||||
@ -64,13 +54,9 @@ public:
|
||||
}
|
||||
void SetCurFunc_by_Name(QString v)
|
||||
{
|
||||
lFunction & funcs(Project::get()->functions());
|
||||
for(auto iter=funcs.begin(),fin=funcs.end(); iter!=fin; ++iter) {
|
||||
if(iter->name==v) {
|
||||
m_current_func = iter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
PtrFunction p(Project::get()->findByName(v));
|
||||
if(p!=nullptr)
|
||||
m_current_func = p;
|
||||
}
|
||||
QDir installDir() {
|
||||
return QDir(".");
|
||||
|
||||
@ -91,7 +91,7 @@ static map<int,int> pl;
|
||||
static uint32_t nextInst;
|
||||
static bool fImpure;
|
||||
//static int g_lab;
|
||||
static Function * pProc; /* Points to current proc struct */
|
||||
static PtrFunction pProc; /* Points to current proc struct */
|
||||
|
||||
struct POSSTACK_ENTRY
|
||||
{
|
||||
@ -138,7 +138,7 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
|
||||
* pass == 3 generates output on file .b
|
||||
****************************************************************************/
|
||||
|
||||
void Disassembler::disassem(Function * ppProc)
|
||||
void Disassembler::disassem(PtrFunction ppProc)
|
||||
{
|
||||
|
||||
|
||||
@ -660,7 +660,7 @@ static char *strHex(uint32_t d)
|
||||
/****************************************************************************
|
||||
* interactDis - interactive disassembler *
|
||||
****************************************************************************/
|
||||
void interactDis(Function * initProc, int initIC)
|
||||
void interactDis(const PtrFunction & initProc, int initIC)
|
||||
{
|
||||
QString procname = "UNKNOWN";
|
||||
if(initProc)
|
||||
|
||||
@ -213,7 +213,7 @@ void Function::findIdioms()
|
||||
if ((flg & PROC_HLL) and (not args.empty()))
|
||||
{
|
||||
args.m_minOff += (flg & PROC_FAR ? 4 : 2);
|
||||
delta = args.maxOff - args.m_minOff;
|
||||
delta = args.m_maxOff - args.m_minOff;
|
||||
if (cbParam != delta)
|
||||
{
|
||||
cbParam = delta;
|
||||
|
||||
@ -24,7 +24,7 @@ using namespace std;
|
||||
static void setBits(int16_t type, uint32_t start, uint32_t len);
|
||||
static void process_MOV(LLInst &ll, STATE * pstate);
|
||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||
void interactDis(Function * initProc, int ic);
|
||||
//void interactDis(Function * initProc, int ic);
|
||||
|
||||
/* Returns the size of the string pointed by sym and delimited by delim.
|
||||
* Size includes delimiter. */
|
||||
@ -658,7 +658,7 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
|
||||
|
||||
flg |= PROC_IJMP;
|
||||
flg &= ~TERMINATES;
|
||||
interactDis(this, this->Icode.size()-1);
|
||||
interactDis(shared_from_this(), Icode.size()-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -737,10 +737,10 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
|
||||
if (pIcode.ll()->testFlags(I))
|
||||
{
|
||||
/* Search procedure list for one with appropriate entry point */
|
||||
ilFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
|
||||
PtrFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
|
||||
|
||||
/* Create a new procedure node and save copy of the state */
|
||||
if ( not Project::get()->valid(iter) )
|
||||
if ( iter == nullptr )
|
||||
{
|
||||
iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()});
|
||||
Function &x(*iter);
|
||||
@ -750,7 +750,7 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
|
||||
if (x.flg & PROC_ISLIB)
|
||||
{
|
||||
/* A library function. No need to do any more to it */
|
||||
pcallGraph->insertCallGraph (this, iter);
|
||||
pcallGraph->insertCallGraph (this->shared_from_this(), iter);
|
||||
//iter = (++pProcList.rbegin()).base();
|
||||
last_insn.ll()->src().proc.proc = &x;
|
||||
return false;
|
||||
@ -774,7 +774,7 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
|
||||
x.state = *pstate;
|
||||
|
||||
/* Insert new procedure in call graph */
|
||||
pcallGraph->insertCallGraph (this, iter);
|
||||
pcallGraph->insertCallGraph (this->shared_from_this(), iter);
|
||||
|
||||
/* Process new procedure */
|
||||
x.FollowCtrl (pcallGraph, pstate);
|
||||
@ -788,7 +788,7 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
|
||||
|
||||
}
|
||||
else
|
||||
Project::get()->callGraph->insertCallGraph (this, iter);
|
||||
Project::get()->callGraph->insertCallGraph (this->shared_from_this(), iter);
|
||||
|
||||
last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc
|
||||
|
||||
@ -912,8 +912,8 @@ void STKFRAME::updateFrameOff ( int16_t off, int _size, uint16_t duFlag)
|
||||
}
|
||||
|
||||
/* Save maximum argument offset */
|
||||
if ((uint32_t)this->maxOff < (off + (uint32_t)_size))
|
||||
this->maxOff = off + (int16_t)_size;
|
||||
if ((uint32_t)this->m_maxOff < (off + (uint32_t)_size))
|
||||
this->m_maxOff = off + (int16_t)_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ const char *indentStr(int indLevel) // Indentation according to the depth of the
|
||||
|
||||
/* Inserts an outEdge at the current callGraph pointer if the newProc does
|
||||
* not exist. */
|
||||
void CALL_GRAPH::insertArc (ilFunction newProc)
|
||||
void CALL_GRAPH::insertArc (PtrFunction newProc)
|
||||
{
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ void CALL_GRAPH::insertArc (ilFunction newProc)
|
||||
|
||||
|
||||
/* Inserts a (caller, callee) arc in the call graph tree. */
|
||||
bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
|
||||
bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee)
|
||||
{
|
||||
if (proc == caller)
|
||||
{
|
||||
@ -56,10 +56,10 @@ bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee)
|
||||
{
|
||||
return insertCallGraph(Project::get()->funcIter(caller),callee);
|
||||
}
|
||||
//bool CALL_GRAPH::insertCallGraph(PtrFunction &caller, PtrFunction &callee)
|
||||
//{
|
||||
// return insertCallGraph(caller,callee);
|
||||
//}
|
||||
|
||||
|
||||
/* Displays the current node of the call graph, and invokes recursively on
|
||||
|
||||
@ -50,35 +50,49 @@ bool Project::valid(ilFunction iter)
|
||||
ilFunction Project::funcIter(Function *to_find)
|
||||
{
|
||||
auto iter=std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[to_find](const Function &f)->bool {return to_find==&f;});
|
||||
[to_find](const PtrFunction &f)->bool {return to_find->shared_from_this()==f;});
|
||||
assert(iter!=pProcList.end());
|
||||
return iter;
|
||||
}
|
||||
|
||||
ilFunction Project::findByEntry(uint32_t entry)
|
||||
PtrFunction Project::findByEntry(uint32_t entry)
|
||||
{
|
||||
/* Search procedure list for one with appropriate entry point */
|
||||
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[entry](const Function &f) { return f.procEntry==entry; });
|
||||
return iter;
|
||||
[entry](const PtrFunction &f) { return f->procEntry==entry; });
|
||||
if(iter==pProcList.end())
|
||||
return nullptr;
|
||||
return *iter;
|
||||
}
|
||||
ilFunction Project::createFunction(FunctionType *f,const QString &name,SegOffAddr addr)
|
||||
|
||||
/**
|
||||
* \brief Search procedure list for one with given name
|
||||
*/
|
||||
PtrFunction Project::findByName(const QString &name)
|
||||
{
|
||||
pProcList.push_back(Function::Create(f,0,name,0));
|
||||
ilFunction iter = (++pProcList.rbegin()).base();
|
||||
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[name](const PtrFunction &f) { return f->name==name; });
|
||||
if(iter==pProcList.end())
|
||||
return nullptr;
|
||||
return *iter;
|
||||
}
|
||||
PtrFunction Project::createFunction(FunctionType *f,const QString &name,SegOffAddr addr)
|
||||
{
|
||||
PtrFunction func(Function::Create(f,0,name,0));
|
||||
pProcList.push_back(func);
|
||||
// FIXME: use provided segment addr !
|
||||
iter->procEntry = addr.addr;
|
||||
func->procEntry = addr.addr;
|
||||
if(!callGraph) {
|
||||
/* Set up call graph initial node */
|
||||
callGraph = new CALL_GRAPH;
|
||||
callGraph->proc = iter;
|
||||
callGraph->proc = func;
|
||||
/* The entry state info is for the first procedure */
|
||||
iter->state = m_entry_state;
|
||||
func->state = m_entry_state;
|
||||
|
||||
}
|
||||
|
||||
emit newFunctionCreated(*iter);
|
||||
return iter;
|
||||
emit newFunctionCreated(func);
|
||||
return func;
|
||||
}
|
||||
|
||||
int Project::getSymIdxByAdd(uint32_t adr)
|
||||
@ -127,6 +141,19 @@ SourceMachine *Project::machine()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Project::addCommand(Command *cmd) {
|
||||
bool res = m_project_command_stream.add(cmd);
|
||||
emit commandListChanged();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Project::addCommand(PtrFunction f, Command *cmd)
|
||||
{
|
||||
bool res = m_function_streams[f].add(cmd);
|
||||
emit commandListChanged();
|
||||
return res;
|
||||
}
|
||||
|
||||
void Project::onCommandStreamFinished(bool state)
|
||||
{
|
||||
if(false==state) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/*****************************************************************************
|
||||
/**
|
||||
* dcc project scanner module
|
||||
* Implements a simple state driven scanner to convert 8086 machine code into
|
||||
* I-code
|
||||
|
||||
14
src/udm.cpp
14
src/udm.cpp
@ -31,7 +31,7 @@ void Function::buildCFG(Disassembler &ds)
|
||||
|
||||
if (option.asm2)
|
||||
{
|
||||
ds.disassem(this); // Print 2nd pass assembler listing
|
||||
ds.disassem(this->shared_from_this()); // Print 2nd pass assembler listing
|
||||
return;
|
||||
}
|
||||
|
||||
@ -79,13 +79,13 @@ void udm(void)
|
||||
Disassembler ds(2);
|
||||
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
|
||||
{
|
||||
Function &f(*iter);
|
||||
Function &f(**iter);
|
||||
if(option.CustomEntryPoint) {
|
||||
if(f.procEntry!=option.CustomEntryPoint) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
iter->buildCFG(ds);
|
||||
f.buildCFG(ds);
|
||||
}
|
||||
if (option.asm2)
|
||||
return;
|
||||
@ -96,8 +96,8 @@ void udm(void)
|
||||
* substitution algorithm */
|
||||
LivenessSet live_regs;
|
||||
if(option.CustomEntryPoint) {
|
||||
ilFunction iter = proj->findByEntry(option.CustomEntryPoint);
|
||||
if(iter==proj->pProcList.end()) {
|
||||
PtrFunction iter = proj->findByEntry(option.CustomEntryPoint);
|
||||
if(iter==nullptr) {
|
||||
qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16);
|
||||
return;
|
||||
}
|
||||
@ -108,12 +108,12 @@ void udm(void)
|
||||
proj->callGraph->proc = iter;
|
||||
return;
|
||||
}
|
||||
proj->pProcList.front().dataFlow (live_regs);
|
||||
proj->pProcList.front()->dataFlow (live_regs);
|
||||
|
||||
/* Control flow analysis - structuring algorithm */
|
||||
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
|
||||
{
|
||||
iter->controlFlowAnalysis();
|
||||
(*iter)->controlFlowAnalysis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,13 +26,15 @@ DccMainWindow::DccMainWindow(QWidget *parent) :
|
||||
g_EXE2C->BaseInit();
|
||||
g_EXE2C->Init(this);
|
||||
|
||||
m_last_display = g_EXE2C->GetFirstFuncHandle();
|
||||
m_last_display = nullptr;
|
||||
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(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);
|
||||
m_asm_view = new FunctionViewWidget(this);
|
||||
@ -62,6 +64,9 @@ void DccMainWindow::changeEvent(QEvent *e)
|
||||
break;
|
||||
}
|
||||
}
|
||||
void DccMainWindow::onNewFunction(PtrFunction f) {
|
||||
emit functionListChanged();
|
||||
}
|
||||
void DccMainWindow::onOptim()
|
||||
{
|
||||
Project::get()->processCommands();
|
||||
|
||||
@ -34,7 +34,7 @@ protected:
|
||||
void changeEvent(QEvent *e);
|
||||
private slots:
|
||||
void on_actionExit_triggered();
|
||||
|
||||
void onNewFunction(PtrFunction f);
|
||||
private:
|
||||
|
||||
FunctionViewWidget *m_asm_view;
|
||||
@ -43,7 +43,7 @@ private:
|
||||
CommandQueueView *m_command_queue;
|
||||
FunctionListDockWidget *m_functionlist_widget;
|
||||
Ui::DccMainWindow *ui;
|
||||
ilFunction m_last_display;
|
||||
PtrFunction m_last_display;
|
||||
};
|
||||
|
||||
#endif // EXE2C_MAINWINDOW_H
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
#include "FunctionListDockWidget.h"
|
||||
#include "ui_FunctionListDockWidget.h"
|
||||
|
||||
#include "dcc.h"
|
||||
#include "dcc_interface.h"
|
||||
#include "Procedure.h"
|
||||
#include "project.h"
|
||||
|
||||
#include <QtCore>
|
||||
//#include "exe2c.h"
|
||||
@ -21,9 +23,10 @@ FunctionListDockWidget::~FunctionListDockWidget()
|
||||
}
|
||||
void FunctionListDockWidget::functionSelected(const QModelIndex &idx)
|
||||
{
|
||||
QVariant v=m_list_model.data(idx,Qt::DisplayRole);
|
||||
qDebug()<<"neb changed function to "<<v;
|
||||
g_EXE2C->SetCurFunc_by_Name(v.toString().toStdString().c_str());
|
||||
|
||||
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());
|
||||
}
|
||||
// signalled by m_func_list_view accepted signal
|
||||
void FunctionListDockWidget::displayRequest(const QModelIndex &)
|
||||
@ -37,20 +40,17 @@ void FunctionListModel::updateFunctionList()
|
||||
}
|
||||
void FunctionListModel::rebuildFunctionList()
|
||||
{
|
||||
ilFunction iter = g_EXE2C->GetFirstFuncHandle();
|
||||
Project &project(*Project::get());
|
||||
const lFunction &funcs(project.functions());
|
||||
clear();
|
||||
beginInsertRows(QModelIndex(),0,g_EXE2C->getFuncCount());
|
||||
|
||||
while (g_EXE2C->isValidFuncHandle(iter))
|
||||
beginInsertRows(QModelIndex(),0,funcs.size());
|
||||
for(const PtrFunction &info : funcs)
|
||||
{
|
||||
const Function &info(*iter);
|
||||
//g_EXE2C->GetFuncInfo(iter, &info);
|
||||
iter = g_EXE2C->GetNextFuncHandle(iter);
|
||||
|
||||
if (info.name.isEmpty())
|
||||
if (info->name.isEmpty())
|
||||
continue;
|
||||
// fixme
|
||||
add_function(info.name,info.nStep,info.procEntry,info.procEntry+10,info.cbParam);
|
||||
add_function(info->name,info->nStep,info->procEntry,info->procEntry+10,info->cbParam);
|
||||
}
|
||||
endInsertRows();
|
||||
}
|
||||
@ -67,8 +67,18 @@ QVariant FunctionListModel::data(const QModelIndex &idx,int role) const
|
||||
{
|
||||
return QVariant(inf.m_name);
|
||||
}
|
||||
case 1: // step
|
||||
return QVariant(inf.m_decoding_step);
|
||||
case 1: { // step
|
||||
switch(inf.m_decoding_step) {
|
||||
case eNotDecoded:
|
||||
return "Undecoded";
|
||||
case eDisassemblyInProgress:
|
||||
return "Disassembly in progress";
|
||||
case eDissassembled:
|
||||
return "Disassembled";
|
||||
default:
|
||||
return "UNKNOWN STATE";
|
||||
}
|
||||
}
|
||||
case 2: // start offset
|
||||
{
|
||||
QString in_base_16=QString("%1").arg(inf.m_start_off,0,16);
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
#include <QAbstractTableModel>
|
||||
#include <QDockWidget>
|
||||
//#include "exe2c.h"
|
||||
|
||||
enum DecompilationStep : uint32_t;
|
||||
class FunctionListModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -12,7 +12,7 @@ class FunctionListModel : public QAbstractTableModel
|
||||
struct function_info
|
||||
{
|
||||
QString m_name;
|
||||
int m_decoding_step;
|
||||
DecompilationStep m_decoding_step;
|
||||
int m_start_off, m_end_off, m_stack_purge;
|
||||
};
|
||||
std::vector<function_info> m_list;
|
||||
@ -31,7 +31,7 @@ public slots:
|
||||
void updateFunctionList();
|
||||
|
||||
protected:
|
||||
void add_function(const QString &name,int step,int start_off,int end_off,int stack_purge)
|
||||
void add_function(const QString &name,DecompilationStep step,int start_off,int end_off,int stack_purge)
|
||||
{
|
||||
|
||||
function_info info;
|
||||
|
||||
@ -22,9 +22,9 @@ void FunctionViewWidget::prtt(const char *s)
|
||||
collected_text+=s;
|
||||
//collected_text+="<br>";
|
||||
}
|
||||
void FunctionViewWidget::prtt(const std::string &s)
|
||||
void FunctionViewWidget::prtt(const QString &s)
|
||||
{
|
||||
collected_text+=s.c_str();
|
||||
collected_text+=s;
|
||||
//collected_text+="<br>";
|
||||
}
|
||||
void FunctionViewWidget::TAGbegin(TAG_TYPE tag_type, void *p)
|
||||
|
||||
@ -16,7 +16,7 @@ public:
|
||||
explicit FunctionViewWidget(QWidget *parent = 0);
|
||||
~FunctionViewWidget();
|
||||
void prtt(const char * s);
|
||||
void prtt(const std::string &s);
|
||||
void prtt(const QString &s);
|
||||
void TAGbegin(enum TAG_TYPE tag_type, void * p);
|
||||
void TAGend(enum TAG_TYPE tag_type);
|
||||
private:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <qcolor.h>
|
||||
#include <QtGui/QColor>
|
||||
enum TAG_TYPE
|
||||
{
|
||||
XT_invalid = 0,
|
||||
|
||||
@ -1,4 +1,28 @@
|
||||
#pragma once
|
||||
class IStructuredTextTarget {
|
||||
#include "src/ui/RenderTags.h"
|
||||
|
||||
class IStructuredTextTarget {
|
||||
public:
|
||||
virtual void TAGbegin(TAG_TYPE t,void *data)=0;
|
||||
virtual void TAGend(TAG_TYPE t)=0;
|
||||
virtual void prtt(const QString &v)=0;
|
||||
|
||||
virtual void addEOL() // some targets might want to disable newlines
|
||||
{
|
||||
prtt("\n");
|
||||
}
|
||||
void addSpace(int n=1) {
|
||||
while(n--)
|
||||
prtt(" ");
|
||||
}
|
||||
void addTaggedString(TAG_TYPE t, QString v) {
|
||||
this->TAGbegin(t,nullptr);
|
||||
this->prtt(v);
|
||||
this->TAGend(t);
|
||||
}
|
||||
void addTaggedString(TAG_TYPE t, QString str, void *value) {
|
||||
this->TAGbegin(t,value);
|
||||
this->prtt(str);
|
||||
this->TAGend(t);
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user