GUI work.

This commit is contained in:
nemerle 2016-04-29 15:51:02 +02:00
parent 2452984864
commit 95acbaa7fa
35 changed files with 1564 additions and 466 deletions

View File

@ -96,6 +96,22 @@ set(dcc_LIB_SOURCES
src/Loaders.cpp src/Loaders.cpp
src/Loaders.h 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 set(dcc_SOURCES
src/dcc.cpp src/dcc.cpp
) )
@ -142,7 +158,7 @@ ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS})
qt5_use_modules(dcc_lib Core) qt5_use_modules(dcc_lib Core)
#cotire(dcc_lib) #cotire(dcc_lib)
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES}) ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_UI_SOURCES})
ADD_DEPENDENCIES(dcc_original dcc_lib) ADD_DEPENDENCIES(dcc_original dcc_lib)
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport) TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s ${REQ_LLVM_LIBRARIES} LLVMSupport)
qt5_use_modules(dcc_original Core Widgets) qt5_use_modules(dcc_original Core Widgets)

View File

@ -1,3 +1,5 @@
#pragma once
#include <stdint.h> #include <stdint.h>
/** Perfect hashing function library. Contains functions to generate perfect /** Perfect hashing function library. Contains functions to generate perfect
hashing functions */ hashing functions */

View File

@ -14,10 +14,8 @@ struct PROG /* Loaded program image parameters */
int cProcs; /* Number of procedures so far */ int cProcs; /* Number of procedures so far */
int offMain; /* The offset of the main() proc */ int offMain; /* The offset of the main() proc */
uint16_t segMain; /* The segment 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 */ int cbImage; /* Length of image in bytes */
uint8_t * Imagez; /* Allocated by loader to hold entire program image */ uint8_t * Imagez; /* Allocated by loader to hold entire program image */
int addressingMode;
public: public:
const uint8_t *image() const {return Imagez;} const uint8_t *image() const {return Imagez;}
void displayLoadInfo(); void displayLoadInfo();

View File

@ -9,7 +9,6 @@ class DccFrontend : public QObject
public: public:
explicit DccFrontend(QObject *parent = 0); explicit DccFrontend(QObject *parent = 0);
bool FrontEnd(); /* frontend.c */ bool FrontEnd(); /* frontend.c */
void initializeMachineState(Project & proj);
signals: signals:

View File

@ -164,6 +164,7 @@ protected:
} }
public: public:
int nStep; // decompilation step number for this function
FunctionType * type; FunctionType * type;
uint32_t procEntry; /* label number */ uint32_t procEntry; /* label number */
QString name; /* Meaningful name for this proc */ QString name; /* Meaningful name for this proc */

View File

@ -88,7 +88,7 @@ void interactDis(Function *, int initIC); /* disassem.c */
bool JmpInst(llIcode opcode); /* idioms.c */ bool JmpInst(llIcode opcode); /* idioms.c */
queue::iterator appendQueue(queue &Q, BB *node); /* reducible.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 */ void CleanupLibCheck(void); /* chklib.c */
bool LibCheck(Function &p); /* chklib.c */ bool LibCheck(Function &p); /* chklib.c */

View File

