diff --git a/CMakeLists.txt b/CMakeLists.txt index a137dc3..4dbf102 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/CallGraph.h b/include/CallGraph.h index 114d92d..f0e4c62 100644 --- a/include/CallGraph.h +++ b/include/CallGraph.h @@ -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 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 */ diff --git a/include/DccFrontend.h b/include/DccFrontend.h index 150330a..877218a 100644 --- a/include/DccFrontend.h +++ b/include/DccFrontend.h @@ -1,5 +1,8 @@ #pragma once #include +#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; +}; diff --git a/include/Procedure.h b/include/Procedure.h index 992bbc1..ea51735 100644 --- a/include/Procedure.h +++ b/include/Procedure.h @@ -7,7 +7,8 @@ #include "CallConvention.h" #include -//#include +#include +#include #include #include #include @@ -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 +typedef std::shared_ptr 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 { typedef llvm::iplist BasicBlockListType; // BasicBlock iterators... @@ -154,7 +159,7 @@ struct Function : public llvm::ilist_node 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,16 +169,16 @@ 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 */ STATE state; /* Entry state */ - int depth; /* Depth at which we found it - for printing */ - uint32_t flg; /* Combination of Icode & Proc flags */ - int16_t cbParam; /* Probable no. of bytes of parameters */ - STKFRAME args; /* Array of arguments */ - LOCAL_ID localId; /* Local identifiers */ + int depth; /* Depth at which we found it - for printing */ + uint32_t flg; /* Combination of Icode & Proc flags */ + int16_t cbParam; /* Probable no. of bytes of parameters */ + STKFRAME args; /* Array of arguments */ + LOCAL_ID localId; /* Local identifiers */ /* Icodes and control flow graph */ CIcodeRec Icode; /* Object with ICODE records */ @@ -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(); @@ -277,31 +283,13 @@ protected: void genLiveKtes(); bool findDerivedSeq(derSeq &derivedGi); bool nextOrderGraph(derSeq &derivedGi); - void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll); + void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll); 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 - : public ilist_default_traits { - // createSentinel is used to get hold of the node that marks the end of the - // list... (same trick used here as in ilist_traits) - typename ::Function *createSentinel() const { - return static_cast(&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 Sentinel; -}; -} -typedef llvm::iplist FunctionListType; +typedef std::list FunctionListType; typedef FunctionListType lFunction; typedef lFunction::iterator ilFunction; diff --git a/include/StackFrame.h b/include/StackFrame.h index 13f0506..2a52a8a 100644 --- a/include/StackFrame.h +++ b/include/StackFrame.h @@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon //std::vector 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) { } diff --git a/include/dcc.h b/include/dcc.h index c5c6751..6f7afa4 100644 --- a/include/dcc.h +++ b/include/dcc.h @@ -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 */ diff --git a/include/dcc_interface.h b/include/dcc_interface.h index 8ef88eb..8421104 100644 --- a/include/dcc_interface.h +++ b/include/dcc_interface.h @@ -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; diff --git a/include/disassem.h b/include/disassem.h index 37fe06c..26d57f6 100644 --- a/include/disassem.h +++ b/include/disassem.h @@ -7,12 +7,16 @@ #pragma once #include "bundle.h" +#include #include #include #include #include + struct LLInst; struct Function; +typedef std::shared_ptr 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) */ diff --git a/include/project.h b/include/project.h index 7c1c3bc..66d457e 100644 --- a/include/project.h +++ b/include/project.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -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"; } @@ -85,11 +90,6 @@ class Project : public QObject { Q_OBJECT public: - typedef llvm::iplist FunctionListType; - typedef FunctionListType lFunction; - typedef FunctionListType::iterator ilFunction; - -public: DosLoader * m_selected_loader; bool m_metadata_available=false; LoaderMetadata m_loader_data; @@ -101,6 +101,8 @@ public: PROG prog; /* Loaded program image parameters */ CommandStream m_project_command_stream; + std::unordered_map m_function_streams; + bool m_error_state; struct PatternLocator *m_pattern_locator; public: @@ -121,9 +123,10 @@ public: const QString & project_name() const {return m_project_name;} 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); + ilFunction funcIter(Function *to_find); + 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: diff --git a/include/symtab.h b/include/symtab.h index 2f9f8a4..d8d28f3 100644 --- a/include/symtab.h +++ b/include/symtab.h @@ -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]; diff --git a/src/CallConvention.cpp b/src/CallConvention.cpp index 5dd6d09..fb6b4d3 100644 --- a/src/CallConvention.cpp +++ b/src/CallConvention.cpp @@ -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; diff --git a/src/Command.cpp b/src/Command.cpp index 482bdad..261c1ed 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -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; } diff --git a/src/Command.h b/src/Command.h index 280cca5..71d6a81 100644 --- a/src/Command.h +++ b/src/Command.h @@ -1,11 +1,14 @@ #ifndef COMMAND_H #define COMMAND_H +#include #include #include #include class Project; +struct Function; +typedef std::shared_ptr PtrFunction; enum CommandLevel { eProject, eBinary, @@ -22,6 +25,7 @@ public: } Project *m_project; + PtrFunction *m_func; QVector> 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; } diff --git a/src/DccFrontend.cpp b/src/DccFrontend.cpp index e528cc4..bc6d543 100644 --- a/src/DccFrontend.cpp +++ b/src/DccFrontend.cpp @@ -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,87 +151,6 @@ bool DccFrontend::FrontEnd () /***************************************************************************** * LoadImage ****************************************************************************/ -struct MachineStateInitialization : public Command { - -public: - MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {} - - bool execute(CommandContext *ctx) override - { - assert(ctx && ctx->m_project); - Project &proj(*ctx->m_project); - const PROG &prog(proj.prog); - proj.m_entry_state.setState(rES, 0); /* PSP segment */ - proj.m_entry_state.setState(rDS, 0); - proj.m_entry_state.setState(rCS, prog.initCS); - proj.m_entry_state.setState(rSS, prog.initSS); - proj.m_entry_state.setState(rSP, prog.initSP); - proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP; - 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 { - Project &proj(*ctx->m_project); - const PROG &prog(proj.prog); - - 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); - //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 */ @@ -241,3 +160,67 @@ void DccFrontend::parse(Project &proj) proj.addCommand(new MachineStateInitialization); proj.addCommand(new FindMain); } + +bool MachineStateInitialization::execute(CommandContext *ctx) +{ + assert(ctx && ctx->m_project); + Project &proj(*ctx->m_project); + const PROG &prog(proj.prog); + proj.m_entry_state.setState(rES, 0); /* PSP segment */ + proj.m_entry_state.setState(rDS, 0); + proj.m_entry_state.setState(rCS, prog.initCS); + proj.m_entry_state.setState(rSS, prog.initSS); + proj.m_entry_state.setState(rSP, prog.initSP); + proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP; + proj.SynthLab = SYNTHESIZED_MIN; + return true; +} + +bool FindMain::execute(CommandContext *ctx) { + Project &proj(*ctx->m_project); + const PROG &prog(proj.prog); + + 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; + } + 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); + +} diff --git a/src/FollowControlFlow.cpp b/src/FollowControlFlow.cpp new file mode 100644 index 0000000..f59f3db --- /dev/null +++ b/src/FollowControlFlow.cpp @@ -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; +} diff --git a/src/FollowControlFlow.h b/src/FollowControlFlow.h new file mode 100644 index 0000000..2e7e063 --- /dev/null +++ b/src/FollowControlFlow.h @@ -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 diff --git a/src/Procedure.cpp b/src/Procedure.cpp index 5d72ad7..ff49ba8 100644 --- a/src/Procedure.cpp +++ b/src/Procedure.cpp @@ -3,6 +3,9 @@ #include "msvc_fixes.h" #include "project.h" #include "scanner.h" +#include "ui/StructuredTextTarget.h" + +#include //FunctionType *Function::getFunctionType() const //{ @@ -39,9 +42,83 @@ 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) { - m_call_conv=CConv::create(cc); - assert(m_call_conv); + m_call_conv=CConv::create(cc); + assert(m_call_conv); } diff --git a/src/backend.cpp b/src/backend.cpp index fe8bb36..a3e158f 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -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 */ { diff --git a/src/chklib.cpp b/src/chklib.cpp index 641d449..c02f27c 100644 --- a/src/chklib.cpp +++ b/src/chklib.cpp @@ -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 diff --git a/src/chklib.h b/src/chklib.h index b261893..92a5d56 100644 --- a/src/chklib.h +++ b/src/chklib.h @@ -20,11 +20,11 @@ struct LoadPatternLibrary : public Command { class PatternLocator { std::vector 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 diff --git a/src/dcc_interface.cpp b/src/dcc_interface.cpp index 4ecc3aa..654bdc9 100644 --- a/src/dcc_interface.cpp +++ b/src/dcc_interface.cpp @@ -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("."); diff --git a/src/disassem.cpp b/src/disassem.cpp index 7b7558b..e5aa49e 100644 --- a/src/disassem.cpp +++ b/src/disassem.cpp @@ -91,7 +91,7 @@ static map 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) diff --git a/src/idioms.cpp b/src/idioms.cpp index 79a3f14..2f6fa65 100644 --- a/src/idioms.cpp +++ b/src/idioms.cpp @@ -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; diff --git a/src/parser.cpp b/src/parser.cpp index 9920933..de3cd66 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -10,7 +10,7 @@ #include #include -#include /* For exit() */ +#include /* For exit() */ #include #include #include @@ -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. */ @@ -127,7 +127,7 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) { // Danger! Dcc will likely fall over in this code. // So we act as though we have done with this proc - // pProc->flg &= ~TERMINATES; // Not sure about this + // pProc->flg &= ~TERMINATES; // Not sure about this done = true; // And mark it as a library function, so structure() won't choke on it flg |= PROC_ISLIB; @@ -180,8 +180,8 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) case iJCXZ: { STATE StCopy; - int ip = Icode.size()-1; /* Index of this jump */ - ICODE &prev(*(++Icode.rbegin())); /* Previous icode */ + int ip = Icode.size()-1; /* Index of this jump */ + ICODE &prev(*(++Icode.rbegin())); /* Previous icode */ bool fBranch = false; pstate->JCond.regi = 0; @@ -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; } diff --git a/src/procs.cpp b/src/procs.cpp index 4f046ac..5204f82 100644 --- a/src/procs.cpp +++ b/src/procs.cpp @@ -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,23 +43,23 @@ 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) { insertArc (callee); return true; } - for (CALL_GRAPH *edg : outEdges) - if (edg->insertCallGraph (caller, callee)) - return true; + for (CALL_GRAPH *edg : outEdges) + if (edg->insertCallGraph (caller, callee)) + return true; 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 diff --git a/src/project.cpp b/src/project.cpp index 79bec21..404064d 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -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) { diff --git a/src/scanner.cpp b/src/scanner.cpp index 374bb0f..8b6f967 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1,5 +1,5 @@ -/***************************************************************************** - * dcc project scanner module +/** + * dcc project scanner module * Implements a simple state driven scanner to convert 8086 machine code into * I-code * (C) Cristina Cifuentes, Jeff Ledermann @@ -51,8 +51,8 @@ static void none1(int i); static void none2(int i); static void checkInt(int i); -#define iZERO (llIcode)0 // For neatness -#define IC llIcode +#define iZERO (llIcode)0 // For neatness +#define IC llIcode static struct { void (*state1)(int); @@ -60,26 +60,26 @@ static struct { uint32_t flg; llIcode opcode; } stateTable[] = { - { modrm, none2, B , iADD }, /* 00 */ - { modrm, none2, 0 , iADD }, /* 01 */ - { modrm, none2, TO_REG | B , iADD }, /* 02 */ - { modrm, none2, TO_REG , iADD }, /* 03 */ - { data1, axImp, B , iADD }, /* 04 */ - { data2, axImp, 0 , iADD }, /* 05 */ - { segop, none2, NO_SRC , iPUSH }, /* 06 */ - { segop, none2, NO_SRC , iPOP }, /* 07 */ - { modrm, none2, B , iOR }, /* 08 */ - { modrm, none2, NSP , iOR }, /* 09 */ - { modrm, none2, TO_REG | B , iOR }, /* 0A */ - { modrm, none2, TO_REG | NSP , iOR }, /* 0B */ - { data1, axImp, B , iOR }, /* 0C */ - { data2, axImp, 0 , iOR }, /* 0D */ - { segop, none2, NO_SRC , iPUSH }, /* 0E */ - { none1, none2, OP386 , iZERO }, /* 0F */ - { modrm, none2, B , iADC }, /* 10 */ - { modrm, none2, NSP , iADC }, /* 11 */ - { modrm, none2, TO_REG | B , iADC }, /* 12 */ - { modrm, none2, TO_REG | NSP , iADC }, /* 13 */ + { modrm, none2, B , iADD }, /* 00 */ + { modrm, none2, 0 , iADD }, /* 01 */ + { modrm, none2, TO_REG | B , iADD }, /* 02 */ + { modrm, none2, TO_REG , iADD }, /* 03 */ + { data1, axImp, B , iADD }, /* 04 */ + { data2, axImp, 0 , iADD }, /* 05 */ + { segop, none2, NO_SRC , iPUSH }, /* 06 */ + { segop, none2, NO_SRC , iPOP }, /* 07 */ + { modrm, none2, B , iOR }, /* 08 */ + { modrm, none2, NSP , iOR }, /* 09 */ + { modrm, none2, TO_REG | B , iOR }, /* 0A */ + { modrm, none2, TO_REG | NSP , iOR }, /* 0B */ + { data1, axImp, B , iOR }, /* 0C */ + { data2, axImp, 0 , iOR }, /* 0D */ + { segop, none2, NO_SRC , iPUSH }, /* 0E */ + { none1, none2, OP386 , iZERO }, /* 0F */ + { modrm, none2, B , iADC }, /* 10 */ + { modrm, none2, NSP , iADC }, /* 11 */ + { modrm, none2, TO_REG | B , iADC }, /* 12 */ + { modrm, none2, TO_REG | NSP , iADC }, /* 13 */ { data1, axImp, B , iADC }, /* 14 */ { data2, axImp, 0 , iADC }, /* 15 */ { segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */ @@ -87,59 +87,59 @@ static struct { { modrm, none2, B , iSBB }, /* 18 */ { modrm, none2, NSP , iSBB }, /* 19 */ { modrm, none2, TO_REG | B , iSBB }, /* 1A */ - { modrm, none2, TO_REG | NSP , iSBB }, /* 1B */ - { data1, axImp, B , iSBB }, /* 1C */ - { data2, axImp, 0 , iSBB }, /* 1D */ - { segop, none2, NO_SRC , iPUSH }, /* 1E */ - { segop, none2, NO_SRC , iPOP }, /* 1F */ - { modrm, none2, B , iAND }, /* 20 */ - { modrm, none2, NSP , iAND }, /* 21 */ - { modrm, none2, TO_REG | B , iAND }, /* 22 */ - { modrm, none2, TO_REG | NSP , iAND }, /* 23 */ - { data1, axImp, B , iAND }, /* 24 */ - { data2, axImp, 0 , iAND }, /* 25 */ - { prefix, none2, 0 , (IC)rES}, /* 26 */ - { none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */ - { modrm, none2, B , iSUB }, /* 28 */ - { modrm, none2, 0 , iSUB }, /* 29 */ - { modrm, none2, TO_REG | B , iSUB }, /* 2A */ - { modrm, none2, TO_REG , iSUB }, /* 2B */ - { data1, axImp, B , iSUB }, /* 2C */ - { data2, axImp, 0 , iSUB }, /* 2D */ - { prefix, none2, 0 , (IC)rCS}, /* 2E */ - { none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */ - { modrm, none2, B , iXOR }, /* 30 */ - { modrm, none2, NSP , iXOR }, /* 31 */ - { modrm, none2, TO_REG | B , iXOR }, /* 32 */ - { modrm, none2, TO_REG | NSP , iXOR }, /* 33 */ - { data1, axImp, B , iXOR }, /* 34 */ - { data2, axImp, 0 , iXOR }, /* 35 */ - { prefix, none2, 0 , (IC)rSS}, /* 36 */ - { none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */ - { modrm, none2, B , iCMP }, /* 38 */ - { modrm, none2, NSP , iCMP }, /* 39 */ - { modrm, none2, TO_REG | B , iCMP }, /* 3A */ - { modrm, none2, TO_REG | NSP , iCMP }, /* 3B */ - { data1, axImp, B , iCMP }, /* 3C */ - { data2, axImp, 0 , iCMP }, /* 3D */ - { prefix, none2, 0 , (IC)rDS}, /* 3E */ - { none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */ - { regop, none2, 0 , iINC }, /* 40 */ - { regop, none2, 0 , iINC }, /* 41 */ - { regop, none2, 0 , iINC }, /* 42 */ - { regop, none2, 0 , iINC }, /* 43 */ - { regop, none2, NOT_HLL , iINC }, /* 44 */ - { regop, none2, 0 , iINC }, /* 45 */ - { regop, none2, 0 , iINC }, /* 46 */ - { regop, none2, 0 , iINC }, /* 47 */ - { regop, none2, 0 , iDEC }, /* 48 */ - { regop, none2, 0 , iDEC }, /* 49 */ - { regop, none2, 0 , iDEC }, /* 4A */ - { regop, none2, 0 , iDEC }, /* 4B */ - { regop, none2, NOT_HLL , iDEC }, /* 4C */ - { regop, none2, 0 , iDEC }, /* 4D */ - { regop, none2, 0 , iDEC }, /* 4E */ - { regop, none2, 0 , iDEC }, /* 4F */ + { modrm, none2, TO_REG | NSP , iSBB }, /* 1B */ + { data1, axImp, B , iSBB }, /* 1C */ + { data2, axImp, 0 , iSBB }, /* 1D */ + { segop, none2, NO_SRC , iPUSH }, /* 1E */ + { segop, none2, NO_SRC , iPOP }, /* 1F */ + { modrm, none2, B , iAND }, /* 20 */ + { modrm, none2, NSP , iAND }, /* 21 */ + { modrm, none2, TO_REG | B , iAND }, /* 22 */ + { modrm, none2, TO_REG | NSP , iAND }, /* 23 */ + { data1, axImp, B , iAND }, /* 24 */ + { data2, axImp, 0 , iAND }, /* 25 */ + { prefix, none2, 0 , (IC)rES}, /* 26 */ + { none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */ + { modrm, none2, B , iSUB }, /* 28 */ + { modrm, none2, 0 , iSUB }, /* 29 */ + { modrm, none2, TO_REG | B , iSUB }, /* 2A */ + { modrm, none2, TO_REG , iSUB }, /* 2B */ + { data1, axImp, B , iSUB }, /* 2C */ + { data2, axImp, 0 , iSUB }, /* 2D */ + { prefix, none2, 0 , (IC)rCS}, /* 2E */ + { none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */ + { modrm, none2, B , iXOR }, /* 30 */ + { modrm, none2, NSP , iXOR }, /* 31 */ + { modrm, none2, TO_REG | B , iXOR }, /* 32 */ + { modrm, none2, TO_REG | NSP , iXOR }, /* 33 */ + { data1, axImp, B , iXOR }, /* 34 */ + { data2, axImp, 0 , iXOR }, /* 35 */ + { prefix, none2, 0 , (IC)rSS}, /* 36 */ + { none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */ + { modrm, none2, B , iCMP }, /* 38 */ + { modrm, none2, NSP , iCMP }, /* 39 */ + { modrm, none2, TO_REG | B , iCMP }, /* 3A */ + { modrm, none2, TO_REG | NSP , iCMP }, /* 3B */ + { data1, axImp, B , iCMP }, /* 3C */ + { data2, axImp, 0 , iCMP }, /* 3D */ + { prefix, none2, 0 , (IC)rDS}, /* 3E */ + { none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */ + { regop, none2, 0 , iINC }, /* 40 */ + { regop, none2, 0 , iINC }, /* 41 */ + { regop, none2, 0 , iINC }, /* 42 */ + { regop, none2, 0 , iINC }, /* 43 */ + { regop, none2, NOT_HLL , iINC }, /* 44 */ + { regop, none2, 0 , iINC }, /* 45 */ + { regop, none2, 0 , iINC }, /* 46 */ + { regop, none2, 0 , iINC }, /* 47 */ + { regop, none2, 0 , iDEC }, /* 48 */ + { regop, none2, 0 , iDEC }, /* 49 */ + { regop, none2, 0 , iDEC }, /* 4A */ + { regop, none2, 0 , iDEC }, /* 4B */ + { regop, none2, NOT_HLL , iDEC }, /* 4C */ + { regop, none2, 0 , iDEC }, /* 4D */ + { regop, none2, 0 , iDEC }, /* 4E */ + { regop, none2, 0 , iDEC }, /* 4F */ { regop, none2, NO_SRC , iPUSH }, /* 50 */ { regop, none2, NO_SRC , iPUSH }, /* 51 */ { regop, none2, NO_SRC , iPUSH }, /* 52 */ diff --git a/src/udm.cpp b/src/udm.cpp index 9bd455b..c0e04a3 100644 --- a/src/udm.cpp +++ b/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(); } } diff --git a/src/ui/DccMainWindow.cpp b/src/ui/DccMainWindow.cpp index 4900a6c..13ddb02 100644 --- a/src/ui/DccMainWindow.cpp +++ b/src/ui/DccMainWindow.cpp @@ -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(); diff --git a/src/ui/DccMainWindow.h b/src/ui/DccMainWindow.h index adbf75c..daf2aa1 100644 --- a/src/ui/DccMainWindow.h +++ b/src/ui/DccMainWindow.h @@ -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 diff --git a/src/ui/FunctionListDockWidget.cpp b/src/ui/FunctionListDockWidget.cpp index eab9b69..34fee5e 100644 --- a/src/ui/FunctionListDockWidget.cpp +++ b/src/ui/FunctionListDockWidget.cpp @@ -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 //#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 "<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 "<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(); } @@ -63,19 +63,29 @@ QVariant FunctionListModel::data(const QModelIndex &idx,int role) const { switch(column) { - case 0: // name - { - return QVariant(inf.m_name); - } - case 1: // step - return QVariant(inf.m_decoding_step); - case 2: // start offset - { - QString in_base_16=QString("%1").arg(inf.m_start_off,0,16); - return QVariant(in_base_16); - } + case 0: // name + { + return QVariant(inf.m_name); + } + case 1: { // step + switch(inf.m_decoding_step) { + case eNotDecoded: + return "Undecoded"; + case eDisassemblyInProgress: + return "Disassembly in progress"; + case eDissassembled: + return "Disassembled"; default: - return QVariant(); + return "UNKNOWN STATE"; + } + } + case 2: // start offset + { + QString in_base_16=QString("%1").arg(inf.m_start_off,0,16); + return QVariant(in_base_16); + } + default: + return QVariant(); } } @@ -87,14 +97,14 @@ QVariant FunctionListModel::headerData(int section, Qt::Orientation orientation, { switch(section) { - case 0: // name - return QObject::tr("Function name"); - case 1: // step - return QObject::tr("Decoding step"); - case 2: // start offset - return QObject::tr("Start offset"); - default: - return QVariant(); + case 0: // name + return QObject::tr("Function name"); + case 1: // step + return QObject::tr("Decoding step"); + case 2: // start offset + return QObject::tr("Start offset"); + default: + return QVariant(); } } diff --git a/src/ui/FunctionListDockWidget.h b/src/ui/FunctionListDockWidget.h index 89e0935..c882e6f 100644 --- a/src/ui/FunctionListDockWidget.h +++ b/src/ui/FunctionListDockWidget.h @@ -4,7 +4,7 @@ #include #include //#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 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; diff --git a/src/ui/FunctionViewWidget.cpp b/src/ui/FunctionViewWidget.cpp index 145b6e9..5b3d027 100644 --- a/src/ui/FunctionViewWidget.cpp +++ b/src/ui/FunctionViewWidget.cpp @@ -22,9 +22,9 @@ void FunctionViewWidget::prtt(const char *s) collected_text+=s; //collected_text+="
"; } -void FunctionViewWidget::prtt(const std::string &s) +void FunctionViewWidget::prtt(const QString &s) { - collected_text+=s.c_str(); + collected_text+=s; //collected_text+="
"; } void FunctionViewWidget::TAGbegin(TAG_TYPE tag_type, void *p) diff --git a/src/ui/FunctionViewWidget.h b/src/ui/FunctionViewWidget.h index 2d69ec9..d22ef54 100644 --- a/src/ui/FunctionViewWidget.h +++ b/src/ui/FunctionViewWidget.h @@ -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: diff --git a/src/ui/RenderTags.h b/src/ui/RenderTags.h index c56afc4..1b37604 100644 --- a/src/ui/RenderTags.h +++ b/src/ui/RenderTags.h @@ -1,20 +1,20 @@ #pragma once -#include +#include enum TAG_TYPE { XT_invalid = 0, XT_blank, XT_Symbol, XT_Function, - XT_Keyword, //Keywords, such as struct, union, for, while - XT_Class, //For comound types (struct/class/union) - XT_K1, //Braces {} [] - XT_Comment, //Comments + XT_Keyword, //Keywords, such as struct, union, for, while + XT_Class, //For comound types (struct/class/union) + XT_K1, //Braces {} [] + XT_Comment, //Comments XT_DataType, // - XT_Number, // + XT_Number, // XT_AsmStack, //stack values - XT_AsmOffset, //seg:offset + XT_AsmOffset, //seg:offset XT_AsmLabel, //label name XT_FuncName, }; diff --git a/src/ui/StructuredTextTarget.h b/src/ui/StructuredTextTarget.h index dadd174..93a4108 100644 --- a/src/ui/StructuredTextTarget.h +++ b/src/ui/StructuredTextTarget.h @@ -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); + } };