diff --git a/CMakeLists.txt b/CMakeLists.txt index 009dd8c..a137dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,22 @@ set(dcc_LIB_SOURCES src/Loaders.cpp src/Loaders.h ) +set(dcc_UI_SOURCES + src/ui/DccMainWindow.ui + src/ui/DccMainWindow.h + src/ui/DccMainWindow.cpp + src/ui/FunctionViewWidget.ui + src/ui/FunctionViewWidget.h + src/ui/FunctionViewWidget.cpp + src/ui/FunctionListDockWidget.ui + src/ui/FunctionListDockWidget.cpp + src/ui/FunctionListDockWidget.h + src/ui/RenderTags.cpp + src/ui/RenderTags.h + src/ui/CommandQueueView.cpp + src/ui/CommandQueueView.h + src/ui/CommandQueueView.ui +) set(dcc_SOURCES src/dcc.cpp ) @@ -142,7 +158,7 @@ ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS}) qt5_use_modules(dcc_lib Core) #cotire(dcc_lib) -ADD_EXECUTABLE(dcc_original ${dcc_SOURCES}) +ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_UI_SOURCES}) ADD_DEPENDENCIES(dcc_original dcc_lib) TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport) qt5_use_modules(dcc_original Core Widgets) diff --git a/common/perfhlib.h b/common/perfhlib.h index a7221b8..81346cf 100644 --- a/common/perfhlib.h +++ b/common/perfhlib.h @@ -1,3 +1,5 @@ +#pragma once + #include /** Perfect hashing function library. Contains functions to generate perfect hashing functions */ diff --git a/include/BinaryImage.h b/include/BinaryImage.h index e713633..69083b9 100644 --- a/include/BinaryImage.h +++ b/include/BinaryImage.h @@ -14,10 +14,8 @@ struct PROG /* Loaded program image parameters */ int cProcs; /* Number of procedures so far */ int offMain; /* The offset of the main() proc */ uint16_t segMain; /* The segment of the main() proc */ - bool bSigs; /* True if signatures loaded */ int cbImage; /* Length of image in bytes */ uint8_t * Imagez; /* Allocated by loader to hold entire program image */ - int addressingMode; public: const uint8_t *image() const {return Imagez;} void displayLoadInfo(); diff --git a/include/DccFrontend.h b/include/DccFrontend.h index 5a0a9dd..150330a 100644 --- a/include/DccFrontend.h +++ b/include/DccFrontend.h @@ -9,7 +9,6 @@ class DccFrontend : public QObject public: explicit DccFrontend(QObject *parent = 0); bool FrontEnd(); /* frontend.c */ - void initializeMachineState(Project & proj); signals: diff --git a/include/Procedure.h b/include/Procedure.h index 1e4347d..57879a8 100644 --- a/include/Procedure.h +++ b/include/Procedure.h @@ -164,6 +164,7 @@ protected: } public: + int nStep; // decompilation step number for this function FunctionType * type; uint32_t procEntry; /* label number */ QString name; /* Meaningful name for this proc */ diff --git a/include/dcc.h b/include/dcc.h index 9ede23d..c5c6751 100644 --- a/include/dcc.h +++ b/include/dcc.h @@ -88,7 +88,7 @@ void interactDis(Function *, int initIC); /* disassem.c */ bool JmpInst(llIcode opcode); /* idioms.c */ queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */ -bool SetupLibCheck(void); /* chklib.c */ +bool SetupLibCheck(QString pattern_file_id); /* chklib.c */ void CleanupLibCheck(void); /* chklib.c */ bool LibCheck(Function &p); /* chklib.c */ diff --git a/include/dcc_interface.h b/include/dcc_interface.h index 12488e1..8ef88eb 100644 --- a/include/dcc_interface.h +++ b/include/dcc_interface.h @@ -5,18 +5,20 @@ #include #include -class IXmlTarget; +class IStructuredTextTarget; struct IDcc { static IDcc *get(); virtual void BaseInit()=0; virtual void Init(QObject *tgt)=0; - virtual lFunction::iterator GetFirstFuncHandle()=0; - virtual lFunction::iterator GetCurFuncHandle()=0; + virtual ilFunction GetFirstFuncHandle()=0; + virtual ilFunction GetNextFuncHandle(ilFunction iter)=0; + virtual ilFunction GetCurFuncHandle()=0; + virtual bool isValidFuncHandle(ilFunction) = 0; virtual void analysis_Once()=0; - virtual void load(QString name)=0; // load and preprocess -> find entry point - virtual void prtout_asm(IXmlTarget *,int level=0)=0; - virtual void prtout_cpp(IXmlTarget *,int level=0)=0; + virtual bool load(QString name)=0; // load and preprocess -> find entry point + virtual void prtout_asm(IStructuredTextTarget *,int level=0)=0; + virtual void prtout_cpp(IStructuredTextTarget *,int level=0)=0; virtual size_t getFuncCount()=0; virtual const lFunction &validFunctions() const =0; virtual void SetCurFunc_by_Name(QString )=0; diff --git a/include/project.h b/include/project.h index 34b7b7f..7c1c3bc 100644 --- a/include/project.h +++ b/include/project.h @@ -25,6 +25,62 @@ struct SegOffAddr { uint16_t seg; uint32_t addr; }; +enum CompilerVendor { + eUnknownVendor=0, + eBorland, + eMicrosoft, + eLogitech, +}; +enum CompilerLanguage { + eUnknownLanguage=0, + eAnsiCorCPP, + ePascal, + eModula2 +}; +enum CompilerMemoryModel { + eUnknownMemoryModel=0, + eTiny, + eSmall, + eCompact, + eMedium, + eLarge +}; +struct LoaderMetadata { + CompilerVendor compiler_vendor; + CompilerLanguage compiler_language; + CompilerMemoryModel compiler_memory_model; + int compiler_version; + QString compilerId() const { + switch(compiler_vendor) { + case eBorland: + switch(compiler_language) { + case eUnknownLanguage: + return QString("bx") + codeModelChar(); + case eAnsiCorCPP: + return QString("b%1%2").arg(compiler_version).arg(codeModelChar()); + case ePascal: + return QString("tp%1").arg(compiler_version); + } + case eMicrosoft: + assert(compiler_language==eAnsiCorCPP); + return QString("m%1%2").arg(compiler_version).arg(codeModelChar()); + case eLogitech: + assert(compiler_language==eModula2); + return QString("l%1%2").arg(compiler_version).arg(codeModelChar()); + } + return "xxx"; + } + QChar codeModelChar() const { + switch(compiler_memory_model) { + case eUnknownMemoryModel: return 'x'; + case eTiny: return 't'; + case eSmall: return 's'; + case eCompact: return 'c'; + case eMedium: return 'm'; + case eLarge: return 'l'; + } + } +}; class Project : public QObject { Q_OBJECT @@ -33,8 +89,10 @@ public: typedef FunctionListType lFunction; typedef FunctionListType::iterator ilFunction; - DosLoader * m_selected_loader; -public: +public: + DosLoader * m_selected_loader; + bool m_metadata_available=false; + LoaderMetadata m_loader_data; uint32_t SynthLab; //!< Last snthetic lab idx SYMTAB symtab; //!< Global symbol table FunctionListType pProcList; //!< List of located functions @@ -44,6 +102,7 @@ public: PROG prog; /* Loaded program image parameters */ CommandStream m_project_command_stream; bool m_error_state; + struct PatternLocator *m_pattern_locator; public: // prevent Project instance copying Project(const Project&) = delete; @@ -74,6 +133,8 @@ public: const QString & symbolName(size_t idx); const SYM & getSymByIdx(size_t idx) const; + LoaderMetadata &getLoaderMetadata() { assert(m_metadata_available); return m_loader_data; } + void setLoaderMetadata(LoaderMetadata d) { m_loader_data = d; m_metadata_available=true;} static Project * get(); PROG * binary() {return &prog;} SourceMachine *machine(); @@ -81,14 +142,16 @@ public: const FunctionListType &functions() const { return pProcList; } FunctionListType &functions() { return pProcList; } - bool addCommand(Command *cmd) { return m_project_command_stream.add(cmd); } + bool addCommand(Command *cmd) { return m_project_command_stream.add(cmd); emit commandListChanged(); } void dumpAllErrors(); void setLoader(DosLoader *ins); + void processCommands(int count=1); public slots: void onCommandStreamFinished(bool state); signals: void newFunctionCreated(Function &); void loaderSelected(); + void commandListChanged(); protected: void initialize(); void writeGlobSymTable(); diff --git a/sigs/dccb3l.sig b/sigs/dccb3l.sig new file mode 100644 index 0000000..ed23b4c Binary files /dev/null and b/sigs/dccb3l.sig differ diff --git a/sigs/dccb3s.SIG b/sigs/dccb3s.SIG new file mode 100644 index 0000000..65db78e Binary files /dev/null and b/sigs/dccb3s.SIG differ diff --git a/src/Command.cpp b/src/Command.cpp index 74c25d8..482bdad 100644 --- a/src/Command.cpp +++ b/src/Command.cpp @@ -8,7 +8,7 @@ bool LoaderSelection::execute(CommandContext * ctx) { - Project *proj=ctx->proj; + Project *proj=ctx->m_project; if(nullptr==proj) { ctx->recordFailure(this,"No active project "); return false; @@ -47,7 +47,7 @@ bool LoaderSelection::execute(CommandContext * ctx) bool LoaderApplication::execute(CommandContext * ctx) { - Project *proj=ctx->proj; + Project *proj=ctx->m_project; if(nullptr==proj) { ctx->recordFailure(this,"No active project "); @@ -96,6 +96,20 @@ void CommandStream::processAll(CommandContext *ctx) emit streamCompleted(true); } +bool CommandStream::processOne(CommandContext *ctx) +{ + if(not m_commands.isEmpty()) { + Command *cmd = m_commands.takeFirst(); + if(false==cmd->execute(ctx)) { + emit streamChanged(); + return false; + } + m_recently_executed.push_back(cmd); + } + emit streamChanged(); + return true; +} + void CommandStream::clear() { qDeleteAll(m_commands); diff --git a/src/Command.h b/src/Command.h index fe510f2..d04a921 100644 --- a/src/Command.h +++ b/src/Command.h @@ -21,7 +21,7 @@ public: m_failures.push_back({cmd,error_message}); } - Project *proj; + Project *m_project; QVector> m_failures; void reset(); }; @@ -60,10 +60,12 @@ public: QVector m_commands; bool add(Command *c); void setMaximumCommandCount(int maximum_command_count); + bool processOne(CommandContext *ctx); void processAll(CommandContext *ctx); void clear(); signals: void streamCompleted(bool success); + void streamChanged(); }; // Effect: loader has been selected and set in current project class LoaderSelection : public Command { diff --git a/src/DccFrontend.cpp b/src/DccFrontend.cpp index c5490c2..e528cc4 100644 --- a/src/DccFrontend.cpp +++ b/src/DccFrontend.cpp @@ -7,6 +7,7 @@ #include "disassem.h" #include "CallGraph.h" #include "Command.h" +#include "chklib.h" #include #include @@ -157,8 +158,8 @@ public: bool execute(CommandContext *ctx) override { - assert(ctx && ctx->proj); - Project &proj(*ctx->proj); + 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); @@ -180,7 +181,7 @@ struct CreateFunction : public Command { m_type(f) {} bool execute(CommandContext *ctx) override { - Project &proj(*ctx->proj); + Project &proj(*ctx->m_project); const PROG &prog(proj.prog); proj.createFunction(m_type,m_name,m_addr); @@ -201,15 +202,15 @@ struct FindMain : public Command { FindMain() : Command("Locate the main entry point",eProject) { } bool execute(CommandContext *ctx) { - Project &proj(*ctx->proj); + Project &proj(*ctx->m_project); const PROG &prog(proj.prog); - if(ctx->proj->m_entry_state.IP==0) { + 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 */ - ctx->proj->m_entry_state.checkStartup(); + checkStartup(ctx->m_project->m_entry_state); Command *cmd; if (prog.offMain != -1) { @@ -227,29 +228,15 @@ struct FindMain : public Command { cmd = new CreateFunction("start",SegOffAddr {prog.segMain,proj.m_entry_state.IP},main_type); } proj.addCommand(cmd); + proj.addCommand(new LoadPatternLibrary()); return true; } }; -void DccFrontend::initializeMachineState(Project &proj) -{ - 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; -} /* Parses the program, builds the call graph, and returns the list of * procedures found */ void DccFrontend::parse(Project &proj) { - /* This proc needs to be called to set things up for LibCheck(), which - checks a proc to see if it is a know C (etc) library */ - proj.prog.bSigs = SetupLibCheck(); - /* Set initial state */ proj.addCommand(new MachineStateInitialization); proj.addCommand(new FindMain); diff --git a/src/backend.cpp b/src/backend.cpp index 7ba081d..fe8bb36 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -226,7 +226,7 @@ void Function::codeGen (QIODevice &fs) /* Write procedure/function header */ cCode.init(); - if (getReturnType() != TYPE_UNKNOWN) /* Function flg & PROC_IS_FUNC*/ + if (getReturnType() != TYPE_UNKNOWN) /* Function */ ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name); else /* Procedure */ ostr << "\nvoid "+name+" ("; diff --git a/src/chklib.cpp b/src/chklib.cpp index a170dd9..641d449 100644 --- a/src/chklib.cpp +++ b/src/chklib.cpp @@ -4,7 +4,9 @@ * address of main() * (C) Mike van Emmerik */ +#include "chklib.h" +#include "Enums.h" #include "dcc.h" #include "msvc_fixes.h" #include "project.h" @@ -18,22 +20,21 @@ #include #include #include +#include "Command.h" -PerfectHash g_pattern_hasher; #define NIL -1 /* Used like NULL, but 0 is valid */ /* Hash table structure */ -typedef struct HT_tag +struct HT { char htSym[SYMLEN]; - uint8_t htPat[PATLEN]; -} HT; + uint8_t htPat[PATLEN]; +}; /* Structure of the prototypes table. Same as the struct in parsehdr.h, except here we don't need the "next" index (the elements are already sorted by function name) */ -typedef -struct ph_func_tag +struct PH_FUNC_STRUCT { char name[SYMLEN]; /* Name of function or arg */ hlType typ; /* Return type */ @@ -41,38 +42,24 @@ struct ph_func_tag int firstArg; /* Index of first arg in chain */ // int next; /* Index of next function in chain */ bool bVararg; /* True if variable arguements */ -} PH_FUNC_STRUCT; +} ; #define NUM_PLIST 64 /* Number of entries to increase allocation by */ /* statics */ static char buf[100]; /* A general purpose buffer */ -int numKeys; /* Number of hash table entries (keys) */ -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 */ -static FILE *g_file; /* File being read */ -static QString sSigName; /* Full path name of .sig file */ -static uint16_t *T1base, *T2base; /* Pointers to start of T1, T2 */ -static uint16_t *g; /* g[] */ -static HT *ht; /* The hash table */ -static PH_FUNC_STRUCT *pFunc; /* Points to the array of func names */ -static hlType *pArg=nullptr; /* Points to the array of param types */ -static int numFunc; /* Number of func names actually stored */ -static int numArg; /* Number of param names actually stored */ #define DCCLIBS "dcclibs.dat" /* Name of the prototypes data file */ /* prototypes */ -void grab(int n, FILE *_file); -uint16_t readFileShort(FILE *_file); -void readFileSection(uint16_t* p, int len, FILE *_file); -void cleanup(void); -void checkStartup(STATE *state); -void readProtoFile(void); -int searchPList(char *name); -void checkHeap(char *msg); /* For debugging */ +static bool grab(int n, QFile & _file); +static uint16_t readFileShort(FILE *_file); +static void readFileSection(uint16_t* p, int len, QFile & _file); +static void cleanup(void); +static void readProtoFile(void); +static int searchPList(char *name); +static void checkHeap(char *msg); /* For debugging */ void fixWildCards(uint8_t pat[]); /* In fixwild.c */ @@ -294,148 +281,10 @@ static uint8_t pattMsChkstk[] = 0xE9 /* jmp XXXX */ }; - - - -/* This procedure is called to initialise the library check code */ -bool SetupLibCheck(void) -{ - uint16_t w, len; - int i; - IDcc *dcc = IDcc::get(); - QString fpath = dcc->dataDir("sigs").absoluteFilePath(sSigName); - if ((g_file = fopen(qPrintable(fpath), "rb")) == nullptr) - { - printf("Warning: cannot open signature file %s\n", qPrintable(fpath)); - return false; - } - - readProtoFile(); - - - /* Read the parameters */ - grab(4, g_file); - if (memcmp("dccs", buf, 4) != 0) - { - printf("Not a dcc signature file!\n"); - exit(3); - } - numKeys = readFileShort(g_file); - numVert = readFileShort(g_file); - PatLen = readFileShort(g_file); - SymLen = readFileShort(g_file); - if ((PatLen != PATLEN) or (SymLen != SYMLEN)) - { - printf("Sorry! Compiled for sym and pattern lengths of %d and %d\n", SYMLEN, PATLEN); - return false; - } - - /* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */ - /* Set the parameters for the hash table */ - g_pattern_hasher.setHashParams( - numKeys, /* The number of symbols */ - PatLen, /* The length of the pattern to be hashed */ - 256, /* The character set of the pattern (0-FF) */ - 0, /* Minimum pattern character value */ - numVert); /* Specifies c, the sparseness of the graph. See Czech, Havas and Majewski for details */ - T1base = g_pattern_hasher.readT1(); - T2base = g_pattern_hasher.readT2(); - g = g_pattern_hasher.readG(); - - /* Read T1 and T2 tables */ - grab(2, g_file); - if (memcmp("T1", buf, 2) != 0) - { - printf("Expected 'T1'\n"); - exit(3); - } - len = (uint16_t) (PatLen * 256 * sizeof(uint16_t)); - w = readFileShort(g_file); - if (w != len) - { - printf("Problem with size of T1: file %d, calc %d\n", w, len); - return false; - } - readFileSection(T1base, len, g_file); - - grab(2, g_file); - if (memcmp("T2", buf, 2) != 0) - { - printf("Expected 'T2'\n"); - return false; - } - w = readFileShort(g_file); - if (w != len) - { - printf("Problem with size of T2: file %d, calc %d\n", w, len); - return false; - } - readFileSection(T2base, len, g_file); - - /* Now read the function g[] */ - grab(2, g_file); - if (memcmp("gg", buf, 2) != 0) - { - printf("Expected 'gg'\n"); - return false; - } - len = (uint16_t)(numVert * sizeof(uint16_t)); - w = readFileShort(g_file); - if (w != len) - { - printf("Problem with size of g[]: file %d, calc %d\n", w, len); - return false; - } - readFileSection(g, len, g_file); - - - /* This is now the hash table */ - /* First allocate space for the table */ - ht = new HT[numKeys]; - if ( nullptr == ht) - { - printf("Could not allocate hash table\n"); - return false; - } - grab(2, g_file); - if (memcmp("ht", buf, 2) != 0) - { - printf("Expected 'ht'\n"); - return false; - } - w = readFileShort(g_file); - if (w != numKeys * (SymLen + PatLen + sizeof(uint16_t))) - { - printf("Problem with size of hash table: file %d, calc %d\n", w, len); - return false; - } - - - for (i=0; i < numKeys; i++) - { - if (fread(&ht[i], 1, SymLen + PatLen, g_file) != SymLen + PatLen) - { - printf("Could not read signature\n"); - return false; - } - } - fclose(g_file); - return true; -} - - -void CleanupLibCheck(void) -{ - /* Deallocate all the stuff allocated in SetupLibCheck() */ - delete [] ht; - delete [] pFunc; -} - - /* Check this function to see if it is a library function. Return true if it is, and copy its name to pProc->name */ -bool LibCheck(Function & pProc) +bool PatternLocator::LibCheck(Function & pProc) { PROG &prog(Project::get()->prog); long fileOffset; @@ -443,13 +292,6 @@ bool LibCheck(Function & pProc) int Idx; uint8_t pat[PATLEN]; - if (prog.bSigs == false) - { - /* No signatures... can't rely on hash parameters to be initialised - so always return false */ - return false; - } - fileOffset = pProc.procEntry; /* Offset into the image */ if (fileOffset == prog.offMain) { @@ -545,35 +387,29 @@ bool LibCheck(Function & pProc) -void grab(int n, FILE *_file) +bool grab(int n, QFile &_file) { - if (fread(buf, 1, n, _file) != (unsigned)n) + + if (_file.read(buf,n) != n) { - printf("Could not grab\n"); - exit(11); + qCritical() << "File read failed"; + return false; } + return true; } -uint16_t -readFileShort(FILE *f) +uint16_t readFileShort(QFile &f) { - uint8_t b1, b2; - - if (fread(&b1, 1, 1, f) != 1) - { - printf("Could not read short\n"); - exit(11); + uint16_t tgt; + if(sizeof(tgt)!=f.read((char *)&tgt,sizeof(tgt))) { + qCritical() << "File read failed"; + return false; } - if (fread(&b2, 1, 1, f) != 1) - { - printf("Could not read short\n"); - exit(11); - } - return (uint16_t)(b2 << 8) + (uint16_t)b1; + return tgt; } // Read a section of the file, considering endian issues -void readFileSection(uint16_t* p, int len, FILE* f) +static void readFileSection(uint16_t* p, int len, QFile & f) { for (int i=0; i < len; i += 2) { @@ -581,23 +417,11 @@ void readFileSection(uint16_t* p, int len, FILE* f) } } -/* The following two functions are dummies, since we don't call map() */ -void getKey(int /*i*/, uint8_t **/*keys*/) -{ - -} - -void dispKey(int /*i*/) -{ - -} - /* Search the source array between limits iMin and iMax for the pattern (length iPatLen). The pattern can contain wild bytes; if you really want to match for the pattern that is used up by the WILD uint8_t, tough - it will match with everything else as well. */ -static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pattern, int iPatLen, - int *index) +static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pattern, int iPatLen, int *index) { int i, j; const uint8_t *pSrc; /* Pointer to start of considered source */ @@ -633,26 +457,25 @@ static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pa } -void STATE::checkStartup() +/** + * This function checks the startup code for various compilers' way of + * loading DS. If found, it sets DS. This may not be needed in the future if + * pushing and popping of registers is implemented. + * Also sets prog.offMain and prog.segMain if possible + */ +void checkStartup(STATE &state) { - PROG &prog(Project::get()->prog); - /* This function checks the startup code for various compilers' way of - loading DS. If found, it sets DS. This may not be needed in the future if - pushing and popping of registers is implemented. - Also sets prog.offMain and prog.segMain if possible */ + Project & proj(*Project::get()); + PROG & prog(Project::get()->prog); int startOff; /* Offset into the Image of the initial CS:IP */ int i, rel, para, init; - char chModel = 'x'; - char chVendor = 'x'; - char chVersion = 'x'; - char temp[4]; startOff = ((uint32_t)prog.initCS << 4) + prog.initIP; /* Check the Turbo Pascal signatures first, since they involve only the - first 3 bytes, and false positives may be founf with the others later */ + first 3 bytes, and false positives may be found with the others later */ if (locatePattern(prog.image(), startOff, startOff+5, pattBorl4on,sizeof(pattBorl4on), &i)) { /* The first 5 bytes are a far call. Follow that call and @@ -660,49 +483,41 @@ void STATE::checkStartup() rel = LH(&prog.image()[startOff+1]); /* This is abs off of init */ para= LH(&prog.image()[startOff+3]);/* This is abs seg of init */ init = ((uint32_t)para << 4) + rel; - if (locatePattern(prog.image(), init, init+26, pattBorl4Init, - sizeof(pattBorl4Init), &i)) + if (locatePattern(prog.image(), init, init+26, pattBorl4Init, sizeof(pattBorl4Init), &i)) { - setState(rDS, LH(&prog.image()[i+1])); - printf("Borland Pascal v4 detected\n"); - chVendor = 't'; /* Trubo */ - chModel = 'p'; /* Pascal */ - chVersion = '4'; /* Version 4 */ + state.setState(rDS, LH(&prog.image()[i+1])); + printf("Borland Turbo Pascal v4 detected\n"); + proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,4}); prog.offMain = startOff; /* Code starts immediately */ prog.segMain = prog.initCS; /* At the 5 uint8_t jump */ - goto gotVendor; /* Already have vendor */ + return; /* Already have vendor */ } - else if (locatePattern(prog.image(), init, init+26, pattBorl5Init, - sizeof(pattBorl5Init), &i)) + else if (locatePattern(prog.image(), init, init+26, pattBorl5Init, sizeof(pattBorl5Init), &i)) { - setState( rDS, LH(&prog.image()[i+1])); - printf("Borland Pascal v5.0 detected\n"); - chVendor = 't'; /* Trubo */ - chModel = 'p'; /* Pascal */ - chVersion = '5'; /* Version 5 */ + state.setState( rDS, LH(&prog.image()[i+1])); + printf("Borland Turbo Pascal v5.0 detected\n"); + proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,5}); prog.offMain = startOff; /* Code starts immediately */ prog.segMain = prog.initCS; - goto gotVendor; /* Already have vendor */ + return; /* Already have vendor */ } else if (locatePattern(prog.image(), init, init+26, pattBorl7Init, sizeof(pattBorl7Init), &i)) { - setState( rDS, LH(&prog.image()[i+1])); + state.setState( rDS, LH(&prog.image()[i+1])); printf("Borland Pascal v7 detected\n"); - chVendor = 't'; /* Trubo */ - chModel = 'p'; /* Pascal */ - chVersion = '7'; /* Version 7 */ + proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,7}); prog.offMain = startOff; /* Code starts immediately */ prog.segMain = prog.initCS; - goto gotVendor; /* Already have vendor */ + return; /* Already have vendor */ } - } + LoaderMetadata metadata; /* Search for the call to main pattern. This is compiler independant, but decides the model required. Note: must do the far data models (large and compact) before the others, since they are the same pattern @@ -716,7 +531,7 @@ void STATE::checkStartup() /* Save absolute image offset */ prog.offMain = ((uint32_t)para << 4) + rel; prog.segMain = (uint16_t)para; - chModel = 'l'; /* Large model */ + metadata.compiler_memory_model = eLarge; } else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainCompact, sizeof(pattMainCompact), &i)) @@ -724,7 +539,7 @@ void STATE::checkStartup() 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; - chModel = 'c'; /* Compact model */ + metadata.compiler_memory_model = eCompact; } else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainMedium, sizeof(pattMainMedium), &i)) @@ -733,7 +548,7 @@ void STATE::checkStartup() para= LH(&prog.image()[i+OFFMAINMEDIUM+2]);/* This is abs seg of main */ prog.offMain = ((uint32_t)para << 4) + rel; prog.segMain = (uint16_t)para; - chModel = 'm'; /* Medium model */ + metadata.compiler_memory_model = eMedium; } else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainSmall, sizeof(pattMainSmall), &i)) @@ -741,7 +556,7 @@ void STATE::checkStartup() rel = LH_SIGNED(&prog.image()[i+OFFMAINSMALL]); /* This is rel addr of main */ prog.offMain = i+OFFMAINSMALL+2+rel; /* Save absolute image offset */ prog.segMain = prog.initCS; - chModel = 's'; /* Small model */ + metadata.compiler_memory_model = eSmall; } else if (memcmp(&prog.image()[startOff], pattTPasStart, sizeof(pattTPasStart)) == 0) { @@ -749,12 +564,10 @@ void STATE::checkStartup() prog.offMain = rel+startOff+3; /* Save absolute image offset */ prog.offMain += 0x20; /* These first 32 bytes are setting up */ prog.segMain = prog.initCS; - chVendor = 't'; /* Turbo.. */ - chModel = 'p'; /* ...Pascal... (only 1 model) */ - chVersion = '3'; /* 3.0 */ + proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,3}); printf("Turbo Pascal 3.0 detected\n"); printf("Main at %04X\n", prog.offMain); - goto gotVendor; /* Already have vendor */ + return; /* Already have vendor */ } else { @@ -767,28 +580,28 @@ void STATE::checkStartup() printf("Main could not be located!\n"); prog.offMain = -1; } - - printf("Model: %c\n", chModel); - prog.addressingMode = chModel; + //printf("Model: %c\n", chModel); /* Now decide the compiler vendor and version number */ if (memcmp(&prog.image()[startOff], pattMsC5Start, sizeof(pattMsC5Start)) == 0) { /* Yes, this is Microsoft startup code. The DS is sitting right here in the next 2 bytes */ - setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC5Start)])); - chVendor = 'm'; /* Microsoft compiler */ - chVersion = '5'; /* Version 5 */ + state.setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC5Start)])); + metadata.compiler_vendor = eMicrosoft; + metadata.compiler_language = eAnsiCorCPP; + metadata.compiler_version = 5; printf("MSC 5 detected\n"); } /* The C8 startup pattern is different from C5's */ else if (memcmp(&prog.image()[startOff], pattMsC8Start, sizeof(pattMsC8Start)) == 0) { - setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC8Start)])); + state.setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC8Start)])); printf("MSC 8 detected\n"); - chVendor = 'm'; /* Microsoft compiler */ - chVersion = '8'; /* Version 8 */ + metadata.compiler_vendor = eMicrosoft; + metadata.compiler_language = eAnsiCorCPP; + metadata.compiler_version = 8; } /* The C8 .com startup pattern is different again! */ @@ -796,37 +609,35 @@ void STATE::checkStartup() sizeof(pattMsC8ComStart)) == 0) { printf("MSC 8 .com detected\n"); - chVendor = 'm'; /* Microsoft compiler */ - chVersion = '8'; /* Version 8 */ + metadata.compiler_vendor = eMicrosoft; + metadata.compiler_language = eAnsiCorCPP; + metadata.compiler_version = 8; } - - else if (locatePattern(prog.image(), startOff, startOff+0x30, pattBorl2Start, - sizeof(pattBorl2Start), &i)) + else if (locatePattern(prog.image(), startOff, startOff+0x30, pattBorl2Start, sizeof(pattBorl2Start), &i)) { /* Borland startup. DS is at the second uint8_t (offset 1) */ - setState( rDS, LH(&prog.image()[i+1])); + state.setState( rDS, LH(&prog.image()[i+1])); printf("Borland v2 detected\n"); - chVendor = 'b'; /* Borland compiler */ - chVersion = '2'; /* Version 2 */ + metadata.compiler_vendor = eBorland; + metadata.compiler_language = eAnsiCorCPP; + metadata.compiler_version = 2; } - - else if (locatePattern(prog.image(), startOff, startOff+0x30, pattBorl3Start, - sizeof(pattBorl3Start), &i)) + else if (locatePattern(prog.image(), startOff, startOff+0x30, pattBorl3Start, sizeof(pattBorl3Start), &i)) { /* Borland startup. DS is at the second uint8_t (offset 1) */ - setState( rDS, LH(&prog.image()[i+1])); + state.setState( rDS, LH(&prog.image()[i+1])); printf("Borland v3 detected\n"); - chVendor = 'b'; /* Borland compiler */ - chVersion = '3'; /* Version 3 */ + metadata.compiler_vendor = eBorland; + metadata.compiler_language = eAnsiCorCPP; + metadata.compiler_version = 3; } - - else if (locatePattern(prog.image(), startOff, startOff+0x30, pattLogiStart, - sizeof(pattLogiStart), &i)) + else if (locatePattern(prog.image(), startOff, startOff+0x30, pattLogiStart, sizeof(pattLogiStart), &i)) { /* Logitech modula startup. DS is 0, despite appearances */ printf("Logitech modula detected\n"); - chVendor = 'l'; /* Logitech compiler */ - chVersion = '1'; /* Version 1 */ + metadata.compiler_vendor = eLogitech; + metadata.compiler_language = eModula2; + metadata.compiler_version = 1; } /* Other startup idioms would go here */ @@ -834,16 +645,7 @@ void STATE::checkStartup() { printf("Warning - compiler not recognised\n"); } - -gotVendor: - - sSigName = QString("dcc%1%2%3.sig") - .arg(QChar(chVendor)) /* Add vendor */ - .arg(QChar(chVersion)) /* Add version */ - .arg(QChar(chModel)) /* Add model */ - ; - printf("Signature file: %s\n", qPrintable(sSigName)); - + proj.setLoaderMetadata(metadata); } /* DCCLIBS.DAT is a data file sorted on function name containing names and @@ -853,32 +655,31 @@ gotVendor: by dcc, rather than considered as known functions. When a prototype is found (in searchPList()), the parameter info is written to the proc struct. */ -void readProtoFile(void) +bool PatternLocator::readProtoFile(void) { IDcc *dcc = IDcc::get(); QString szProFName = dcc->dataDir("prototypes").absoluteFilePath(DCCLIBS); /* Full name of dclibs.lst */ - FILE *fProto; - int i; + QFile fProto(szProFName); - if ((fProto = fopen(qPrintable(szProFName), "rb")) == nullptr) + if (not fProto.open(QFile::ReadOnly)) { printf("Warning: cannot open library prototype data file %s\n", qPrintable(szProFName)); - return; + return false; } grab(4, fProto); if (strncmp(buf, "dccp", 4) != 0) { printf("%s is not a dcc prototype file\n", qPrintable(szProFName)); - exit(1); + return false; } grab(2, fProto); if (strncmp(buf, "FN", 2) != 0) { printf("FN (Function Name) subsection expected in %s\n", qPrintable(szProFName)); - exit(2); + return false; } numFunc = readFileShort(fProto); /* Num of entries to allocate */ @@ -886,51 +687,48 @@ void readProtoFile(void) /* Allocate exactly correct # entries */ pFunc = new PH_FUNC_STRUCT[numFunc]; - for (i=0; i < numFunc; i++) + for (int i=0; i < numFunc; i++) { - size_t read_size=fread(&pFunc[i], 1, SYMLEN, fProto); + size_t read_size=fProto.read((char *)&pFunc[i], SYMLEN); assert(read_size==SYMLEN); if(read_size!=SYMLEN) break; pFunc[i].typ = (hlType)readFileShort(fProto); pFunc[i].numArg = readFileShort(fProto); pFunc[i].firstArg = readFileShort(fProto); - if(feof(fProto)) + if(fProto.atEnd()) break; - int c = fgetc(fProto); - pFunc[i].bVararg = (c!=0); //fread(&pFunc[i].bVararg, 1, 1, fProto); + char isvararg; + fProto.read(&isvararg,1); + pFunc[i].bVararg = (isvararg!=0); } grab(2, fProto); if (strncmp(buf, "PM", 2) != 0) { printf("PM (Parameter) subsection expected in %s\n", qPrintable(szProFName)); - exit(2); + return false; } numArg = readFileShort(fProto); /* Num of entries to allocate */ /* Allocate exactly correct # entries */ - delete [] pArg; - pArg = new hlType[numArg]; + pArg.clear(); + pArg.reserve(numArg); - for (i=0; i < numArg; i++) + for (int i=0; i < numArg; i++) { // fread(&pArg[i], 1, SYMLEN, fProto); /* No names to read as yet */ - pArg[i] = (hlType) readFileShort(fProto); + pArg.push_back((hlType) readFileShort(fProto)); } - - fclose(fProto); - } -int searchPList(char *name) +int PatternLocator::searchPList(const char *name) { /* Search through the symbol names for the name */ /* Use binary search */ int mx, mn, i, res; - mx = numFunc; mn = 0; @@ -939,29 +737,173 @@ int searchPList(char *name) i = (mn + mx) /2; res = strcmp(pFunc[i].name, name); if (res == 0) - { return i; /* Found! */ - } + + if (res < 0) + mn = i+1; else - { - if (res < 0) - { - mn = i+1; - } - else - { - mx = i-1; - } - } + mx = i-1; } /* Still could be the case that mn == mx == required record */ res = strcmp(pFunc[mn].name, name); if (res == 0) - { return mn; /* Found! */ - } + return NIL; } +/* This procedure is called to initialise the library check code */ +bool PatternLocator::load() +{ + uint16_t w, len; + int i; + IDcc *dcc = IDcc::get(); + QString fpath = dcc->dataDir("sigs").absoluteFilePath(pattern_id); + QFile g_file(fpath); + if (not g_file.open(QFile::ReadOnly)) + { + printf("Warning: cannot open signature file %s\n", qPrintable(fpath)); + return false; + } + + readProtoFile(); + /* Read the parameters */ + grab(4, g_file); + if (memcmp("dccs", buf, 4) != 0) + { + printf("Not a dcc signature file!\n"); + return false; + } + numKeys = readFileShort(g_file); + numVert = readFileShort(g_file); + PatLen = readFileShort(g_file); + SymLen = readFileShort(g_file); + if ((PatLen != PATLEN) or (SymLen != SYMLEN)) + { + printf("Sorry! Compiled for sym and pattern lengths of %d and %d\n", SYMLEN, PATLEN); + return false; + } + + /* Initialise the perfhlib stuff. Also allocates T1, T2, g, etc */ + /* Set the parameters for the hash table */ + g_pattern_hasher.setHashParams( + numKeys, /* The number of symbols */ + PatLen, /* The length of the pattern to be hashed */ + 256, /* The character set of the pattern (0-FF) */ + 0, /* Minimum pattern character value */ + numVert); /* Specifies c, the sparseness of the graph. See Czech, Havas and Majewski for details */ + T1base = g_pattern_hasher.readT1(); + T2base = g_pattern_hasher.readT2(); + g = g_pattern_hasher.readG(); + + /* Read T1 and T2 tables */ + grab(2, g_file); + if (memcmp("T1", buf, 2) != 0) + { + printf("Expected 'T1'\n"); + exit(3); + } + len = (uint16_t) (PatLen * 256 * sizeof(uint16_t)); + w = readFileShort(g_file); + if (w != len) + { + printf("Problem with size of T1: file %d, calc %d\n", w, len); + return false; + } + readFileSection(T1base, len, g_file); + + grab(2, g_file); + if (memcmp("T2", buf, 2) != 0) + { + printf("Expected 'T2'\n"); + return false; + } + w = readFileShort(g_file); + if (w != len) + { + printf("Problem with size of T2: file %d, calc %d\n", w, len); + return false; + } + readFileSection(T2base, len, g_file); + + /* Now read the function g[] */ + grab(2, g_file); + if (memcmp("gg", buf, 2) != 0) + { + printf("Expected 'gg'\n"); + return false; + } + len = (uint16_t)(numVert * sizeof(uint16_t)); + w = readFileShort(g_file); + if (w != len) + { + printf("Problem with size of g[]: file %d, calc %d\n", w, len); + return false; + } + readFileSection(g, len, g_file); + + + /* This is now the hash table */ + /* First allocate space for the table */ + ht = new HT[numKeys]; + if ( nullptr == ht) + { + printf("Could not allocate hash table\n"); + return false; + } + grab(2, g_file); + if (memcmp("ht", buf, 2) != 0) + { + printf("Expected 'ht'\n"); + return false; + } + w = readFileShort(g_file); + if (w != numKeys * (SymLen + PatLen + sizeof(uint16_t))) + { + printf("Problem with size of hash table: file %d, calc %d\n", w, len); + return false; + } + + + for (i=0; i < numKeys; i++) + { + if (g_file.read((char *)&ht[i], SymLen + PatLen) != SymLen + PatLen) + { + printf("Could not read signature\n"); + return false; + } + } + return true; +} +PatternLocator::~PatternLocator() +{ + /* Deallocate all the stuff allocated in SetupLibCheck() */ + delete [] ht; + delete [] pFunc; + delete [] T1base; + delete [] T2base; + delete [] g; +} + +bool LoadPatternLibrary::execute(CommandContext * ctx) +{ + if(nullptr==ctx->m_project) { + ctx->recordFailure(this,"Project was not created yet."); + return false; + } + Project & project( *ctx->m_project) ; + if(!project.m_metadata_available) { + ctx->recordFailure(this,"Loader metadata was not set. FindMain command should be run before LoadPatternLibrary"); + return false; + } + PatternLocator *loc = new PatternLocator(project.getLoaderMetadata().compilerId()); + if(!loc->load()) { + qDebug()<< " No library patterns found for" << project.getLoaderMetadata().compilerId(); + delete loc; + return true; // not an error, just no pattern locator available + } + project.m_pattern_locator = loc; + return true; +} diff --git a/src/chklib.h b/src/chklib.h new file mode 100644 index 0000000..b261893 --- /dev/null +++ b/src/chklib.h @@ -0,0 +1,49 @@ +#ifndef CHKLIB_H +#define CHKLIB_H + +#include "Command.h" +#include "Enums.h" +#include "perfhlib.h" + +#include +#include +#include + +struct Function; + +// This will create a PatternLocator instance load it and pass it to project instance. +struct LoadPatternLibrary : public Command { + LoadPatternLibrary() : Command("Load patterns for the file",eProject) {} + bool execute(CommandContext *ctx) override; +}; + +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 */ +public: + struct HT *ht; //!< The hash table + struct PH_FUNC_STRUCT *pFunc; //!< Points to the array of func names + + + PatternLocator(QString name) : pattern_id(name) {} + ~PatternLocator(); + + bool load(); + int searchPList(const char * name); + + bool LibCheck(Function & pProc); +private: + bool readProtoFile(); + PerfectHash g_pattern_hasher; + int numKeys; /* Number of hash table entries (keys) */ + 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[] */ + +}; +extern void checkStartup(struct STATE &state); +#endif // CHKLIB_H diff --git a/src/dataflow.cpp b/src/dataflow.cpp index c4711a9..2dfaf7b 100644 --- a/src/dataflow.cpp +++ b/src/dataflow.cpp @@ -671,9 +671,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE Expr *_exp; bool res; int size_of_arg=0; - PROG &prog(Project::get()->prog); - - + Project &proj(*Project::get()); /* if (numArgs == 0) return; */ assert(pProc==g_exp_stk.func); @@ -693,7 +691,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE } else { if(numArgsargs.size()) { - if(prog.addressingMode=='l') { + if(proj.getLoaderMetadata().compiler_memory_model==eLarge) { if((callee->args[numArgs].type==TYPE_STR) or (callee->args[numArgs].type==TYPE_PTR)) { RegisterNode *rn = dynamic_cast(g_exp_stk.top()); AstIdent *idn = dynamic_cast(g_exp_stk.top()); diff --git a/src/dcc.cpp b/src/dcc.cpp index 270b599..2172006 100644 --- a/src/dcc.cpp +++ b/src/dcc.cpp @@ -14,26 +14,10 @@ #include #include #include +#include #include - -#ifdef LLVM_EXPERIMENTAL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif #include - +#include "ui/DccMainWindow.h" /* Global variables - extern to other modules */ extern QString asm1_name, asm2_name; /* Assembler output filenames */ @@ -46,79 +30,6 @@ static void displayTotalStats(void); /**************************************************************************** * main ***************************************************************************/ -#ifdef LLVM_EXPERIMENTAL -using namespace llvm; -bool TVisitor(raw_ostream &OS, RecordKeeper &Records) -{ - Record *rec = Records.getDef("ADD8i8"); - if(rec) - { - if(not rec->getTemplateArgs().empty()) - std::cout << "Has template args\n"; - auto classes(rec->getSuperClasses()); - for(auto val : rec->getSuperClasses()) - std::cout << "Super "<getName()<<"\n"; - - // DagInit * in = rec->getValueAsDag(val.getName()); - // in->dump(); - for(const RecordVal &val : rec->getValues()) - { - // val.dump(); - } - rec->dump(); - - } - // rec = Records.getDef("CCR"); - // if(rec) - // rec->dump(); -// for(auto val : Records.getDefs()) -// { -// //std::cout<< "Def "<createTargetMachine(TheTriple.getTriple(),MCPU,Features,opts); -// std::cerr<getInstrInfo()->getName(97)<<"\n"; -// const MCInstrDesc &ds(tm->getInstrInfo()->get(97)); -// const MCOperandInfo *op1=ds.OpInfo; -// uint16_t impl_def = ds.getImplicitDefs()[0]; -// std::cerr<functions().begin(); } + ilFunction GetNextFuncHandle(ilFunction iter) + { + if(iter!=Project::get()->functions().end()) + ++iter; + return iter; + } ilFunction GetCurFuncHandle() { return m_current_func; } void analysis_Once() { + if(m_current_func==Project::get()->functions().end()) + return; + if(m_current_func->nStep==0) { // unscanned function + } } - void load(QString name) + bool load(QString name) { option.filename = name; Project::get()->create(name); + return Project::get()->addLoadCommands(name); } - void prtout_asm(IXmlTarget *, int level) + void prtout_asm(IStructuredTextTarget *, int level) + { +// if (m_Cur_Func->m_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); + } + void prtout_cpp(IStructuredTextTarget *, int level) { } - void prtout_cpp(IXmlTarget *, int level) - { + bool isValidFuncHandle(ilFunction f) { + return f != Project::get()->functions().end(); } size_t getFuncCount() { diff --git a/src/parser.cpp b/src/parser.cpp index 56ae980..9920933 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6,6 +6,7 @@ #include "project.h" #include "CallGraph.h" #include "msvc_fixes.h" +#include "chklib.h" #include #include @@ -673,6 +674,7 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate) { + Project &project(*Project::get()); PROG &prog(Project::get()->prog); ICODE &last_insn(Icode.back()); STATE localState; /* Local copy of the machine state */ @@ -742,7 +744,8 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta { iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()}); Function &x(*iter); - LibCheck(x); + if(project.m_pattern_locator) + project.m_pattern_locator->LibCheck(x); if (x.flg & PROC_ISLIB) { diff --git a/src/project.cpp b/src/project.cpp index 1eebf33..79bec21 100644 --- a/src/project.cpp +++ b/src/project.cpp @@ -15,7 +15,10 @@ STATS stats; /* cfg statistics */ //PROG prog; /* programs fields */ OPTION option; /* Command line options */ Project *Project::s_instance = nullptr; -Project::Project() : callGraph(nullptr) +Project::Project() : + m_selected_loader(nullptr), + callGraph(nullptr), + m_pattern_locator(nullptr) { m_project_command_stream.setMaximumCommandCount(10); connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool))); @@ -29,6 +32,7 @@ void Project::initialize() } void Project::create(const QString &a) { + // TODO: reset all state. initialize(); QFileInfo fi(a); m_fname=a; @@ -152,15 +156,23 @@ bool Project::addLoadCommands(QString fname) void Project::processAllCommands() { - m_command_ctx.proj = this; + m_command_ctx.m_project = this; m_project_command_stream.processAll(&m_command_ctx); - + emit commandListChanged(); +} +void Project::processCommands(int count) { + m_command_ctx.m_project = this; + while(count--) { + if(false==m_project_command_stream.processOne(&m_command_ctx)) { + break; + } + } + emit commandListChanged(); } - void Project::resetCommandsAndErrorState() { m_error_state = false; m_command_ctx.reset(); - m_command_ctx.proj = this; + m_command_ctx.m_project = this; m_project_command_stream.clear(); } diff --git a/src/ui/CommandQueueView.cpp b/src/ui/CommandQueueView.cpp new file mode 100644 index 0000000..1f195a9 --- /dev/null +++ b/src/ui/CommandQueueView.cpp @@ -0,0 +1,39 @@ +#include "CommandQueueView.h" + +#include "project.h" + +#include "ui_CommandQueueView.h" + +CommandQueueView::CommandQueueView(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::CommandQueueView) +{ + ui->setupUi(this); + connect(Project::get(),SIGNAL(commandListChanged()),SLOT(onCommandListChanged())); +} + +CommandQueueView::~CommandQueueView() +{ + delete ui; +} + +void CommandQueueView::changeEvent(QEvent *e) +{ + QDockWidget::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} + +void CommandQueueView::onCommandListChanged() { + Project &project(*Project::get()); + ui->lstQueuedCommands->clear(); + const CommandStream& cs(project.m_project_command_stream); + for(const Command * cmd : cs.m_commands) { + ui->lstQueuedCommands->addItem(cmd->name()); + } +} diff --git a/src/ui/CommandQueueView.h b/src/ui/CommandQueueView.h new file mode 100644 index 0000000..eb7cda8 --- /dev/null +++ b/src/ui/CommandQueueView.h @@ -0,0 +1,28 @@ +#ifndef COMMANDQUEUEVIEW_H +#define COMMANDQUEUEVIEW_H + +#include + +namespace Ui { +class CommandQueueView; +} + +class CommandQueueView : public QDockWidget +{ + Q_OBJECT + +public: + explicit CommandQueueView(QWidget *parent = 0); + ~CommandQueueView(); + +public slots: + void onCommandListChanged(); + +protected: + void changeEvent(QEvent *e); + +private: + Ui::CommandQueueView *ui; +}; + +#endif // COMMANDQUEUEVIEW_H diff --git a/src/ui/CommandQueueView.ui b/src/ui/CommandQueueView.ui new file mode 100644 index 0000000..0a759c8 --- /dev/null +++ b/src/ui/CommandQueueView.ui @@ -0,0 +1,33 @@ + + + CommandQueueView + + + + 0 + 0 + 222 + 446 + + + + Doc&kWidget + + + + + + + + + + Step + + + + + + + + + diff --git a/src/ui/DccMainWindow.cpp b/src/ui/DccMainWindow.cpp new file mode 100644 index 0000000..4900a6c --- /dev/null +++ b/src/ui/DccMainWindow.cpp @@ -0,0 +1,115 @@ +#include "DccMainWindow.h" +#include "ui_DccMainWindow.h" +//#include "ui_exe2c_gui.h" +//#include "exe2c_interface.h" +//#include "exe2c.h" +#include "FunctionViewWidget.h" +#include "FunctionListDockWidget.h" +#include "CommandQueueView.h" +#include "dcc_interface.h" +#include "project.h" + +#include +#include +#include +IDcc* g_EXE2C = NULL; +extern bool exe2c_Init(); + +DccMainWindow::DccMainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::DccMainWindow) +{ + ui->setupUi(this); + ui->statusbar->addPermanentWidget(new QLabel("Test")); + + g_EXE2C = IDcc::get(); + g_EXE2C->BaseInit(); + g_EXE2C->Init(this); + + m_last_display = g_EXE2C->GetFirstFuncHandle(); + 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())); + this->addDockWidget(Qt::RightDockWidgetArea,m_functionlist_widget); + this->addDockWidget(Qt::LeftDockWidgetArea,m_command_queue); + m_asm_view = new FunctionViewWidget(this); + m_asm_view->setWindowTitle(tr("Assembly listing")); + ui->mdiArea->addSubWindow(m_asm_view); + //m_internal_view = new FunctionViewWidget; + //m_internal_view->setWindowTitle(QApplication::tr("Internal listing")); + //ui->mdiArea->addSubWindow(m_internal_view); + m_c_view = new FunctionViewWidget; + m_c_view->setWindowTitle(tr("Decompiled")); + ui->mdiArea->addSubWindow(m_c_view); +} + +DccMainWindow::~DccMainWindow() +{ + delete ui; +} + +void DccMainWindow::changeEvent(QEvent *e) +{ + QMainWindow::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } +} +void DccMainWindow::onOptim() +{ + Project::get()->processCommands(); + g_EXE2C->analysis_Once(); + emit functionListChanged(); + if(m_last_display==g_EXE2C->GetCurFuncHandle()) + { + displayCurrentFunction(); + } +} +void DccMainWindow::onOptim10() +{ + for(int i=0; i<10; i++) + g_EXE2C->analysis_Once(); + emit functionListChanged(); + if(m_last_display==g_EXE2C->GetCurFuncHandle()) + { + displayCurrentFunction(); + } +} +void DccMainWindow::onOpenFile_Action() +{ + QFileDialog dlg; + QString name=dlg.getOpenFileName(0, + tr("Select DOS executable"), + ".", + tr("Executable files (*.exe *.EXE *.com *.COM)")); + if(!g_EXE2C->load(name)) { + QMessageBox::critical(this,tr("Error"),QString(tr("Cannot open file %1")).arg(name)); + } + //bool m_bSucc = m_xTextBuffer.LoadFromFile(lpszPathName); + emit functionListChanged(); +} + +void DccMainWindow::displayCurrentFunction() +{ + if(m_last_display!=g_EXE2C->GetCurFuncHandle()) + m_last_display=g_EXE2C->GetCurFuncHandle(); + g_EXE2C->prtout_asm(m_asm_view); + //g_EXE2C->prtout_itn(m_internal_view); + g_EXE2C->prtout_cpp(m_c_view); +} +void DccMainWindow::prt_log(const char *v) +{ + qDebug()<exit(0); +} diff --git a/src/ui/DccMainWindow.h b/src/ui/DccMainWindow.h new file mode 100644 index 0000000..adbf75c --- /dev/null +++ b/src/ui/DccMainWindow.h @@ -0,0 +1,49 @@ +#ifndef EXE2C_MAINWINDOW_H +#define EXE2C_MAINWINDOW_H + +#include "Procedure.h" +#include "DccFrontend.h" + +#include +#include +#include +#include + +class FunctionViewWidget; +class FunctionListDockWidget; +class CommandQueueView; + +namespace Ui { +class DccMainWindow; +} + +class DccMainWindow : public QMainWindow/*,public I_E2COUT*/ { + Q_OBJECT +public: + explicit DccMainWindow(QWidget *parent = 0); + ~DccMainWindow(); + void prt_log(const char * str); +public slots: + void onOptim(); + void onOptim10(); + void onOpenFile_Action(); + void displayCurrentFunction(); +signals: + void functionListChanged(); +protected: + void changeEvent(QEvent *e); +private slots: + void on_actionExit_triggered(); + +private: + + FunctionViewWidget *m_asm_view; + // FunctionViewWidget *m_internal_view; + FunctionViewWidget *m_c_view; + CommandQueueView *m_command_queue; + FunctionListDockWidget *m_functionlist_widget; + Ui::DccMainWindow *ui; + ilFunction m_last_display; +}; + +#endif // EXE2C_MAINWINDOW_H diff --git a/src/ui/DccMainWindow.ui b/src/ui/DccMainWindow.ui new file mode 100644 index 0000000..52357bc --- /dev/null +++ b/src/ui/DccMainWindow.ui @@ -0,0 +1,372 @@ + + + DccMainWindow + + + + 0 + 0 + 800 + 600 + + + + MainWindow + + + false + + + + + + + + + + + + + + + + + + + 0 + 0 + 800 + 18 + + + + + File + + + + + + + + + + + + Edit + + + + + + + + + + + + + + + + + + + + + View + + + + + + + Window + + + + + + Help + + + + + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + New + + + + + Open + + + + + Save + + + + + Save as + + + + + Exit + + + + + Undo + + + + + Redo + + + + + Cut + + + + + Copy + + + + + Paste + + + + + Delete + + + + + Select All + + + + + Find + + + + + Find Next + + + + + Find Previous + + + + + Replace + + + + + Read Only + + + + + Optim + + + Optimization step + + + + + true + + + Toolbar + + + Toggle toolbar visibility + + + Alt+T + + + + + true + + + Status Bar + + + Toggle status bar visibility + + + + + Cascade windows + + + Will re-arrange the mdi children windows + + + + + Tile windows + + + + + Optim10 + + + + + + + actionStatus_Bar + toggled(bool) + statusbar + setVisible(bool) + + + -1 + -1 + + + 399 + 588 + + + + + actionToolbar + toggled(bool) + toolBar + setVisible(bool) + + + -1 + -1 + + + 399 + 37 + + + + + actionMdiCascadeWindows + triggered() + mdiArea + cascadeSubWindows() + + + -1 + -1 + + + 347 + 314 + + + + + actionMdiTileWindows + triggered() + mdiArea + tileSubWindows() + + + -1 + -1 + + + 347 + 314 + + + + + actionOptim + triggered() + DccMainWindow + onOptim() + + + -1 + -1 + + + 399 + 299 + + + + + actionNew + triggered() + DccMainWindow + onOpenFile_Action() + + + -1 + -1 + + + 399 + 299 + + + + + actionOptim10 + triggered() + DccMainWindow + onOptim10() + + + -1 + -1 + + + 399 + 299 + + + + + + onOptim() + onOpenFile_Action() + displayCurrentFunction(QModelIndex) + functionSelected(QModelIndex) + onOptim10() + + diff --git a/src/ui/FunctionListDockWidget.cpp b/src/ui/FunctionListDockWidget.cpp new file mode 100644 index 0000000..eab9b69 --- /dev/null +++ b/src/ui/FunctionListDockWidget.cpp @@ -0,0 +1,102 @@ +#include "FunctionListDockWidget.h" +#include "ui_FunctionListDockWidget.h" +#include "dcc.h" +#include "dcc_interface.h" +#include "Procedure.h" + +#include +//#include "exe2c.h" +extern IDcc *g_EXE2C; +FunctionListDockWidget::FunctionListDockWidget(QWidget *parent) : + QDockWidget(parent), + ui(new Ui::FunctionListDockWidget) +{ + ui->setupUi(this); + ui->m_func_list_view->setModel(&m_list_model); +} + +FunctionListDockWidget::~FunctionListDockWidget() +{ + delete ui; +} +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()); +} +// signalled by m_func_list_view accepted signal +void FunctionListDockWidget::displayRequest(const QModelIndex &) +{ + // argument ignored since functionSelected must've been called before us + emit displayRequested(); +} +void FunctionListModel::updateFunctionList() +{ + rebuildFunctionList(); +} +void FunctionListModel::rebuildFunctionList() +{ + ilFunction iter = g_EXE2C->GetFirstFuncHandle(); + clear(); + beginInsertRows(QModelIndex(),0,g_EXE2C->getFuncCount()); + + while (g_EXE2C->isValidFuncHandle(iter)) + { + const Function &info(*iter); + //g_EXE2C->GetFuncInfo(iter, &info); + iter = g_EXE2C->GetNextFuncHandle(iter); + + if (info.name.isEmpty()) + continue; + // fixme + add_function(info.name,info.nStep,info.procEntry,info.procEntry+10,info.cbParam); + } + endInsertRows(); +} +QVariant FunctionListModel::data(const QModelIndex &idx,int role) const +{ + int row=idx.row(); + int column=idx.column(); + const function_info &inf=m_list[row]; + if(Qt::DisplayRole==role) + { + 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); + } + default: + return QVariant(); + + } + } + return QVariant(); +} +QVariant FunctionListModel::headerData(int section, Qt::Orientation orientation,int role) const +{ + if(Qt::DisplayRole==role && orientation==Qt::Horizontal) + { + 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(); + + } + } + return QVariant(); +} diff --git a/src/ui/FunctionListDockWidget.h b/src/ui/FunctionListDockWidget.h new file mode 100644 index 0000000..89e0935 --- /dev/null +++ b/src/ui/FunctionListDockWidget.h @@ -0,0 +1,72 @@ +#ifndef FUNCTIONLISTDOCKWIDGET_H +#define FUNCTIONLISTDOCKWIDGET_H + +#include +#include +//#include "exe2c.h" + +class FunctionListModel : public QAbstractTableModel +{ + Q_OBJECT + + struct function_info + { + QString m_name; + int m_decoding_step; + int m_start_off, m_end_off, m_stack_purge; + }; + std::vector m_list; +public: + int rowCount(const QModelIndex &/*idx*/) const {return m_list.size();} + int columnCount(const QModelIndex &/*idx*/) const {return 3;} + QVariant data(const QModelIndex &,int role) const; + void clear() + { + beginResetModel(); + m_list.clear(); + endResetModel(); + } + QVariant headerData(int section, Qt::Orientation orientation,int role) const; +public slots: + void updateFunctionList(); + +protected: + void add_function(const QString &name,int step,int start_off,int end_off,int stack_purge) + { + + function_info info; + info.m_name=name; + info.m_decoding_step=step; + info.m_start_off=start_off; + info.m_end_off=end_off; + info.m_stack_purge=stack_purge; + m_list.push_back(info); + } + void rebuildFunctionList(); + +}; + +namespace Ui { +class FunctionListDockWidget; +} + +class FunctionListDockWidget : public QDockWidget +{ + Q_OBJECT + +public: + explicit FunctionListDockWidget(QWidget *parent = 0); + ~FunctionListDockWidget(); + FunctionListModel *model() {return &m_list_model;} +public slots: + void displayRequest(const QModelIndex &idx); + void functionSelected(const QModelIndex &idx); + +signals: + void displayRequested(); +private: + Ui::FunctionListDockWidget *ui; + FunctionListModel m_list_model; +}; + +#endif // FUNCTIONLISTDOCKWIDGET_H diff --git a/src/ui/FunctionListDockWidget.ui b/src/ui/FunctionListDockWidget.ui new file mode 100644 index 0000000..702f93b --- /dev/null +++ b/src/ui/FunctionListDockWidget.ui @@ -0,0 +1,74 @@ + + + FunctionListDockWidget + + + + 0 + 0 + 400 + 300 + + + + DockWidget + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + + + + + + + m_func_list_view + activated(QModelIndex) + FunctionListDockWidget + displayRequest(QModelIndex) + + + 199 + 161 + + + 199 + 149 + + + + + m_func_list_view + clicked(QModelIndex) + FunctionListDockWidget + functionSelected(QModelIndex) + + + 199 + 161 + + + 199 + 149 + + + + + + displayRequested() + displayRequest(QModelIndex) + functionSelected(QModelIndex) + + diff --git a/src/ui/FunctionViewWidget.cpp b/src/ui/FunctionViewWidget.cpp new file mode 100644 index 0000000..145b6e9 --- /dev/null +++ b/src/ui/FunctionViewWidget.cpp @@ -0,0 +1,81 @@ +#include +#include +#include "FunctionViewWidget.h" +#include "ui_FunctionViewWidget.h" +#include "RenderTags.h" +//#include "XMLTYPE.h" +FunctionViewWidget::FunctionViewWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::FunctionViewWidget) +{ + ui->setupUi(this); + //ui->label->setTextFormat(Qt::RichText); +} + +FunctionViewWidget::~FunctionViewWidget() +{ + delete ui; +} + +void FunctionViewWidget::prtt(const char *s) +{ + collected_text+=s; + //collected_text+="
"; +} +void FunctionViewWidget::prtt(const std::string &s) +{ + collected_text+=s.c_str(); + //collected_text+="
"; +} +void FunctionViewWidget::TAGbegin(TAG_TYPE tag_type, void *p) +{ + QColor col= RenderTag_2_Color(tag_type); + switch(tag_type) + { + case XT_Function: + collected_text+=""; + break; + case XT_FuncName: + case XT_Symbol: + case XT_Keyword: + case XT_DataType: + case XT_Number: + case XT_AsmOffset: + case XT_AsmLabel: + collected_text+=""; + break; + default: + qDebug()<<"Tag type:"<"); + ui->textEdit->setHtml(collected_text); + collected_text.clear(); + break; + } + case XT_FuncName: + case XT_Symbol: + case XT_Keyword: + case XT_DataType: + case XT_Number: + case XT_AsmOffset: + case XT_AsmLabel: + collected_text+=""; + break; + default: + qDebug()<<"Tag end:"< +#include "StructuredTextTarget.h" +#include "RenderTags.h" +//#include "XmlPrt.h" +namespace Ui { +class FunctionViewWidget; +} +class FunctionViewWidget : public QWidget,public IStructuredTextTarget +{ + Q_OBJECT + +public: + explicit FunctionViewWidget(QWidget *parent = 0); + ~FunctionViewWidget(); + void prtt(const char * s); + void prtt(const std::string &s); + void TAGbegin(enum TAG_TYPE tag_type, void * p); + void TAGend(enum TAG_TYPE tag_type); +private: + Ui::FunctionViewWidget *ui; + QString collected_text; +}; + +#endif // FUNCTIONVIEWWIDGET_H diff --git a/src/ui/FunctionViewWidget.ui b/src/ui/FunctionViewWidget.ui new file mode 100644 index 0000000..8b44818 --- /dev/null +++ b/src/ui/FunctionViewWidget.ui @@ -0,0 +1,28 @@ + + + FunctionViewWidget + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + true + + + + + + + + diff --git a/src/ui/RenderTags.cpp b/src/ui/RenderTags.cpp new file mode 100644 index 0000000..9b34402 --- /dev/null +++ b/src/ui/RenderTags.cpp @@ -0,0 +1,23 @@ +#include "RenderTags.h" + +QColor RenderTag_2_Color(TAG_TYPE tag_type) +{ + switch (tag_type) + { + case XT_invalid : return QColor(255,255,255); + case XT_blank : return QColor(255,255,255); + case XT_Symbol : return QColor(57,109,165); + case XT_Function : return QColor(255,255,255); + case XT_Keyword : return QColor(255,255,0); + case XT_Class : return QColor(255,255,0); + case XT_K1 : return QColor(163,70,255); + case XT_Comment : return QColor(0,245,255); + case XT_DataType : return QColor(100,222,192); + case XT_Number : return QColor(0,255,0); + case XT_AsmStack : return QColor(0,70,255); + case XT_AsmOffset: return QColor(70,180,70); + case XT_AsmLabel : return QColor(255,180,70); + case XT_FuncName : return QColor(255,0,255); + } + return QColor(255,255,255); +} diff --git a/src/ui/RenderTags.h b/src/ui/RenderTags.h new file mode 100644 index 0000000..c56afc4 --- /dev/null +++ b/src/ui/RenderTags.h @@ -0,0 +1,28 @@ +#pragma once + +#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_DataType, // + XT_Number, // + XT_AsmStack, //stack values + XT_AsmOffset, //seg:offset + XT_AsmLabel, //label name + XT_FuncName, +}; +struct tColorPair +{ + QColor color1; + QColor color2; +}; +extern tColorPair tbl_color[]; + +QColor RenderTag_2_Color(TAG_TYPE tag_type);