@ -5,18 +5,20 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include <llvm/ADT/ilist.h> #include <llvm/ADT/ilist.h>
class IXmlTarget; class IStructuredTextTarget;
struct IDcc { struct IDcc {
static IDcc *get(); static IDcc *get();
virtual void BaseInit()=0; virtual void BaseInit()=0;
virtual void Init(QObject *tgt)=0; virtual void Init(QObject *tgt)=0;
virtual lFunction::iterator GetFirstFuncHandle()=0; virtual ilFunction GetFirstFuncHandle()=0;
virtual lFunction::iterator GetCurFuncHandle()=0; virtual ilFunction GetNextFuncHandle(ilFunction iter)=0;
virtual ilFunction GetCurFuncHandle()=0;
virtual bool isValidFuncHandle(ilFunction) = 0;
virtual void analysis_Once()=0; virtual void analysis_Once()=0;
virtual void load(QString name)=0; // load and preprocess -> find entry point virtual bool load(QString name)=0; // load and preprocess -> find entry point
virtual void prtout_asm(IXmlTarget *,int level=0)=0; virtual void prtout_asm(IStructuredTextTarget *,int level=0)=0;
virtual void prtout_cpp(IXmlTarget *,int level=0)=0; virtual void prtout_cpp(IStructuredTextTarget *,int level=0)=0;
virtual size_t getFuncCount()=0; virtual size_t getFuncCount()=0;
virtual const lFunction &validFunctions() const =0; virtual const lFunction &validFunctions() const =0;
virtual void SetCurFunc_by_Name(QString )=0; virtual void SetCurFunc_by_Name(QString )=0;

View File

@ -25,6 +25,62 @@ struct SegOffAddr {
uint16_t seg; uint16_t seg;
uint32_t addr; 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 class Project : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -33,8 +89,10 @@ public:
typedef FunctionListType lFunction; typedef FunctionListType lFunction;
typedef FunctionListType::iterator ilFunction; 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 uint32_t SynthLab; //!< Last snthetic lab idx
SYMTAB symtab; //!< Global symbol table SYMTAB symtab; //!< Global symbol table
FunctionListType pProcList; //!< List of located functions FunctionListType pProcList; //!< List of located functions
@ -44,6 +102,7 @@ public:
PROG prog; /* Loaded program image parameters */ PROG prog; /* Loaded program image parameters */
CommandStream m_project_command_stream; CommandStream m_project_command_stream;
bool m_error_state; bool m_error_state;
struct PatternLocator *m_pattern_locator;
public: public:
// prevent Project instance copying // prevent Project instance copying
Project(const Project&) = delete; Project(const Project&) = delete;
@ -74,6 +133,8 @@ public:
const QString & symbolName(size_t idx); const QString & symbolName(size_t idx);
const SYM & getSymByIdx(size_t idx) const; 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(); static Project * get();
PROG * binary() {return &prog;} PROG * binary() {return &prog;}
SourceMachine *machine(); SourceMachine *machine();
@ -81,14 +142,16 @@ public:
const FunctionListType &functions() const { return pProcList; } const FunctionListType &functions() const { return pProcList; }
FunctionListType &functions() { 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 dumpAllErrors();
void setLoader(DosLoader *ins); void setLoader(DosLoader *ins);
void processCommands(int count=1);
public slots: public slots:
void onCommandStreamFinished(bool state); void onCommandStreamFinished(bool state);
signals: signals:
void newFunctionCreated(Function &); void newFunctionCreated(Function &);
void loaderSelected(); void loaderSelected();
void commandListChanged();
protected: protected:
void initialize(); void initialize();
void writeGlobSymTable(); void writeGlobSymTable();

BIN
sigs/dccb3l.sig Normal file

Binary file not shown.

BIN
sigs/dccb3s.SIG Normal file

Binary file not shown.

View File

@ -8,7 +8,7 @@
bool LoaderSelection::execute(CommandContext * ctx) bool LoaderSelection::execute(CommandContext * ctx)
{ {
Project *proj=ctx->proj; Project *proj=ctx->m_project;
if(nullptr==proj) { if(nullptr==proj) {
ctx->recordFailure(this,"No active project "); ctx->recordFailure(this,"No active project ");
return false; return false;
@ -47,7 +47,7 @@ bool LoaderSelection::execute(CommandContext * ctx)
bool LoaderApplication::execute(CommandContext * ctx) bool LoaderApplication::execute(CommandContext * ctx)
{ {
Project *proj=ctx->proj; Project *proj=ctx->m_project;
if(nullptr==proj) { if(nullptr==proj) {
ctx->recordFailure(this,"No active project "); ctx->recordFailure(this,"No active project ");
@ -96,6 +96,20 @@ void CommandStream::processAll(CommandContext *ctx)
emit streamCompleted(true); 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() void CommandStream::clear()
{ {
qDeleteAll(m_commands); qDeleteAll(m_commands);

View File

@ -21,7 +21,7 @@ public:
m_failures.push_back({cmd,error_message}); m_failures.push_back({cmd,error_message});
} }
Project *proj; Project *m_project;
QVector<QPair<Command *,QString>> m_failures; QVector<QPair<Command *,QString>> m_failures;
void reset(); void reset();
}; };
@ -60,10 +60,12 @@ public:
QVector<Command *> m_commands; QVector<Command *> m_commands;
bool add(Command *c); bool add(Command *c);
void setMaximumCommandCount(int maximum_command_count); void setMaximumCommandCount(int maximum_command_count);
bool processOne(CommandContext *ctx);
void processAll(CommandContext *ctx); void processAll(CommandContext *ctx);
void clear(); void clear();
signals: signals:
void streamCompleted(bool success); void streamCompleted(bool success);
void streamChanged();
}; };
// Effect: loader has been selected and set in current project // Effect: loader has been selected and set in current project
class LoaderSelection : public Command { class LoaderSelection : public Command {

View File

@ -7,6 +7,7 @@
#include "disassem.h" #include "disassem.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "Command.h" #include "Command.h"
#include "chklib.h"
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QDebug> #include <QtCore/QDebug>
@ -157,8 +158,8 @@ public:
bool execute(CommandContext *ctx) override bool execute(CommandContext *ctx) override
{ {
assert(ctx && ctx->proj); assert(ctx && ctx->m_project);
Project &proj(*ctx->proj); Project &proj(*ctx->m_project);
const PROG &prog(proj.prog); const PROG &prog(proj.prog);
proj.m_entry_state.setState(rES, 0); /* PSP segment */ proj.m_entry_state.setState(rES, 0); /* PSP segment */
proj.m_entry_state.setState(rDS, 0); proj.m_entry_state.setState(rDS, 0);
@ -180,7 +181,7 @@ struct CreateFunction : public Command {
m_type(f) m_type(f)
{} {}
bool execute(CommandContext *ctx) override { bool execute(CommandContext *ctx) override {
Project &proj(*ctx->proj); Project &proj(*ctx->m_project);
const PROG &prog(proj.prog); const PROG &prog(proj.prog);
proj.createFunction(m_type,m_name,m_addr); proj.createFunction(m_type,m_name,m_addr);
@ -201,15 +202,15 @@ struct FindMain : public Command {
FindMain() : Command("Locate the main entry point",eProject) { FindMain() : Command("Locate the main entry point",eProject) {
} }
bool execute(CommandContext *ctx) { bool execute(CommandContext *ctx) {
Project &proj(*ctx->proj); Project &proj(*ctx->m_project);
const PROG &prog(proj.prog); 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"); ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
return false; return false;
} }
/* Check for special settings of initial state, based on idioms of the startup code */ /* 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; Command *cmd;
if (prog.offMain != -1) 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); cmd = new CreateFunction("start",SegOffAddr {prog.segMain,proj.m_entry_state.IP},main_type);
} }
proj.addCommand(cmd); proj.addCommand(cmd);
proj.addCommand(new LoadPatternLibrary());
return true; 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 /* Parses the program, builds the call graph, and returns the list of
* procedures found */ * procedures found */
void DccFrontend::parse(Project &proj) 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 */ /* Set initial state */
proj.addCommand(new MachineStateInitialization); proj.addCommand(new MachineStateInitialization);
proj.addCommand(new FindMain); proj.addCommand(new FindMain);

View File

@ -226,7 +226,7 @@ void Function::codeGen (QIODevice &fs)
/* Write procedure/function header */ /* Write procedure/function header */
cCode.init(); 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); ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name);
else /* Procedure */ else /* Procedure */
ostr << "\nvoid "+name+" ("; ostr << "\nvoid "+name+" (";

View File

@ -4,7 +4,9 @@
* address of main() * address of main()
* (C) Mike van Emmerik * (C) Mike van Emmerik
*/ */
#include "chklib.h"
#include "Enums.h"
#include "dcc.h" #include "dcc.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "project.h" #include "project.h"
@ -18,22 +20,21 @@
#include <stdlib.h> #include <stdlib.h>
#include <memory.h> #include <memory.h>
#include <string.h> #include <string.h>
#include "Command.h"
PerfectHash g_pattern_hasher;
#define NIL -1 /* Used like NULL, but 0 is valid */ #define NIL -1 /* Used like NULL, but 0 is valid */
/* Hash table structure */ /* Hash table structure */
typedef struct HT_tag struct HT
{ {
char htSym[SYMLEN]; char htSym[SYMLEN];
uint8_t htPat[PATLEN]; uint8_t htPat[PATLEN];
} HT; };
/* Structure of the prototypes table. Same as the struct in parsehdr.h, /* 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 except here we don't need the "next" index (the elements are already
sorted by function name) */ sorted by function name) */
typedef struct PH_FUNC_STRUCT
struct ph_func_tag
{ {
char name[SYMLEN]; /* Name of function or arg */ char name[SYMLEN]; /* Name of function or arg */
hlType typ; /* Return type */ hlType typ; /* Return type */
@ -41,38 +42,24 @@ struct ph_func_tag
int firstArg; /* Index of first arg in chain */ int firstArg; /* Index of first arg in chain */
// int next; /* Index of next function in chain */ // int next; /* Index of next function in chain */
bool bVararg; /* True if variable arguements */ bool bVararg; /* True if variable arguements */
} PH_FUNC_STRUCT; } ;
#define NUM_PLIST 64 /* Number of entries to increase allocation by */ #define NUM_PLIST 64 /* Number of entries to increase allocation by */
/* statics */ /* statics */
static char buf[100]; /* A general purpose buffer */ 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 */ #define DCCLIBS "dcclibs.dat" /* Name of the prototypes data file */
/* prototypes */ /* prototypes */
void grab(int n, FILE *_file); static bool grab(int n, QFile & _file);
uint16_t readFileShort(FILE *_file); static uint16_t readFileShort(FILE *_file);
void readFileSection(uint16_t* p, int len, FILE *_file); static void readFileSection(uint16_t* p, int len, QFile & _file);
void cleanup(void); static void cleanup(void);
void checkStartup(STATE *state); static void readProtoFile(void);
void readProtoFile(void); static int searchPList(char *name);
int searchPList(char *name); static void checkHeap(char *msg); /* For debugging */
void checkHeap(char *msg); /* For debugging */
void fixWildCards(uint8_t pat[]); /* In fixwild.c */ void fixWildCards(uint8_t pat[]); /* In fixwild.c */
@ -294,148 +281,10 @@ static uint8_t pattMsChkstk[] =
0xE9 /* jmp XXXX */ 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 /* Check this function to see if it is a library function. Return true if
it is, and copy its name to pProc->name it is, and copy its name to pProc->name
*/ */
bool LibCheck(Function & pProc) bool PatternLocator::LibCheck(Function & pProc)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
long fileOffset; long fileOffset;
@ -443,13 +292,6 @@ bool LibCheck(Function & pProc)
int Idx; int Idx;
uint8_t pat[PATLEN]; 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 */ fileOffset = pProc.procEntry; /* Offset into the image */
if (fileOffset == prog.offMain) 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"); qCritical() << "File read failed";
exit(11); return false;
} }
return true;
} }
uint16_t uint16_t readFileShort(QFile &f)
readFileShort(FILE *f)
{ {
uint8_t b1, b2; uint16_t tgt;
if(sizeof(tgt)!=f.read((char *)&tgt,sizeof(tgt))) {
if (fread(&b1, 1, 1, f) != 1) qCritical() << "File read failed";
{ return false;
printf("Could not read short\n");
exit(11);
} }
if (fread(&b2, 1, 1, f) != 1) return tgt;
{
printf("Could not read short\n");
exit(11);
}
return (uint16_t)(b2 << 8) + (uint16_t)b1;
} }
// Read a section of the file, considering endian issues // 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) 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 /* 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 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 for the pattern that is used up by the WILD uint8_t, tough - it will match with
everything else as well. */ everything else as well. */
static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pattern, int iPatLen, static bool locatePattern(const uint8_t *source, int iMin, int iMax, uint8_t *pattern, int iPatLen, int *index)
int *index)
{ {
int i, j; int i, j;
const uint8_t *pSrc; /* Pointer to start of considered source */ 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)
{ {
Project & proj(*Project::get());
PROG & prog(Project::get()->prog); 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 */
int startOff; /* Offset into the Image of the initial CS:IP */ int startOff; /* Offset into the Image of the initial CS:IP */
int i, rel, para, init; 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; startOff = ((uint32_t)prog.initCS << 4) + prog.initIP;
/* Check the Turbo Pascal signatures first, since they involve only the /* 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)) if (locatePattern(prog.image(), startOff, startOff+5, pattBorl4on,sizeof(pattBorl4on), &i))
{ {
/* The first 5 bytes are a far call. Follow that call and /* 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 */ rel = LH(&prog.image()[startOff+1]); /* This is abs off of init */
para= LH(&prog.image()[startOff+3]);/* This is abs seg of init */ para= LH(&prog.image()[startOff+3]);/* This is abs seg of init */
init = ((uint32_t)para << 4) + rel; init = ((uint32_t)para << 4) + rel;
if (locatePattern(prog.image(), init, init+26, pattBorl4Init, if (locatePattern(prog.image(), init, init+26, pattBorl4Init, sizeof(pattBorl4Init), &i))
sizeof(pattBorl4Init), &i))
{ {
setState(rDS, LH(&prog.image()[i+1])); state.setState(rDS, LH(&prog.image()[i+1]));
printf("Borland Pascal v4 detected\n"); printf("Borland Turbo Pascal v4 detected\n");
chVendor = 't'; /* Trubo */ proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,4});
chModel = 'p'; /* Pascal */
chVersion = '4'; /* Version 4 */
prog.offMain = startOff; /* Code starts immediately */ prog.offMain = startOff; /* Code starts immediately */
prog.segMain = prog.initCS; /* At the 5 uint8_t jump */ 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, else if (locatePattern(prog.image(), init, init+26, pattBorl5Init, sizeof(pattBorl5Init), &i))
sizeof(pattBorl5Init), &i))
{ {
setState( rDS, LH(&prog.image()[i+1])); state.setState( rDS, LH(&prog.image()[i+1]));
printf("Borland Pascal v5.0 detected\n"); printf("Borland Turbo Pascal v5.0 detected\n");
chVendor = 't'; /* Trubo */ proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,5});
chModel = 'p'; /* Pascal */
chVersion = '5'; /* Version 5 */
prog.offMain = startOff; /* Code starts immediately */ prog.offMain = startOff; /* Code starts immediately */
prog.segMain = prog.initCS; prog.segMain = prog.initCS;
goto gotVendor; /* Already have vendor */ return; /* Already have vendor */
} }
else if (locatePattern(prog.image(), init, init+26, pattBorl7Init, else if (locatePattern(prog.image(), init, init+26, pattBorl7Init,
sizeof(pattBorl7Init), &i)) sizeof(pattBorl7Init), &i))
{ {
setState( rDS, LH(&prog.image()[i+1])); state.setState( rDS, LH(&prog.image()[i+1]));
printf("Borland Pascal v7 detected\n"); printf("Borland Pascal v7 detected\n");
chVendor = 't'; /* Trubo */ proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,7});
chModel = 'p'; /* Pascal */
chVersion = '7'; /* Version 7 */
prog.offMain = startOff; /* Code starts immediately */ prog.offMain = startOff; /* Code starts immediately */
prog.segMain = prog.initCS; 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, /* Search for the call to main pattern. This is compiler independant,
but decides the model required. Note: must do the far data models but decides the model required. Note: must do the far data models
(large and compact) before the others, since they are the same pattern (large and compact) before the others, since they are the same pattern
@ -716,7 +531,7 @@ void STATE::checkStartup()
/* Save absolute image offset */ /* Save absolute image offset */
prog.offMain = ((uint32_t)para << 4) + rel; prog.offMain = ((uint32_t)para << 4) + rel;
prog.segMain = (uint16_t)para; prog.segMain = (uint16_t)para;
chModel = 'l'; /* Large model */ metadata.compiler_memory_model = eLarge;
} }
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainCompact, else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainCompact,
sizeof(pattMainCompact), &i)) sizeof(pattMainCompact), &i))
@ -724,7 +539,7 @@ void STATE::checkStartup()
rel = LH_SIGNED(&prog.image()[i+OFFMAINCOMPACT]);/* This is the rel addr of main */ 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.offMain = i+OFFMAINCOMPACT+2+rel; /* Save absolute image offset */
prog.segMain = prog.initCS; prog.segMain = prog.initCS;
chModel = 'c'; /* Compact model */ metadata.compiler_memory_model = eCompact;
} }
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainMedium, else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainMedium,
sizeof(pattMainMedium), &i)) sizeof(pattMainMedium), &i))
@ -733,7 +548,7 @@ void STATE::checkStartup()
para= LH(&prog.image()[i+OFFMAINMEDIUM+2]);/* This is abs seg of main */ para= LH(&prog.image()[i+OFFMAINMEDIUM+2]);/* This is abs seg of main */
prog.offMain = ((uint32_t)para << 4) + rel; prog.offMain = ((uint32_t)para << 4) + rel;
prog.segMain = (uint16_t)para; prog.segMain = (uint16_t)para;
chModel = 'm'; /* Medium model */ metadata.compiler_memory_model = eMedium;
} }
else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainSmall, else if (locatePattern(prog.image(), startOff, startOff+0x180, pattMainSmall,
sizeof(pattMainSmall), &i)) sizeof(pattMainSmall), &i))
@ -741,7 +556,7 @@ void STATE::checkStartup()
rel = LH_SIGNED(&prog.image()[i+OFFMAINSMALL]); /* This is rel addr of main */ rel = LH_SIGNED(&prog.image()[i+OFFMAINSMALL]); /* This is rel addr of main */
prog.offMain = i+OFFMAINSMALL+2+rel; /* Save absolute image offset */ prog.offMain = i+OFFMAINSMALL+2+rel; /* Save absolute image offset */
prog.segMain = prog.initCS; prog.segMain = prog.initCS;
chModel = 's'; /* Small model */ metadata.compiler_memory_model = eSmall;
} }
else if (memcmp(&prog.image()[startOff], pattTPasStart, sizeof(pattTPasStart)) == 0) 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 = rel+startOff+3; /* Save absolute image offset */
prog.offMain += 0x20; /* These first 32 bytes are setting up */ prog.offMain += 0x20; /* These first 32 bytes are setting up */
prog.segMain = prog.initCS; prog.segMain = prog.initCS;
chVendor = 't'; /* Turbo.. */ proj.setLoaderMetadata({eBorland,ePascal,eUnknownMemoryModel,3});
chModel = 'p'; /* ...Pascal... (only 1 model) */
chVersion = '3'; /* 3.0 */
printf("Turbo Pascal 3.0 detected\n"); printf("Turbo Pascal 3.0 detected\n");
printf("Main at %04X\n", prog.offMain); printf("Main at %04X\n", prog.offMain);
goto gotVendor; /* Already have vendor */ return; /* Already have vendor */
} }
else else
{ {
@ -767,28 +580,28 @@ void STATE::checkStartup()
printf("Main could not be located!\n"); printf("Main could not be located!\n");
prog.offMain = -1; prog.offMain = -1;
} }
//printf("Model: %c\n", chModel);
printf("Model: %c\n", chModel);
prog.addressingMode = chModel;
/* Now decide the compiler vendor and version number */ /* Now decide the compiler vendor and version number */
if (memcmp(&prog.image()[startOff], pattMsC5Start, sizeof(pattMsC5Start)) == 0) if (memcmp(&prog.image()[startOff], pattMsC5Start, sizeof(pattMsC5Start)) == 0)
{ {
/* Yes, this is Microsoft startup code. The DS is sitting right here /* Yes, this is Microsoft startup code. The DS is sitting right here
in the next 2 bytes */ in the next 2 bytes */
setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC5Start)])); state.setState( rDS, LH(&prog.image()[startOff+sizeof(pattMsC5Start)]));
chVendor = 'm'; /* Microsoft compiler */ metadata.compiler_vendor = eMicrosoft;
chVersion = '5'; /* Version 5 */ metadata.compiler_language = eAnsiCorCPP;
metadata.compiler_version = 5;
printf("MSC 5 detected\n"); printf("MSC 5 detected\n");
} }
/* The C8 startup pattern is different from C5's */ /* The C8 startup pattern is different from C5's */
else if (memcmp(&prog.image()[startOff], pattMsC8Start, sizeof(pattMsC8Start)) == 0) 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"); printf("MSC 8 detected\n");
chVendor = 'm'; /* Microsoft compiler */ metadata.compiler_vendor = eMicrosoft;
chVersion = '8'; /* Version 8 */ metadata.compiler_language = eAnsiCorCPP;
metadata.compiler_version = 8;
} }
/* The C8 .com startup pattern is different again! */ /* The C8 .com startup pattern is different again! */
@ -796,37 +609,35 @@ void STATE::checkStartup()
sizeof(pattMsC8ComStart)) == 0) sizeof(pattMsC8ComStart)) == 0)
{ {
printf("MSC 8 .com detected\n"); printf("MSC 8 .com detected\n");
chVendor = 'm'; /* Microsoft compiler */ metadata.compiler_vendor = eMicrosoft;
chVersion = '8'; /* Version 8 */ 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) */ /* 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"); printf("Borland v2 detected\n");
chVendor = 'b'; /* Borland compiler */ metadata.compiler_vendor = eBorland;
chVersion = '2'; /* Version 2 */ 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) */ /* 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"); printf("Borland v3 detected\n");
chVendor = 'b'; /* Borland compiler */ metadata.compiler_vendor = eBorland;
chVersion = '3'; /* Version 3 */ 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 */ /* Logitech modula startup. DS is 0, despite appearances */
printf("Logitech modula detected\n"); printf("Logitech modula detected\n");
chVendor = 'l'; /* Logitech compiler */ metadata.compiler_vendor = eLogitech;
chVersion = '1'; /* Version 1 */ metadata.compiler_language = eModula2;
metadata.compiler_version = 1;
} }
/* Other startup idioms would go here */ /* Other startup idioms would go here */
@ -834,16 +645,7 @@ void STATE::checkStartup()
{ {
printf("Warning - compiler not recognised\n"); printf("Warning - compiler not recognised\n");
} }
proj.setLoaderMetadata(metadata);
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));
} }
/* DCCLIBS.DAT is a data file sorted on function name containing names and /* 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 by dcc, rather than considered as known functions. When a prototype is
found (in searchPList()), the parameter info is written to the proc struct. found (in searchPList()), the parameter info is written to the proc struct.
*/ */
void readProtoFile(void) bool PatternLocator::readProtoFile(void)
{ {
IDcc *dcc = IDcc::get(); IDcc *dcc = IDcc::get();
QString szProFName = dcc->dataDir("prototypes").absoluteFilePath(DCCLIBS); /* Full name of dclibs.lst */ QString szProFName = dcc->dataDir("prototypes").absoluteFilePath(DCCLIBS); /* Full name of dclibs.lst */
FILE *fProto; QFile fProto(szProFName);
int i;
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)); printf("Warning: cannot open library prototype data file %s\n", qPrintable(szProFName));
return; return false;
} }
grab(4, fProto); grab(4, fProto);
if (strncmp(buf, "dccp", 4) != 0) if (strncmp(buf, "dccp", 4) != 0)
{ {
printf("%s is not a dcc prototype file\n", qPrintable(szProFName)); printf("%s is not a dcc prototype file\n", qPrintable(szProFName));
exit(1); return false;
} }
grab(2, fProto); grab(2, fProto);
if (strncmp(buf, "FN", 2) != 0) if (strncmp(buf, "FN", 2) != 0)
{ {
printf("FN (Function Name) subsection expected in %s\n", qPrintable(szProFName)); printf("FN (Function Name) subsection expected in %s\n", qPrintable(szProFName));
exit(2); return false;
} }
numFunc = readFileShort(fProto); /* Num of entries to allocate */ numFunc = readFileShort(fProto); /* Num of entries to allocate */
@ -886,51 +687,48 @@ void readProtoFile(void)
/* Allocate exactly correct # entries */ /* Allocate exactly correct # entries */
pFunc = new PH_FUNC_STRUCT[numFunc]; 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); assert(read_size==SYMLEN);
if(read_size!=SYMLEN) if(read_size!=SYMLEN)
break; break;
pFunc[i].typ = (hlType)readFileShort(fProto); pFunc[i].typ = (hlType)readFileShort(fProto);
pFunc[i].numArg = readFileShort(fProto); pFunc[i].numArg = readFileShort(fProto);
pFunc[i].firstArg = readFileShort(fProto); pFunc[i].firstArg = readFileShort(fProto);
if(feof(fProto)) if(fProto.atEnd())
break; break;
int c = fgetc(fProto); char isvararg;
pFunc[i].bVararg = (c!=0); //fread(&pFunc[i].bVararg, 1, 1, fProto); fProto.read(&isvararg,1);
pFunc[i].bVararg = (isvararg!=0);
} }
grab(2, fProto); grab(2, fProto);
if (strncmp(buf, "PM", 2) != 0) if (strncmp(buf, "PM", 2) != 0)
{ {
printf("PM (Parameter) subsection expected in %s\n", qPrintable(szProFName)); printf("PM (Parameter) subsection expected in %s\n", qPrintable(szProFName));
exit(2); return false;
} }
numArg = readFileShort(fProto); /* Num of entries to allocate */ numArg = readFileShort(fProto); /* Num of entries to allocate */
/* Allocate exactly correct # entries */ /* Allocate exactly correct # entries */
delete [] pArg; pArg.clear();
pArg = new hlType[numArg]; 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 */ // 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 PatternLocator::searchPList(const char *name)
}
int searchPList(char *name)
{ {
/* Search through the symbol names for the name */ /* Search through the symbol names for the name */
/* Use binary search */ /* Use binary search */
int mx, mn, i, res; int mx, mn, i, res;
mx = numFunc; mx = numFunc;
mn = 0; mn = 0;
@ -939,29 +737,173 @@ int searchPList(char *name)
i = (mn + mx) /2; i = (mn + mx) /2;
res = strcmp(pFunc[i].name, name); res = strcmp(pFunc[i].name, name);
if (res == 0) if (res == 0)
{
return i; /* Found! */ return i; /* Found! */
}
else
{
if (res < 0) if (res < 0)
{
mn = i+1; mn = i+1;
}
else else
{
mx = i-1; mx = i-1;
} }
}
}
/* Still could be the case that mn == mx == required record */ /* Still could be the case that mn == mx == required record */
res = strcmp(pFunc[mn].name, name); res = strcmp(pFunc[mn].name, name);
if (res == 0) if (res == 0)
{
return mn; /* Found! */ return mn; /* Found! */
}
return NIL; 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;
}

49
src/chklib.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef CHKLIB_H
#define CHKLIB_H
#include "Command.h"
#include "Enums.h"
#include "perfhlib.h"
#include <QtCore/QFile>
#include <QtCore/QString>
#include <vector>
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<hlType> pArg; /* Points to the array of param types */
QString pattern_id;
int numFunc; /* Number of func names actually stored */
int numArg; /* Number of param names actually stored */
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

View File

@ -671,9 +671,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
Expr *_exp; Expr *_exp;
bool res; bool res;
int size_of_arg=0; int size_of_arg=0;
PROG &prog(Project::get()->prog); Project &proj(*Project::get());
/* if (numArgs == 0) /* if (numArgs == 0)
return; */ return; */
assert(pProc==g_exp_stk.func); assert(pProc==g_exp_stk.func);
@ -693,7 +691,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
} }
else { else {
if(numArgs<callee->args.size()) { if(numArgs<callee->args.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)) { if((callee->args[numArgs].type==TYPE_STR) or (callee->args[numArgs].type==TYPE_PTR)) {
RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top()); RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top());
AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top()); AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top());

View File

@ -14,26 +14,10 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#ifdef LLVM_EXPERIMENTAL
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/TargetRegistry.h>
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Signals.h>
#include <llvm/Support/Host.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetInstrInfo.h>
#include <llvm/MC/MCAsmInfo.h>
#include <llvm/CodeGen/MachineInstrBuilder.h>
#include <llvm/TableGen/Main.h>
#include <llvm/TableGen/TableGenBackend.h>
#include <llvm/TableGen/Record.h>
#endif
#include <QtCore/QFile> #include <QtCore/QFile>
#include "ui/DccMainWindow.h"
/* Global variables - extern to other modules */ /* Global variables - extern to other modules */
extern QString asm1_name, asm2_name; /* Assembler output filenames */ extern QString asm1_name, asm2_name; /* Assembler output filenames */
@ -46,79 +30,6 @@ static void displayTotalStats(void);
/**************************************************************************** /****************************************************************************
* main * 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 "<<val->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 "<<val.first<<"\n";
// }
return false;
}
int testTblGen(int argc, char **argv)
{
// using namespace llvm;
// sys::PrintStackTraceOnErrorSignal();
// PrettyStackTraceProgram(argc,argv);
// cl::ParseCommandLineOptions(argc,argv);
// return llvm::TableGenMain(argv[0],TVisitor);
// InitializeNativeTarget();
// Triple TheTriple;
// std::string def = sys::getDefaultTargetTriple();
// std::string MCPU="i386";
// std::string MARCH="x86";
// InitializeAllTargetInfos();
// InitializeAllTargetMCs();
// InitializeAllAsmPrinters();
// InitializeAllAsmParsers();
// InitializeAllDisassemblers();
// std::string TargetTriple("i386-pc-linux-gnu");
// TheTriple = Triple(Triple::normalize(TargetTriple));
// MCOperand op=llvm::MCOperand::CreateImm(11);
// MCAsmInfo info;
// raw_os_ostream wrap(std::cerr);
// op.print(wrap,&info);
// wrap.flush();
// std::cerr<<"\n";
// std::string lookuperr;
// TargetRegistry::printRegisteredTargetsForVersion();
// const Target *t = TargetRegistry::lookupTarget(MARCH,TheTriple,lookuperr);
// TargetOptions opts;
// std::string Features;
// opts.PrintMachineCode=1;
// TargetMachine *tm = t->createTargetMachine(TheTriple.getTriple(),MCPU,Features,opts);
// std::cerr<<tm->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<<lookuperr<<"\n";
// exit(0);
}
#endif
void setupOptions(QCoreApplication &app) { void setupOptions(QCoreApplication &app) {
//[-a1a2cmsi] //[-a1a2cmsi]
QCommandLineParser parser; QCommandLineParser parser;
@ -180,9 +91,17 @@ void setupOptions(QCoreApplication &app) {
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
QCoreApplication::setApplicationName("dcc");
QCoreApplication::setApplicationVersion("0.1");
if(argc==1) {
QApplication app(argc,argv);
DccMainWindow win;
win.show();
return app.exec();
}
QCoreApplication app(argc,argv); QCoreApplication app(argc,argv);
QCoreApplication::setApplicationVersion("0.1");
setupOptions(app); setupOptions(app);
Project *proj = Project::get(); Project *proj = Project::get();

View File

@ -16,23 +16,43 @@ public:
{ {
return Project::get()->functions().begin(); return Project::get()->functions().begin();
} }
ilFunction GetNextFuncHandle(ilFunction iter)
{
if(iter!=Project::get()->functions().end())
++iter;
return iter;
}
ilFunction GetCurFuncHandle() ilFunction GetCurFuncHandle()
{ {
return m_current_func; return m_current_func;
} }
void analysis_Once() 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; option.filename = name;
Project::get()->create(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() size_t getFuncCount()
{ {

View File

@ -6,6 +6,7 @@
#include "project.h" #include "project.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "chklib.h"
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
@ -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) bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
{ {
Project &project(*Project::get());
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
ICODE &last_insn(Icode.back()); ICODE &last_insn(Icode.back());
STATE localState; /* Local copy of the machine state */ 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()}); iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()});
Function &x(*iter); Function &x(*iter);
LibCheck(x); if(project.m_pattern_locator)
project.m_pattern_locator->LibCheck(x);
if (x.flg & PROC_ISLIB) if (x.flg & PROC_ISLIB)
{ {

View File

@ -15,7 +15,10 @@ STATS stats; /* cfg statistics */
//PROG prog; /* programs fields */ //PROG prog; /* programs fields */
OPTION option; /* Command line options */ OPTION option; /* Command line options */
Project *Project::s_instance = nullptr; 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); m_project_command_stream.setMaximumCommandCount(10);
connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool))); connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool)));
@ -29,6 +32,7 @@ void Project::initialize()
} }
void Project::create(const QString &a) void Project::create(const QString &a)
{ {
// TODO: reset all state.
initialize(); initialize();
QFileInfo fi(a); QFileInfo fi(a);
m_fname=a; m_fname=a;
@ -152,15 +156,23 @@ bool Project::addLoadCommands(QString fname)
void Project::processAllCommands() void Project::processAllCommands()
{ {
m_command_ctx.proj = this; m_command_ctx.m_project = this;
m_project_command_stream.processAll(&m_command_ctx); 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() void Project::resetCommandsAndErrorState()
{ {
m_error_state = false; m_error_state = false;
m_command_ctx.reset(); m_command_ctx.reset();
m_command_ctx.proj = this; m_command_ctx.m_project = this;
m_project_command_stream.clear(); m_project_command_stream.clear();
} }

View File

@ -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());
}
}

28
src/ui/CommandQueueView.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef COMMANDQUEUEVIEW_H
#define COMMANDQUEUEVIEW_H
#include <QtWidgets/QDockWidget>
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

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CommandQueueView</class>
<widget class="QDockWidget" name="CommandQueueView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>222</width>
<height>446</height>
</rect>
</property>
<property name="windowTitle">
<string>Doc&amp;kWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="lstQueuedCommands"/>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Step</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

115
src/ui/DccMainWindow.cpp Normal file
View File

@ -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 <QtWidgets>
#include <QLabel>
#include <QFileDialog>
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()<<v;
}
void DccMainWindow::on_actionExit_triggered()
{
qApp->exit(0);
}

49
src/ui/DccMainWindow.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef EXE2C_MAINWINDOW_H
#define EXE2C_MAINWINDOW_H
#include "Procedure.h"
#include "DccFrontend.h"
#include <QMainWindow>
#include <QAbstractTableModel>
#include <QVariant>
#include <vector>
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

372
src/ui/DccMainWindow.ui Normal file
View File

@ -0,0 +1,372 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DccMainWindow</class>
<widget class="QMainWindow" name="DccMainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="documentMode">
<bool>false</bool>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QMdiArea" name="mdiArea"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>18</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionNew"/>
<addaction name="actionOpen"/>
<addaction name="actionSave"/>
<addaction name="actionSave_as"/>
<addaction name="separator"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuUndo">
<property name="title">
<string>Edit</string>
</property>
<addaction name="actionUndo"/>
<addaction name="actionRedo"/>
<addaction name="separator"/>
<addaction name="actionCut"/>
<addaction name="actionCopy"/>
<addaction name="actionPaste"/>
<addaction name="actionDelete"/>
<addaction name="actionSelect_All"/>
<addaction name="separator"/>
<addaction name="actionFind"/>
<addaction name="actionFind_next"/>
<addaction name="actionFind_Previous"/>
<addaction name="actionReplace"/>
<addaction name="separator"/>
<addaction name="actionRead_Only"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>View</string>
</property>
<addaction name="actionToolbar"/>
<addaction name="actionStatus_Bar"/>
</widget>
<widget class="QMenu" name="menuWindow">
<property name="title">
<string>Window</string>
</property>
<addaction name="actionMdiCascadeWindows"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuUndo"/>
<addaction name="menuView"/>
<addaction name="menuWindow"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionOptim"/>
<addaction name="actionOptim10"/>
</widget>
<action name="actionNew">
<property name="text">
<string>New</string>
</property>
</action>
<action name="actionOpen">
<property name="text">
<string>Open</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
</action>
<action name="actionSave_as">
<property name="text">
<string>Save as</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="actionUndo">
<property name="text">
<string>Undo</string>
</property>
</action>
<action name="actionRedo">
<property name="text">
<string>Redo</string>
</property>
</action>
<action name="actionCut">
<property name="text">
<string>Cut</string>
</property>
</action>
<action name="actionCopy">
<property name="text">
<string>Copy</string>
</property>
</action>
<action name="actionPaste">
<property name="text">
<string>Paste</string>
</property>
</action>
<action name="actionDelete">
<property name="text">
<string>Delete</string>
</property>
</action>
<action name="actionSelect_All">
<property name="text">
<string>Select All</string>
</property>
</action>
<action name="actionFind">
<property name="text">
<string>Find</string>
</property>
</action>
<action name="actionFind_next">
<property name="text">
<string>Find Next</string>
</property>
</action>
<action name="actionFind_Previous">
<property name="text">
<string>Find Previous</string>
</property>
</action>
<action name="actionReplace">
<property name="text">
<string>Replace</string>
</property>
</action>
<action name="actionRead_Only">
<property name="text">
<string>Read Only</string>
</property>
</action>
<action name="actionOptim">
<property name="text">
<string>Optim</string>
</property>
<property name="toolTip">
<string>Optimization step</string>
</property>
</action>
<action name="actionToolbar">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Toolbar</string>
</property>
<property name="toolTip">
<string>Toggle toolbar visibility</string>
</property>
<property name="shortcut">
<string>Alt+T</string>
</property>
</action>
<action name="actionStatus_Bar">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Status Bar</string>
</property>
<property name="toolTip">
<string>Toggle status bar visibility</string>
</property>
</action>
<action name="actionMdiCascadeWindows">
<property name="text">
<string>Cascade windows</string>
</property>
<property name="toolTip">
<string>Will re-arrange the mdi children windows</string>
</property>
</action>
<action name="actionMdiTileWindows">
<property name="text">
<string>Tile windows</string>
</property>
</action>
<action name="actionOptim10">
<property name="text">
<string>Optim10</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>actionStatus_Bar</sender>
<signal>toggled(bool)</signal>
<receiver>statusbar</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>588</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionToolbar</sender>
<signal>toggled(bool)</signal>
<receiver>toolBar</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>37</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionMdiCascadeWindows</sender>
<signal>triggered()</signal>
<receiver>mdiArea</receiver>
<slot>cascadeSubWindows()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>347</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionMdiTileWindows</sender>
<signal>triggered()</signal>
<receiver>mdiArea</receiver>
<slot>tileSubWindows()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>347</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionOptim</sender>
<signal>triggered()</signal>
<receiver>DccMainWindow</receiver>
<slot>onOptim()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionNew</sender>
<signal>triggered()</signal>
<receiver>DccMainWindow</receiver>
<slot>onOpenFile_Action()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
<connection>
<sender>actionOptim10</sender>
<signal>triggered()</signal>
<receiver>DccMainWindow</receiver>
<slot>onOptim10()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>299</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>onOptim()</slot>
<slot>onOpenFile_Action()</slot>
<slot>displayCurrentFunction(QModelIndex)</slot>
<slot>functionSelected(QModelIndex)</slot>
<slot>onOptim10()</slot>
</slots>
</ui>

View File

@ -0,0 +1,102 @@
#include "FunctionListDockWidget.h"
#include "ui_FunctionListDockWidget.h"
#include "dcc.h"
#include "dcc_interface.h"
#include "Procedure.h"
#include <QtCore>
//#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 "<<v;
g_EXE2C->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();
}

View File

@ -0,0 +1,72 @@
#ifndef FUNCTIONLISTDOCKWIDGET_H
#define FUNCTIONLISTDOCKWIDGET_H
#include <QAbstractTableModel>
#include <QDockWidget>
//#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<function_info> 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

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FunctionListDockWidget</class>
<widget class="QDockWidget" name="FunctionListDockWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>DockWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="m_func_list_view">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>m_func_list_view</sender>
<signal>activated(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>displayRequest(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>161</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>149</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_func_list_view</sender>
<signal>clicked(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>functionSelected(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>199</x>
<y>161</y>
</hint>
<hint type="destinationlabel">
<x>199</x>
<y>149</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<signal>displayRequested()</signal>
<slot>displayRequest(QModelIndex)</slot>
<slot>functionSelected(QModelIndex)</slot>
</slots>
</ui>

View File

@ -0,0 +1,81 @@
#include <QDebug>
#include <QtCore>
#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+="<br>";
}
void FunctionViewWidget::prtt(const std::string &s)
{
collected_text+=s.c_str();
//collected_text+="<br>";
}
void FunctionViewWidget::TAGbegin(TAG_TYPE tag_type, void *p)
{
QColor col= RenderTag_2_Color(tag_type);
switch(tag_type)
{
case XT_Function:
collected_text+="<body style='color: #FFFFFF; background-color: #000000'>";
break;
case XT_FuncName:
case XT_Symbol:
case XT_Keyword:
case XT_DataType:
case XT_Number:
case XT_AsmOffset:
case XT_AsmLabel:
collected_text+="<font color='"+col.name()+"'>";
break;
default:
qDebug()<<"Tag type:"<<tag_type;
}
}
void FunctionViewWidget::TAGend(TAG_TYPE tag_type)
{
switch(tag_type)
{
case XT_Function:
{
collected_text+="</body>";
// TODO: What about attributes with spaces?
collected_text.replace(" ", "&nbsp;&nbsp;");
QFile res("result.html");
res.open(QFile::WriteOnly);
res.write(collected_text.toUtf8());
res.close();
collected_text.replace(QChar('\n'),"<br>");
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+="</font>";
break;
default:
qDebug()<<"Tag end:"<<tag_type;
}
}

View File

@ -0,0 +1,27 @@
#ifndef FUNCTIONVIEWWIDGET_H
#define FUNCTIONVIEWWIDGET_H
#include <QWidget>
#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

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FunctionViewWidget</class>
<widget class="QWidget" name="FunctionViewWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

23
src/ui/RenderTags.cpp Normal file
View File

@ -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);
}

28
src/ui/RenderTags.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <qcolor.h>
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);