Compare commits

...

38 Commits

Author SHA1 Message Date
nemerle
3905c4e281 Re-activate unit testing and starting work on proper memory segmentation support
Use Qt testing framework.

Reorganize source file references in CMakeLists.txt

Add simplistic Address header and type ( typedef for now )
2016-05-20 15:44:37 +02:00
nemerle
171abc0415 Remove unused variables. 2016-05-20 10:24:28 +02:00
nemerle
126e206b08 Constify parsehdr error/warning reporting function arguments. 2016-05-20 10:24:01 +02:00
nemerle
7f1a4e26bd Fix struct/class confusion for Function class. 2016-05-20 10:23:00 +02:00
nemerle
8875371cee Merge remote-tracking branch 'origin' into experimental_command_streams 2016-05-20 10:20:51 +02:00
nemerle
3af6f8f5c3 Merge branch 'qt5' into experimental_command_streams 2016-05-20 10:16:59 +02:00
nemerle
d5985b4b97 Add parsehdr to the build
As requested in #22
2016-05-19 19:50:47 +02:00
nemerle
5f68987001 Merge branch 'qt5' into experimental_command_streams 2016-05-19 15:57:52 +02:00
nemerle
14ceb301c1 WIP - do not use. 2016-05-19 10:18:17 +02:00
nemerle
bc654cbf76 Fix: bad loader instancfe created for COM files 2016-05-10 14:48:46 +02:00
nemerle
9c6dfd676e Move JMP processing from Function class
Add MarkAsSwitchCase command
2016-05-10 14:02:26 +02:00
nemerle
ae27258e3c Move XCHG and DIV rewriters from Function class
Preliminary work for #19
2016-05-10 13:07:05 +02:00
nemerle
41e9faec0e Start moving parser functionality from Function class.
Add state switching operation to Function interface
2016-05-10 12:36:31 +02:00
nemerle
6f7bfbddf8 Fix: initialize initial state for start proc if no main was found 2016-05-10 10:46:23 +02:00
nemerle
db39014e1b A few more skeleton things for planner 2016-05-09 16:05:15 +02:00
nemerle
3376818a17 fix previous commit
Support simple character deletion operations in StructuredTextTarget.h
to support opcode suffix modification.
2016-05-09 11:53:03 +02:00
nemerle
72ca6bbb70 disassembler: more instructions output into structuredtext 2016-05-09 11:35:30 +02:00
nemerle
888de8d35e More tabs replaced with spaces 2016-05-06 15:57:15 +02:00
nemerle
59c199837c Replace some tabs with spaces 2016-05-06 15:04:45 +02:00
nemerle
152625d67d Extend responsibilities of FunctionViewWidget
Reduced IDcc interface functionality.

Fix a few bugs/warnings discovered by coverity.

Emit functionUpdate signal from project when function object internal
fields change.
2016-05-06 14:40:33 +02:00
nemerle
292e4041e1 Initialize some class attributes. 2016-05-06 00:26:52 +02:00
nemerle
36d95946b3 Show JMP targets 2016-05-05 23:55:39 +02:00
nemerle
4cc3b41e64 Use QTextDocument instead of html to build text display
Continued work on rendering disassembly level text.
2016-05-05 16:06:06 +02:00
nemerle
6ade935e37 Function's command queue implemented, flow control scanning starts to
work.
2016-05-05 14:28:25 +02:00
nemerle
c8fd3a01df Add AutomatedPlanner skeleton class 2016-05-04 14:22:28 +02:00
nemerle
29353111ac A few missing returns 2016-05-04 09:54:38 +02:00
nemerle
4dc321650f Add skeletal functions for ICODE -> StructuredText 2016-05-04 00:57:59 +02:00
nemerle
0521206de5 WIP: More GUI work, use shared_ptr to store Function references. 2016-05-03 13:59:14 +02:00
nemerle
60a4fefe95 Fix command queue stepping.
Also add instanceDescription to Command class to allow for more verbose command information reporting
2016-05-01 18:45:22 +02:00
nemerle
0391f67109 Per-Function flag to prevent decompilation/disassembly
For now it just sets PROC_ISLIB flag
2016-05-01 18:42:28 +02:00
nemerle
d22624a99b Missing include 2016-05-01 14:55:06 +02:00
nemerle
95acbaa7fa GUI work. 2016-04-29 15:51:02 +02:00
nemerle
2452984864 Convert more of Frontend processing to command lists. 2016-04-29 12:23:12 +02:00
nemerle
4682bda8d8 if CFG is missing Project::createFunction should create one 2016-04-29 12:22:42 +02:00
nemerle
4a6d97c1b1 Prepare CMakeLists for UI work 2016-04-29 12:21:33 +02:00
nemerle
3d5a907b30 Move Function closer to LLVM interface ( FunctionType etc. )
A few more places are using Commands.
2016-04-28 16:25:58 +02:00
nemerle
0684062130 Fix full_regression.sh mkdir 2016-04-28 13:13:35 +02:00
nemerle
62d8633113 Implementation 2016-04-26 16:18:23 +02:00
111 changed files with 5437 additions and 2904 deletions

View File

@ -626,7 +626,7 @@ public:
/* the instruction proper */ /* the instruction proper */
enum x86_insn_prefix prefix; /* prefixes ORed together */ enum x86_insn_prefix prefix; /* prefixes ORed together */
char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */ char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */
char mnemonic[MAX_MNEM_STR]; char mnemonic[MAX_MNEM_STR+1];
x86_oplist_t *operands; /* list of explicit/implicit operands */ x86_oplist_t *operands; /* list of explicit/implicit operands */
size_t operand_count; /* total number of operands */ size_t operand_count; /* total number of operands */
size_t explicit_count; /* number of explicit operands */ size_t explicit_count; /* number of explicit operands */

View File

@ -1,10 +1,6 @@
PROJECT(dcc_original) PROJECT(dcc_original)
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core)
OPTION(dcc_build_tests "Enable unit tests." OFF)
#SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}) #SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS) ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
@ -18,15 +14,25 @@ ENDIF()
SET(CMAKE_CXX_STANDARD 11) SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH}) SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}) SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
include(cotire)
FIND_PACKAGE(Boost) set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5Core)
find_package(Qt5Widgets)
find_package(Boost)
OPTION(dcc_build_tests "Enable unit tests." OFF)
IF(dcc_build_tests) IF(dcc_build_tests)
enable_testing() enable_testing()
FIND_PACKAGE(GMock) find_package(Qt5Test)
#FIND_PACKAGE(GMock)
ENDIF() ENDIF()
INCLUDE_DIRECTORIES( INCLUDE_DIRECTORIES(
${PROJECT_SOURCE_DIR}
3rd_party/libdisasm 3rd_party/libdisasm
include include
include/idioms include/idioms
@ -34,109 +40,7 @@ INCLUDE_DIRECTORIES(
${Boost_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}
) )
ADD_SUBDIRECTORY(3rd_party) ADD_SUBDIRECTORY(3rd_party)
ADD_SUBDIRECTORY(common) ADD_SUBDIRECTORY(common)
ADD_SUBDIRECTORY(tools) ADD_SUBDIRECTORY(tools)
set(dcc_LIB_SOURCES
src/CallConvention.cpp
src/ast.cpp
src/backend.cpp
src/bundle.cpp
src/chklib.cpp
src/comwrite.cpp
src/control.cpp
src/dataflow.cpp
src/disassem.cpp
src/DccFrontend.cpp
src/error.cpp
src/fixwild.cpp
src/graph.cpp
src/hlicode.cpp
src/hltype.cpp
src/machine_x86.cpp
src/icode.cpp
src/RegisterNode
src/idioms.cpp
src/idioms/idiom1.cpp
src/idioms/arith_idioms.cpp
src/idioms/call_idioms.cpp
src/idioms/epilogue_idioms.cpp
src/idioms/mov_idioms.cpp
src/idioms/neg_idioms.cpp
src/idioms/shift_idioms.cpp
src/idioms/xor_idioms.cpp
src/locident.cpp
src/liveness_set.cpp
src/parser.cpp
src/procs.cpp
src/project.cpp
src/Procedure.cpp
src/proplong.cpp
src/reducible.cpp
src/scanner.cpp
src/symtab.cpp
src/udm.cpp
src/BasicBlock.cpp
src/dcc_interface.cpp
)
set(dcc_SOURCES
src/dcc.cpp
)
set(dcc_HEADERS
include/ast.h
include/bundle.h
include/BinaryImage.h
include/DccFrontend.h
include/Enums.h
include/dcc.h
include/disassem.h
include/dosdcc.h
include/error.h
include/graph.h
include/hlicode.h
include/machine_x86.h
include/icode.h
include/idioms/idiom.h
include/idioms/idiom1.h
include/idioms/arith_idioms.h
include/idioms/call_idioms.h
include/idioms/epilogue_idioms.h
include/idioms/mov_idioms.h
include/idioms/neg_idioms.h
include/idioms/shift_idioms.h
include/idioms/xor_idioms.h
include/locident.h
include/CallConvention.h
include/project.h
include/scanner.h
include/state.h
include/symtab.h
include/types.h
include/Procedure.h
include/StackFrame.h
include/BasicBlock.h
include/dcc_interface.h
)
SOURCE_GROUP(Source FILES ${dcc_SOURCES})
SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
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} ${dcc_HEADERS})
ADD_DEPENDENCIES(dcc_original dcc_lib)
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s)
qt5_use_modules(dcc_original Core)
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD 11)
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD_REQUIRED ON)
#ADD_SUBDIRECTORY(gui)
if(dcc_build_tests)
ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(src)
endif()

View File

@ -0,0 +1,21 @@
MACRO(ADD_UNIT_TEST name)
IF(NOT ${name}_TEST_VISITED)
# add the loader as a dll
ADD_EXECUTABLE(${name} ${ARGN})
qt5_use_modules(${name} Core)
MESSAGE(WARNING "Adding test " ${name} " " ${ARGN})
TARGET_LINK_LIBRARIES(${name} ${UNIT_TEST_LIBS})
ADD_TEST(NAME ${name} COMMAND ${name})
set_property(TEST ${name} APPEND PROPERTY ENVIRONMENT DCC_TEST_BASE=${PROJECT_SOURCE_DIR})
SET(${name}_TEST_VISITED true)
ENDIF()
ENDMACRO()
function(ADD_QTEST NAME)
add_executable(${NAME} ${NAME}.cpp ${NAME}.h) #${PROTO_SRCS} ${PROTO_HDRS}
target_link_libraries(${NAME} ${test_LIBRARIES})
qt5_use_modules(${NAME} Core Test)
add_test( NAME ${NAME} COMMAND $<TARGET_FILE:${NAME}>)
set_property(TEST ${NAME} APPEND PROPERTY ENVIRONMENT DCC_TEST_BASE=${PROJECT_SOURCE_DIR})
endfunction()

View File

@ -1,4 +1,5 @@
#pragma once #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

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
makedir -p tests/outputs mkdir -p tests/outputs
./test_use_all.sh ./test_use_all.sh
./regression_tester.rb ./dcc_original -s -c 2>stderr >stdout; diff -wB tests/prev/ tests/outputs/ ./regression_tester.rb ./dcc_original -s -c 2>stderr >stdout; diff -wB tests/prev/ tests/outputs/

View File

@ -9,7 +9,7 @@
#include "graph.h" #include "graph.h"
//#include "icode.h" //#include "icode.h"
/* Basic block (BB) node definition */ /* Basic block (BB) node definition */
struct Function; class Function;
class CIcodeRec; class CIcodeRec;
struct BB; struct BB;
struct LOCAL_ID; struct LOCAL_ID;
@ -27,7 +27,7 @@ struct TYPEADR_TYPE
}; };
struct BB struct BB
{ {
friend struct Function; friend class Function;
private: private:
BB(const BB&); BB(const BB&);
BB() : nodeType(0),traversed(DFS_NONE), BB() : nodeType(0),traversed(DFS_NONE),

View File

@ -14,10 +14,8 @@ struct PROG /* Loaded program image parameters */
int cProcs=0; /* Number of procedures so far */ int cProcs=0; /* Number of procedures so far */
int offMain=0; /* The offset of the main() proc */ int offMain=0; /* The offset of the main() proc */
uint16_t segMain=0; /* The segment of the main() proc */ uint16_t segMain=0; /* The segment of the main() proc */
bool bSigs=false; /* True if signatures loaded */
int cbImage=0; /* Length of image in bytes */ int cbImage=0; /* Length of image in bytes */
uint8_t * Imagez=nullptr; /* Allocated by loader to hold entire program image */ uint8_t * Imagez=nullptr; /* Allocated by loader to hold entire program image */
int addressingMode=0;
public: public:
const uint8_t *image() const {return Imagez;} const uint8_t *image() const {return Imagez;}
void displayLoadInfo(); void displayLoadInfo();

View File

@ -7,30 +7,35 @@
class QTextStream; class QTextStream;
struct CConv { struct CConv {
enum Type { enum CC_Type {
UNKNOWN=0, UNKNOWN=0,
C, C,
PASCAL PASCAL
}; };
virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0; virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0;
//! given return and argument types fill Function's STKFRAME and return locations
virtual void calculateStackLayout(Function *func)=0;
virtual void writeComments(QTextStream &)=0; virtual void writeComments(QTextStream &)=0;
static CConv * create(Type v); static CConv * create(CC_Type v);
protected: protected:
}; };
struct C_CallingConvention : public CConv { struct C_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode); virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &); virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
private: private:
int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs); int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs);
}; };
struct Pascal_CallingConvention : public CConv { struct Pascal_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode); virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &); virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
}; };
struct Unknown_CallingConvention : public CConv { struct Unknown_CallingConvention : public CConv {
void processHLI(Function *func, Expr *_exp, iICODE picode) {} void processHLI(Function *func, Expr *_exp, iICODE picode) override {}
virtual void writeComments(QTextStream &); void calculateStackLayout(Function *func) override;
virtual void writeComments(QTextStream &) override;
}; };

View File

@ -3,7 +3,7 @@
/* CALL GRAPH NODE */ /* CALL GRAPH NODE */
struct CALL_GRAPH struct CALL_GRAPH
{ {
ilFunction proc; /* Pointer to procedure in pProcList */ PtrFunction proc; /* Pointer to procedure in pProcList */
std::vector<CALL_GRAPH *> outEdges; /* array of out edges */ std::vector<CALL_GRAPH *> outEdges; /* array of out edges */
public: public:
void write(); void write();
@ -12,8 +12,8 @@ public:
} }
public: public:
void writeNodeCallGraph(int indIdx); void writeNodeCallGraph(int indIdx);
bool insertCallGraph(ilFunction caller, ilFunction callee); bool insertCallGraph(PtrFunction caller, PtrFunction callee);
bool insertCallGraph(Function *caller, ilFunction callee); //bool insertCallGraph(PtrFunction caller, PtrFunction callee);
void insertArc(ilFunction newProc); void insertArc(PtrFunction newProc);
}; };
//extern CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */ //extern CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */

View File

@ -1,12 +1,14 @@
#pragma once #pragma once
#include <QObject> #include <QtCore/QObject>
#include "src/Command.h"
#include "project.h"
class Project; class Project;
class DccFrontend : public QObject class DccFrontend : public QObject
{ {
Q_OBJECT Q_OBJECT
void LoadImage(); void LoadImage();
void parse(Project &proj); void parse(Project &proj);
std::string m_fname;
public: public:
explicit DccFrontend(QObject *parent = 0); explicit DccFrontend(QObject *parent = 0);
bool FrontEnd(); /* frontend.c */ bool FrontEnd(); /* frontend.c */
@ -15,3 +17,28 @@ signals:
public slots: public slots:
}; };
struct MachineStateInitialization : public Command {
MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {}
bool execute(CommandContext *ctx) override;
};
struct FindMain : public Command {
FindMain() : Command("Locate the main entry point",eProject) {}
bool execute(CommandContext *ctx);
};
struct CreateFunction : public Command {
QString m_name;
SegOffAddr m_addr;
FunctionType *m_type;
CreateFunction(QString name,SegOffAddr address,FunctionType *f) : Command("Create function",eProject),
m_name(name),
m_addr(address),
m_type(f)
{}
QString instanceDescription() const override;
bool execute(CommandContext *ctx) override;
};

View File

@ -263,7 +263,8 @@ enum hlType
TYPE_STR, /* string */ TYPE_STR, /* string */
TYPE_CONST, /* constant (any type) */ TYPE_CONST, /* constant (any type) */
TYPE_FLOAT, /* floating point */ TYPE_FLOAT, /* floating point */
TYPE_DOUBLE /* double precision float */ TYPE_DOUBLE, /* double precision float */
TYPE_FUNC
}; };
/* Operand is defined, used or both flag */ /* Operand is defined, used or both flag */

View File

@ -6,6 +6,8 @@
#include "StackFrame.h" #include "StackFrame.h"
#include "CallConvention.h" #include "CallConvention.h"
#include <memory>
#include <stdint.h>
#include <QtCore/QString> #include <QtCore/QString>
#include <bitset> #include <bitset>
#include <map> #include <map>
@ -17,42 +19,71 @@ class QTextStream;
struct CALL_GRAPH; struct CALL_GRAPH;
struct Expr; struct Expr;
struct Disassembler; struct Disassembler;
struct Function; class Function;
struct CALL_GRAPH; struct CALL_GRAPH;
struct PROG; struct PROG;
struct IStructuredTextTarget;
struct Function;
/* Procedure FLAGS */ /* Procedure FLAGS */
enum PROC_FLAGS enum PROC_FLAGS
{ {
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */ PROC_BADINST=0x00000100, /* Proc contains invalid or 386 instruction */
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */ PROC_IJMP =0x00000200, /* Proc incomplete due to indirect jmp */
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */ PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */ PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */ PROC_NEAR =0x00010000, /* Proc exits with near return */
// CALL_C =0x00004000, /* Proc uses C calling convention */ PROC_FAR =0x00020000, /* Proc exits with far return */
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */ GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
PROC_NEAR =0x00010000, /* Proc exits with near return */ SI_REGVAR =0x00200000, /* SI is used as a stack variable */
PROC_FAR =0x00020000, /* Proc exits with far return */ DI_REGVAR =0x00400000, /* DI is used as a stack variable */
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */ REG_ARGS =0x01000000, /* Proc has registers as arguments */
SI_REGVAR =0x00200000, /* SI is used as a stack variable */ // PROC_VARARG =0x02000000, /* Proc has variable arguments */
DI_REGVAR =0x00400000, /* DI is used as a stack variable */ PROC_OUTPUT =0x04000000, /* C for this proc has been output */
PROC_IS_FUNC=0x00800000, /* Proc is a function */ PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */
REG_ARGS =0x01000000, /* Proc has registers as arguments */ PROC_ISLIB =0x10000000, /* Proc is a library function */
// PROC_VARARG =0x02000000, /* Proc has variable arguments */ PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */
PROC_OUTPUT =0x04000000, /* C for this proc has been output */ PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */
PROC_RUNTIME=0x08000000, /* Proc is part of the runtime support */ //#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
PROC_ISLIB =0x10000000, /* Proc is a library function */
PROC_ASM =0x20000000, /* Proc is an intrinsic assembler routine */
PROC_IS_HLL =0x40000000 /* Proc has HLL prolog code */
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
}; };
struct FunctionType struct Type {
hlType dcc_type;
};
struct FunctionType : public Type
{ {
CConv * m_call_conv;
std::vector<Type> ContainedTys;
ID retVal; /* Return value - identifier */
bool m_vararg=false; bool m_vararg=false;
unsigned getNumParams() const { return ContainedTys.size(); }
bool isVarArg() const {return m_vararg;} bool isVarArg() const {return m_vararg;}
void setReturnType(hlType t) {
retVal.type = t;
}
void setReturnLocation(const LONGID_TYPE &v) {
retVal.loc = REG_FRAME;
retVal.longId() = v;
}
void setReturnLocation(eReg reg) {
retVal.loc = REG_FRAME;
retVal.id.regi = reg;
}
hlType getReturnType() const { return retVal.type; }
void addArgument(hlType hl) {
ContainedTys.push_back(Type {hl});
}
void clearArguments() { ContainedTys.clear(); }
void setCallingConvention(CConv::CC_Type cc);
static FunctionType *get(Type result,std::vector<Type> params, bool vararg_func) {
FunctionType * res = new FunctionType;
res->setReturnType(result.dcc_type);
std::swap(res->ContainedTys,params);
res->m_vararg = vararg_func;
return res;
}
}; };
struct Assignment struct Assignment
{ {
@ -88,7 +119,17 @@ public:
} }
void push_back(BB *v) { m_listBB.push_back(v);} void push_back(BB *v) { m_listBB.push_back(v);}
}; };
struct Function typedef std::shared_ptr<Function> PtrFunction;
enum DecompilationStep : uint32_t {
eNotDecoded, // no processing done yet
eDisassemblyInProgress,
eDissassembled, // low level disassembly done
//eLocatedImpureRefs,
//eStackTracing, // tracing stack depth across function calls
};
class Function : public std::enable_shared_from_this<Function>
{ {
typedef std::list<BB *> BasicBlockListType; typedef std::list<BB *> BasicBlockListType;
// BasicBlock iterators... // BasicBlock iterators...
@ -96,25 +137,26 @@ struct Function
typedef BasicBlockListType::const_iterator const_iterator; typedef BasicBlockListType::const_iterator const_iterator;
protected: protected:
BasicBlockListType BasicBlocks; ///< The basic blocks BasicBlockListType BasicBlocks; ///< The basic blocks
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0), Function(FunctionType *ty) : nStep(eNotDecoded),procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
hasCase(false),liveAnal(0) hasCase(false),liveAnal(0)
{ {
type = new FunctionType; type = ty;
if(!ty) // No type was provided, create it
type = new FunctionType;
callingConv(CConv::UNKNOWN); callingConv(CConv::UNKNOWN);
} }
public: public:
DecompilationStep nStep; // decompilation step number for this function
FunctionType * type; FunctionType * type;
CConv * m_call_conv;
uint32_t procEntry; /* label number */ uint32_t procEntry; /* label number */
QString name; /* Meaningful name for this proc */ QString name; /* Meaningful name for this proc */
STATE state; /* Entry state */ STATE state; /* Entry state */
int depth; /* Depth at which we found it - for printing */ int depth; /* Depth at which we found it - for printing */
uint32_t flg; /* Combination of Icode & Proc flags */ uint32_t flg; /* Combination of Icode & Proc flags */
int16_t cbParam; /* Probable no. of bytes of parameters */ int16_t cbParam; /* Probable no. of bytes of parameters */
STKFRAME args; /* Array of arguments */ STKFRAME args; /* Array of arguments */
LOCAL_ID localId; /* Local identifiers */ LOCAL_ID localId; /* Local identifiers */
ID retVal; /* Return value - identifier */
/* Icodes and control flow graph */ /* Icodes and control flow graph */
CIcodeRec Icode; /* Object with ICODE records */ CIcodeRec Icode; /* Object with ICODE records */
@ -128,26 +170,31 @@ public:
/* For interprocedural live analysis */ /* For interprocedural live analysis */
LivenessSet liveIn; /* Registers used before defined */ LivenessSet liveIn; /* Registers used before defined */
LivenessSet liveOut; /* Registers that may be used in successors */ LivenessSet liveOut; /* Registers that may be used in successors */
bool liveAnal; /* Procedure has been analysed already */ bool liveAnal; /* Procedure has been analysed already */
virtual ~Function() { virtual ~Function() {
delete type; delete type;
} }
public: public:
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0) static PtrFunction Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
{ {
Function *r=new Function(ty); PtrFunction r(new Function(ty));
r->name = nm; r->name = nm;
return r; return r;
} }
hlType getReturnType() const {
return getFunctionType()->getReturnType();
}
FunctionType *getFunctionType() const { FunctionType *getFunctionType() const {
return type; return type;
} }
CConv *callingConv() const { return m_call_conv;} CConv *callingConv() const { return type->m_call_conv;}
void callingConv(CConv::Type v); void callingConv(CConv::CC_Type v);
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;} // bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;} bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
void markDoNotDecompile() { flg |= PROC_ISLIB; }
bool doNotDecompile() const { return isLibrary(); }
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;} bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
void compoundCond(); void compoundCond();
void writeProcComments(); void writeProcComments();
@ -161,10 +208,7 @@ public:
void createCFG(); void createCFG();
void markImpure(); void markImpure();
void findImmedDom(); void findImmedDom();
void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate);
void process_operands(ICODE &pIcode, STATE *pstate); void process_operands(ICODE &pIcode, STATE *pstate);
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
void freeCFG(); void freeCFG();
void codeGen(QIODevice & fs); void codeGen(QIODevice & fs);
void mergeFallThrough(BB *pBB); void mergeFallThrough(BB *pBB);
@ -174,6 +218,7 @@ public:
void controlFlowAnalysis(); void controlFlowAnalysis();
void newRegArg(iICODE picode, iICODE ticode); void newRegArg(iICODE picode, iICODE ticode);
void writeProcComments(QTextStream & ostr); void writeProcComments(QTextStream & ostr);
void toStructuredText(IStructuredTextTarget *out,int level);
void displayCFG(); void displayCFG();
void displayStats(); void displayStats();
@ -183,11 +228,10 @@ public:
Expr * adjustActArgType(Expr *_exp, hlType forType); Expr * adjustActArgType(Expr *_exp, hlType forType);
QString writeCall(Function *tproc, STKFRAME &args, int *numLoc); QString writeCall(Function *tproc, STKFRAME &args, int *numLoc);
void processDosInt(STATE *pstate, PROG &prog, bool done); void processDosInt(STATE *pstate, PROG &prog, bool done);
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode); void switchState(DecompilationStep s);
protected: protected:
void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table); void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table);
bool followAllTableEntries(JumpTable &table, uint32_t cs, ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
bool removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b); bool removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b);
bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB); bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB); bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
@ -214,12 +258,8 @@ protected:
void genLiveKtes(); void genLiveKtes();
bool findDerivedSeq(derSeq &derivedGi); bool findDerivedSeq(derSeq &derivedGi);
bool nextOrderGraph(derSeq &derivedGi); bool nextOrderGraph(derSeq &derivedGi);
void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll); void addOutEdgesForConditionalJump(BB *pBB, int next_ip, LLInst *ll);
private:
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
}; };
typedef std::list<Function> FunctionListType; typedef std::list<PtrFunction> FunctionListType;
typedef FunctionListType lFunction; typedef FunctionListType lFunction;
typedef lFunction::iterator ilFunction; typedef lFunction::iterator ilFunction;

View File

@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon<STKSYM>
//std::vector<STKSYM> sym; //std::vector<STKSYM> sym;
//STKSYM * sym; /* Symbols */ //STKSYM * sym; /* Symbols */
int16_t m_minOff; /* Initial offset in stack frame*/ int16_t m_minOff; /* Initial offset in stack frame*/
int16_t maxOff; /* Maximum offset in stack frame*/ int16_t m_maxOff; /* Maximum offset in stack frame*/
int cb; /* Number of bytes in arguments */ int cb; /* Number of bytes in arguments */
int numArgs; /* No. of arguments in the table*/ int numArgs; /* No. of arguments in the table*/
void adjustForArgType(size_t numArg_, hlType actType_); void adjustForArgType(size_t numArg_, hlType actType_);
STKFRAME() : m_minOff(0),maxOff(0),cb(0),numArgs(0) STKFRAME() : m_minOff(0),m_maxOff(0),cb(0),numArgs(0)
{ {
} }

View File

@ -28,7 +28,7 @@ static const condOp condOpJCond[12] = {LESS, LESS_EQUAL, GREATER_EQUAL, GREATER,
EQUAL, NOT_EQUAL, LESS, GREATER_EQUAL, EQUAL, NOT_EQUAL, LESS, GREATER_EQUAL,
LESS_EQUAL, GREATER, GREATER_EQUAL, LESS}; LESS_EQUAL, GREATER, GREATER_EQUAL, LESS};
struct AstIdent; struct AstIdent;
struct Function; class Function;
struct STKFRAME; struct STKFRAME;
struct LOCAL_ID; struct LOCAL_ID;
struct ICODE; struct ICODE;
@ -241,7 +241,7 @@ struct GlobalVariable : public AstIdent
struct GlobalVariableIdx : public AstIdent struct GlobalVariableIdx : public AstIdent
{ {
bool valid; bool valid;
int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */ int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */
virtual Expr *clone() const virtual Expr *clone() const
{ {
@ -255,9 +255,9 @@ struct GlobalVariableIdx : public AstIdent
struct Constant : public AstIdent struct Constant : public AstIdent
{ {
struct _kte struct _kte
{ /* for CONSTANT only */ { /* for CONSTANT only */
uint32_t kte; /* value of the constant */ uint32_t kte; /* value of the constant */
uint8_t size; /* #bytes size constant */ uint8_t size; /* #bytes size constant */
} kte; } kte;
Constant(uint32_t _kte, uint8_t size) Constant(uint32_t _kte, uint8_t size)
@ -276,7 +276,7 @@ struct Constant : public AstIdent
}; };
struct FuncNode : public AstIdent struct FuncNode : public AstIdent
{ {
struct _call { /* for FUNCTION only */ struct _call { /* for FUNCTION only */
Function *proc; Function *proc;
STKFRAME *args; STKFRAME *args;
} call; } call;
@ -297,8 +297,8 @@ struct FuncNode : public AstIdent
struct RegisterNode : public AstIdent struct RegisterNode : public AstIdent
{ {
const LOCAL_ID *m_syms; const LOCAL_ID *m_syms;
regType regiType; /* for REGISTER only */ regType regiType; /* for REGISTER only */
int regiIdx; /* index into localId, REGISTER */ int regiIdx; /* index into localId, REGISTER */
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym); virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);

View File

@ -36,7 +36,7 @@ public:
}; };
extern bundle cCode; extern bundle cCode;
#define lineSize 360 /* 3 lines in the mean time */ #define lineSize 360 /* 3 lines in the mean time */
//void newBundle (bundle *procCode); //void newBundle (bundle *procCode);
void writeBundle (QIODevice & ios, bundle procCode); void writeBundle (QIODevice & ios, bundle procCode);

View File

@ -22,11 +22,11 @@
#include "BasicBlock.h" #include "BasicBlock.h"
class Project; class Project;
/* CALL GRAPH NODE */ /* CALL GRAPH NODE */
extern bundle cCode; /* Output C procedure's declaration and code */ extern bundle cCode; /* Output C procedure's declaration and code */
/**** Global variables ****/ /**** Global variables ****/
extern QString asm1_name, asm2_name; /* Assembler output filenames */ extern QString asm1_name, asm2_name; /* Assembler output filenames */
typedef struct { /* Command line option flags */ typedef struct { /* Command line option flags */
unsigned verbose : 1; unsigned verbose : 1;
@ -37,7 +37,7 @@ typedef struct { /* Command line option flags */
unsigned Stats : 1; unsigned Stats : 1;
unsigned Interact : 1; /* Interactive mode */ unsigned Interact : 1; /* Interactive mode */
unsigned Calls : 1; /* Follow register indirect calls */ unsigned Calls : 1; /* Follow register indirect calls */
QString filename; /* The input filename */ QString filename; /* The input filename */
uint32_t CustomEntryPoint; uint32_t CustomEntryPoint;
} OPTION; } OPTION;
@ -59,13 +59,13 @@ enum eAreaType
/* Intermediate instructions statistics */ /* Intermediate instructions statistics */
struct STATS struct STATS
{ {
int numBBbef; /* number of basic blocks initially */ int numBBbef; /* number of basic blocks initially */
int numBBaft; /* number of basic blocks at the end */ int numBBaft; /* number of basic blocks at the end */
int nOrder; /* n-th order */ int nOrder; /* n-th order */
int numLLIcode; /* number of low-level Icode instructions */ int numLLIcode; /* number of low-level Icode instructions */
int numHLIcode; /* number of high-level Icode instructions */ int numHLIcode; /* number of high-level Icode instructions */
int totalLL; /* total number of low-level Icode insts */ int totalLL; /* total number of low-level Icode insts */
int totalHL; /* total number of high-level Icod insts */ int totalHL; /* total number of high-level Icod insts */
}; };
extern STATS stats; /* Icode statistics */ extern STATS stats; /* Icode statistics */
@ -76,18 +76,17 @@ extern STATS stats; /* Icode statistics */
void udm(void); /* udm.c */ void udm(void); /* udm.c */
void freeCFG(BB * cfg); /* graph.c */ void freeCFG(BB * cfg); /* graph.c */
BB * newBB(BB *, int, int, uint8_t, int, Function *); /* graph.c */ BB * newBB(BB *, int, int, uint8_t, int, Function *); /* graph.c */
void BackEnd(CALL_GRAPH *); /* backend.c */ void BackEnd(CALL_GRAPH *); /* backend.c */
extern char *cChar(uint8_t c); /* backend.c */ extern char *cChar(uint8_t c); /* backend.c */
eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */ eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */
void parse (CALL_GRAPH * *); /* parser.c */ void parse (CALL_GRAPH * *); /* parser.c */
extern int strSize (const uint8_t *, char); /* parser.c */ extern int strSize (const uint8_t *, char); /* parser.c */
//void disassem(int pass, Function * pProc); /* disassem.c */ void interactDis(const PtrFunction &, int initIC); /* disassem.c */
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

@ -4,21 +4,11 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QDir> #include <QtCore/QDir>
class IXmlTarget; class IStructuredTextTarget;
struct IDcc { struct IDcc {
static IDcc *get(); static IDcc *get();
virtual void BaseInit()=0; virtual bool load(QString name)=0; // load and preprocess -> find entry point
virtual void Init(QObject *tgt)=0;
virtual lFunction::iterator GetFirstFuncHandle()=0;
virtual lFunction::iterator GetCurFuncHandle()=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 size_t getFuncCount()=0;
virtual const lFunction &validFunctions() const =0;
virtual void SetCurFunc_by_Name(QString )=0;
virtual QDir installDir()=0; virtual QDir installDir()=0;
virtual QDir dataDir(QString kind)=0; virtual QDir dataDir(QString kind)=0;
}; };

View File

@ -7,19 +7,22 @@
#pragma once #pragma once
#include "bundle.h" #include "bundle.h"
#include <memory>
#include <fstream> #include <fstream>
#include <vector> #include <vector>
#include <QString> #include <QString>
#include <QTextStream> #include <QTextStream>
struct LLInst; struct LLInst;
struct Function; class Function;
typedef std::shared_ptr<Function> PtrFunction;
struct Disassembler struct Disassembler
{ {
protected: protected:
int pass; int pass=0;
int g_lab; int g_lab=0;
//bundle &cCode; QIODevice *m_disassembly_target=nullptr;
QIODevice *m_disassembly_target;
QTextStream m_fp; QTextStream m_fp;
std::vector<std::string> m_decls; std::vector<std::string> m_decls;
std::vector<std::string> m_code; std::vector<std::string> m_code;
@ -27,30 +30,29 @@ protected:
public: public:
Disassembler(int _p) : pass(_p) Disassembler(int _p) : pass(_p)
{ {
g_lab=0;
} }
public:
void disassem(Function *ppProc); void disassem(PtrFunction ppProc);
void disassem(Function *ppProc, int i); void disassem(PtrFunction ppProc, int i);
void dis1Line(LLInst &inst, int loc_ip, int pass); void dis1Line(LLInst &inst, int loc_ip, int pass);
}; };
/* Definitions for extended keys (first key is zero) */ /* Definitions for extended keys (first key is zero) */
#define EXT 0x100 /* "Extended" flag */ #define EXT 0x100 /* "Extended" flag */
#ifdef __UNIX__ #ifdef __UNIX__
#define KEY_DOWN EXT+'B' #define KEY_DOWN EXT+'B'
#define KEY_LEFT EXT+'D' #define KEY_LEFT EXT+'D'
#define KEY_UP EXT+'A' #define KEY_UP EXT+'A'
#define KEY_RIGHT EXT+'C' #define KEY_RIGHT EXT+'C'
#define KEY_NPAGE EXT+'J' /* Enter correct value! */ #define KEY_NPAGE EXT+'J' /* Enter correct value! */
#define KEY_PPAGE EXT+'K' /* Another guess! */ #define KEY_PPAGE EXT+'K' /* Another guess! */
#endif #endif
/* "Attributes" */ /* "Attributes" */
#define A_NORMAL 'N' /* For Dos/Unix */ #define A_NORMAL 'N' /* For Dos/Unix */
#define A_REVERSE 'I' #define A_REVERSE 'I'
#define A_BOLD 'B' #define A_BOLD 'B'
#define LINES 24 #define LINES 24
#define COLS 80 #define COLS 80

View File

@ -8,7 +8,7 @@
#include <stdint.h> #include <stdint.h>
#include <list> #include <list>
struct Function; class Function;
/* Types of basic block nodes */ /* Types of basic block nodes */
/* Real basic blocks: type defined according to their out-edges */ /* Real basic blocks: type defined according to their out-edges */
enum eBBKind enum eBBKind
@ -51,16 +51,16 @@ enum eNodeHeaderType
/* Uninitialized values for certain fields */ /* Uninitialized values for certain fields */
#define NO_NODE MAX /* node has no associated node */ #define NO_NODE MAX /* node has no associated node */
#define NO_DOM MAX /* node has no dominator */ #define NO_DOM MAX /* node has no dominator */
#define UN_INIT MAX /* uninitialized variable */ #define UN_INIT MAX /* uninitialized variable */
#define THEN 0 /* then edge */ #define THEN 0 /* then edge */
#define ELSE 1 /* else edge */ #define ELSE 1 /* else edge */
/* Basic Block (BB) flags */ /* Basic Block (BB) flags */
#define INVALID_BB 0x0001 /* BB is not valid any more */ #define INVALID_BB 0x0001 /* BB is not valid any more */
#define IS_LATCH_NODE 0x0002 /* BB is the latching node of a loop */ #define IS_LATCH_NODE 0x0002 /* BB is the latching node of a loop */
struct BB; struct BB;
/* Interval structure */ /* Interval structure */

View File

@ -7,7 +7,7 @@
#include "BinaryImage.h" #include "BinaryImage.h"
#include "libdis.h" #include "libdis.h"
#include "Enums.h" #include "Enums.h"
#include "state.h" // State depends on INDEXBASE, but later need STATE #include "state.h" // State depends on INDEXBASE, but later need STATE
#include "CallConvention.h" #include "CallConvention.h"
#include <boost/range/iterator_range.hpp> #include <boost/range/iterator_range.hpp>
@ -25,7 +25,7 @@
struct LOCAL_ID; struct LOCAL_ID;
struct BB; struct BB;
struct Function; class Function;
struct STKFRAME; struct STKFRAME;
class CIcodeRec; class CIcodeRec;
struct ICODE; struct ICODE;
@ -128,7 +128,7 @@ struct DU
}; };
/* Definition-use chain for level 1 (within a basic block) */ /* Definition-use chain for level 1 (within a basic block) */
#define MAX_REGS_DEF 4 /* 2 regs def'd for long-reg vars */ #define MAX_REGS_DEF 4 /* 2 regs def'd for long-reg vars */
struct Expr; struct Expr;
@ -166,7 +166,7 @@ struct AssignType : public HlTypeSupport
protected: protected:
public: public:
Expr *m_lhs; Expr *m_lhs;
Expr *rhs; Expr *m_rhs;
AssignType() {} AssignType() {}
Expr *lhs() const {return m_lhs;} Expr *lhs() const {return m_lhs;}
void lhs(Expr *l); void lhs(Expr *l);
@ -243,20 +243,20 @@ public:
/* LOW_LEVEL icode operand record */ /* LOW_LEVEL icode operand record */
struct LLOperand struct LLOperand
{ {
eReg seg; /* CS, DS, ES, SS */ eReg seg; /* CS, DS, ES, SS */
eReg segOver; /* CS, DS, ES, SS if segment override */ eReg segOver; /* CS, DS, ES, SS if segment override */
int16_t segValue; /* Value of segment seg during analysis */ int16_t segValue; /* Value of segment seg during analysis */
eReg regi; /* 0 < regs < INDEXBASE <= index modes */ eReg regi; /* 0 < regs < INDEXBASE <= index modes */
int16_t off; /* memory address offset */ int16_t off; /* memory address offset */
uint32_t opz; /* idx of immed src op */ uint32_t opz; /* idx of immed src op */
bool immed; bool immed;
bool is_offset; // set by jumps bool is_offset; // set by jumps
bool is_compound; bool is_compound;
size_t width; size_t width;
//union {/* Source operand if (flg & I) */ /* Source operand if (flg & I) */
struct { /* Call & # actual arg bytes */ struct { /* Call & # actual arg bytes */
Function *proc; /* pointer to target proc (for CALL(F))*/ Function *proc; /* pointer to target proc (for CALL(F))*/
int cb; /* # actual arg bytes */ int cb; /* # actual arg bytes */
} proc; } proc;
LLOperand() : seg(rUNDEF),segOver(rUNDEF),segValue(0),regi(rUNDEF),off(0), LLOperand() : seg(rUNDEF),segOver(rUNDEF),segValue(0),regi(rUNDEF),off(0),
opz(0),immed(0),is_offset(false),is_compound(0),width(0) opz(0),immed(0),is_offset(false),is_compound(0),width(0)
@ -300,11 +300,11 @@ struct LLOperand
Op.regi = (eReg)Val; Op.regi = (eReg)Val;
return Op; return Op;
} }
bool isSet() bool isSet() const
{ {
return not (*this == LLOperand()); return not (*this == LLOperand());
} }
void addProcInformation(int param_count, CConv::Type call_conv); void addProcInformation(int param_count, CConv::CC_Type call_conv);
bool isImmediate() const { return immed;} bool isImmediate() const { return immed;}
void setImmediate(bool x) { immed=x;} void setImmediate(bool x) { immed=x;}
bool compound() const {return is_compound;} // dx:ax pair bool compound() const {return is_compound;} // dx:ax pair
@ -314,130 +314,125 @@ struct LLInst
{ {
protected: protected:
uint32_t m_opcode; // Low level opcode identifier uint32_t m_opcode; // Low level opcode identifier
uint32_t flg; /* icode flags */ uint32_t flg; /* icode flags */
LLOperand m_src; /* source operand */ LLOperand m_src; /* source operand */
public: public:
int codeIdx; /* Index into cCode.code */ int codeIdx; /* Index into cCode.code */
uint8_t numBytes; /* Number of bytes this instr */ uint8_t numBytes; /* Number of bytes this instr */
uint32_t label; /* offset in image (20-bit adr) */ uint32_t label; /* offset in image (20-bit adr) */
LLOperand m_dst; /* destination operand */ LLOperand m_dst; /* destination operand */
DU flagDU; /* def/use of flags */ DU flagDU; /* def/use of flags */
int caseEntry; int caseEntry;
std::vector<uint32_t> caseTbl2; std::vector<uint32_t> caseTbl2;
int hllLabNum; /* label # for hll codegen */ int hllLabNum; /* label # for hll codegen */
uint32_t getOpcode() const { return m_opcode;} uint32_t getOpcode() const { return m_opcode;}
void setOpcode(uint32_t op) { m_opcode=op; } void setOpcode(uint32_t op) { m_opcode=op; }
bool conditionalJump() bool conditionalJump()
{ {
return (getOpcode() >= iJB) and (getOpcode() < iJCXZ); return (getOpcode() >= iJB) and (getOpcode() < iJCXZ);
} }
bool testFlags(uint32_t x) const { return (flg & x)!=0;} bool testFlags(uint32_t x) const { return (flg & x)!=0;}
void setFlags(uint32_t flag) {flg |= flag;} void setFlags(uint32_t flag) {flg |= flag;}
void clrFlags(uint32_t flag) void clrFlags(uint32_t flag);
{ uint32_t getFlag() const {return flg;}
if(getOpcode()==iMOD) uint32_t GetLlLabel() const { return label;}
{
assert(false);
}
flg &= ~flag;
}
uint32_t getFlag() const {return flg;}
uint32_t GetLlLabel() const { return label;}
void SetImmediateOp(uint32_t dw) {m_src.SetImmediateOp(dw);} void SetImmediateOp(uint32_t dw) {m_src.SetImmediateOp(dw);}
bool match(llIcode op)
{
return (getOpcode()==op);
}
bool matchWithRegDst(llIcode op)
{
return match(op) and m_dst.isReg();
}
bool match(llIcode op,eReg dest)
{
return match(op) and match(dest);
}
bool match(llIcode op,eReg dest,uint32_t flgs)
{
return match(op) and match(dest) and testFlags(flgs);
}
bool match(llIcode op,eReg dest,eReg src_reg)
{
return match(op) and match(dest) and (m_src.regi==src_reg);
}
bool match(eReg dest,eReg src_reg)
{
return match(dest) and (m_src.regi==src_reg);
}
bool matchAny(std::initializer_list<llIcode> ops) {
for(llIcode op : ops) {
if(match(op))
return true;
}
return false;
}
bool match(eReg dest)
{
return (m_dst.regi==dest);
}
bool match(llIcode op,uint32_t flgs)
{
return match(op) and testFlags(flgs);
}
void set(llIcode op,uint32_t flags)
{
setOpcode(op);
flg =flags;
}
void set(llIcode op,uint32_t flags,eReg dst_reg)
{
setOpcode(op);
m_dst = LLOperand::CreateReg2(dst_reg);
flg =flags;
}
void set(llIcode op,uint32_t flags,eReg dst_reg,const LLOperand &src_op)
{
setOpcode(op);
m_dst = LLOperand::CreateReg2(dst_reg);
m_src = src_op;
flg =flags;
}
void emitGotoLabel(int indLevel);
void findJumpTargets(CIcodeRec &_pc);
void writeIntComment(QTextStream & s);
void dis1Line(int loc_ip, int pass);
bool match(llIcode op) void flops(QTextStream & out);
{ bool isJmpInst();
return (getOpcode()==op); HLTYPE createCall();
} LLInst(ICODE *container) : flg(0),codeIdx(0),numBytes(0),m_link(container)
bool matchWithRegDst(llIcode op) {
{ setOpcode(0);
return (getOpcode()==op) and m_dst.isReg(); }
} const LLOperand & dst() const { return m_dst; }
bool match(llIcode op,eReg dest) LLOperand & dst() { return m_dst; }
{ const LLOperand & src() const { return m_src; }
return (getOpcode()==op)&&m_dst.regi==dest; LLOperand & src() { return m_src; }
} void replaceSrc(const LLOperand &with) { m_src = with; }
bool match(llIcode op,eReg dest,uint32_t flgs) void replaceSrc(eReg r) { m_src = LLOperand::CreateReg2(r); }
{ void replaceSrc(int64_t r) { m_src = LLOperand::CreateImm2(r); }
return (getOpcode()==op) and (m_dst.regi==dest) and testFlags(flgs); void replaceDst(const LLOperand &with) { m_dst = with; }
} bool srcIsImmed() const { return (flg & I)!=0; }
bool match(llIcode op,eReg dest,eReg src_reg) condId idType(opLoc sd) const;
{
return (getOpcode()==op) and (m_dst.regi==dest) and (m_src.regi==src_reg);
}
bool match(eReg dest,eReg src_reg)
{
return (m_dst.regi==dest) and (m_src.regi==src_reg);
}
bool match(eReg dest)
{
return (m_dst.regi==dest);
}
bool match(llIcode op,uint32_t flgs)
{
return (getOpcode()==op) and testFlags(flgs);
}
void set(llIcode op,uint32_t flags)
{
setOpcode(op);
flg =flags;
}
void set(llIcode op,uint32_t flags,eReg dst_reg)
{
setOpcode(op);
m_dst = LLOperand::CreateReg2(dst_reg);
flg =flags;
}
void set(llIcode op,uint32_t flags,eReg dst_reg,const LLOperand &src_op)
{
setOpcode(op);
m_dst = LLOperand::CreateReg2(dst_reg);
m_src = src_op;
flg =flags;
}
void emitGotoLabel(int indLevel);
void findJumpTargets(CIcodeRec &_pc);
void writeIntComment(QTextStream & s);
void dis1Line(int loc_ip, int pass);
QTextStream & strSrc(QTextStream & os, bool skip_comma=false);
void flops(QTextStream & out);
bool isJmpInst();
HLTYPE createCall();
LLInst(ICODE *container) : flg(0),codeIdx(0),numBytes(0),m_link(container)
{
setOpcode(0);
}
const LLOperand &src() const {return m_src;}
LLOperand &src() {return m_src;}
void replaceSrc(const LLOperand &with)
{
m_src = with;
}
void replaceSrc(eReg r)
{
m_src = LLOperand::CreateReg2(r);
}
void replaceSrc(int64_t r)
{
m_src = LLOperand::CreateImm2(r);
}
void replaceDst(const LLOperand &with)
{
m_dst = with;
}
// void replaceDst(eReg r)
// {
// dst = LLOperand::CreateReg2(r);
// }
ICODE *m_link;
condId idType(opLoc sd) const;
const LLOperand * get(opLoc sd) const { return (sd == SRC) ? &src() : &m_dst; } const LLOperand * get(opLoc sd) const { return (sd == SRC) ? &src() : &m_dst; }
LLOperand * get(opLoc sd) { return (sd == SRC) ? &src() : &m_dst; } LLOperand * get(opLoc sd) { return (sd == SRC) ? &src() : &m_dst; }
ICODE * m_link;
}; };
struct ADDRESS {
};
struct BinaryArea {
ADDRESS start;
ADDRESS fin;
};
#include <boost/icl/interval_set.hpp>
#include <boost/icl/interval_map.hpp>
/* Icode definition: LOW_LEVEL and HIGH_LEVEL */ /* Icode definition: LOW_LEVEL and HIGH_LEVEL */
struct ICODE struct ICODE
@ -445,7 +440,7 @@ struct ICODE
// use llvm names at least // use llvm names at least
typedef BB MachineBasicBlock; typedef BB MachineBasicBlock;
protected: protected:
LLInst m_ll; LLInst *m_ll;
HLTYPE m_hl; HLTYPE m_hl;
MachineBasicBlock * Parent; /* BB to which this icode belongs */ MachineBasicBlock * Parent; /* BB to which this icode belongs */
bool invalid; /* Has no HIGH_LEVEL equivalent */ bool invalid; /* Has no HIGH_LEVEL equivalent */
@ -548,8 +543,8 @@ public:
DU1 du1; /* du chain 1 */ DU1 du1; /* du chain 1 */
int loc_ip; // used by CICodeRec to number ICODEs int loc_ip; // used by CICodeRec to number ICODEs
LLInst * ll() { return &m_ll;} LLInst * ll() { return m_ll;}
const LLInst * ll() const { return &m_ll;} const LLInst * ll() const { return m_ll;}
HLTYPE * hlU() { HLTYPE * hlU() {
// assert(type==HIGH_LEVEL); // assert(type==HIGH_LEVEL);
@ -589,8 +584,46 @@ public:
{ {
return hlU()->call.newStkArg(exp,opcode,pproc); return hlU()->call.newStkArg(exp,opcode,pproc);
} }
ICODE() : m_ll(this),Parent(0),invalid(false),type(NOT_SCANNED_ICODE),loc_ip(0) ICODE() :Parent(0),invalid(false),type(NOT_SCANNED_ICODE),loc_ip(0)
{ {
m_ll = new LLInst(this);
}
~ICODE() {
delete m_ll;
}
ICODE(const ICODE &v) {
m_ll = new LLInst(*v.m_ll);
m_hl = v.m_hl;
Parent = v.Parent;
insn = v.insn;
type = v.type;
du = v.du;
du1 = v.du1;
loc_ip = v.loc_ip;
}
ICODE & operator=(const ICODE &v) {
delete m_ll;
m_ll = v.m_ll;
m_hl = v.m_hl;
Parent = v.Parent;
insn = v.insn;
type = v.type;
du = v.du;
du1 = v.du1;
loc_ip = v.loc_ip;
return *this;
}
ICODE & operator=(ICODE &&v) {
std::swap(m_ll,v.m_ll);
std::swap(m_hl,v.m_hl);
std::swap(Parent , v.Parent);
std::swap(insn , v.insn);
std::swap(type , v.type);
std::swap(du , v.du);
std::swap(du1 , v.du1);
std::swap(loc_ip , v.loc_ip);
return *this;
} }
public: public:
const MachineBasicBlock* getParent() const { return Parent; } const MachineBasicBlock* getParent() const { return Parent; }
@ -611,9 +644,9 @@ public:
class CIcodeRec : public std::list<ICODE> class CIcodeRec : public std::list<ICODE>
{ {
public: public:
CIcodeRec(); // Constructor CIcodeRec(); // Constructor
ICODE * addIcode(ICODE *pIcode); ICODE * addIcode(const ICODE * pIcode);
void SetInBB(rCODE &rang, BB* pnewBB); void SetInBB(rCODE &rang, BB* pnewBB);
bool labelSrch(uint32_t target, uint32_t &pIndex); bool labelSrch(uint32_t target, uint32_t &pIndex);
iterator labelSrch(uint32_t target); iterator labelSrch(uint32_t target);

View File

@ -36,32 +36,32 @@ struct IDX_ARRAY : public std::vector<iICODE>
enum frameType enum frameType
{ {
STK_FRAME, /* For stack vars */ STK_FRAME, /* For stack vars */
REG_FRAME, /* For register variables */ REG_FRAME, /* For register variables */
GLB_FRAME /* For globals */ GLB_FRAME /* For globals */
}; };
struct BWGLB_TYPE struct BWGLB_TYPE
{ {
int16_t seg; /* segment value */ int16_t seg; /* segment value */
int16_t off; /* offset */ int16_t off; /* offset */
eReg regi; /* optional indexed register */ eReg regi; /* optional indexed register */
} ; } ;
/* For TYPE_LONG_(UN)SIGN on the stack */ /* For TYPE_LONG_(UN)SIGN on the stack */
struct LONG_STKID_TYPE struct LONG_STKID_TYPE
{ {
int offH; /* high offset from BP */ int offH; /* high offset from BP */
int offL; /* low offset from BP */ int offL; /* low offset from BP */
LONG_STKID_TYPE(int h,int l) : offH(h),offL(l) {} LONG_STKID_TYPE(int h,int l) : offH(h),offL(l) {}
}; };
/* For TYPE_LONG_(UN)SIGN registers */ /* For TYPE_LONG_(UN)SIGN registers */
struct LONGID_TYPE struct LONGID_TYPE
{ {
protected: protected:
eReg m_h; /* high register */ eReg m_h; /* high register */
eReg m_l; /* low register */ eReg m_l; /* low register */
public: public:
void set(eReg highpart,eReg lowpart) void set(eReg highpart,eReg lowpart)
{ {
@ -75,7 +75,7 @@ public:
LONGID_TYPE(eReg h,eReg l) : m_h(h),m_l(l) {} LONGID_TYPE(eReg h,eReg l) : m_h(h),m_l(l) {}
}; };
struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */ struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */
{ {
int16_t seg; /* segment value */ int16_t seg; /* segment value */
int16_t offH; /* offset high */ int16_t offH; /* offset high */
@ -93,7 +93,7 @@ struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */
struct ID struct ID
{ {
protected: protected:
LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */ LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */
public: public:
hlType type; /* Probable type */ hlType type; /* Probable type */
bool illegal; /* Boolean: not a valid field any more */ bool illegal; /* Boolean: not a valid field any more */
@ -104,20 +104,17 @@ public:
char macro[10]; /* Macro for this identifier */ char macro[10]; /* Macro for this identifier */
QString name; /* Identifier's name */ QString name; /* Identifier's name */
union ID_UNION { /* Different types of identifiers */ union ID_UNION { /* Different types of identifiers */
friend struct ID;
protected:
LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */ LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */
public: eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */ struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */
uint8_t regOff; /* register offset (if any) */ uint8_t regOff; /* register offset (if any) */
int off; /* offset from BP */ int off; /* offset from BP */
} bwId; } bwId;
BWGLB_TYPE bwGlb; /* For TYPE_BYTE(uint16_t)_(UN)SIGN globals */ BWGLB_TYPE bwGlb; /* For TYPE_BYTE(uint16_t)_(UN)SIGN globals */
LONGGLB_TYPE longGlb; LONGGLB_TYPE longGlb;
struct { /* For TYPE_LONG_(UN)SIGN constants */ struct { /* For TYPE_LONG_(UN)SIGN constants */
uint32_t h; /* high uint16_t */ uint32_t h; /* high uint16_t */
uint32_t l; /* low uint16_t */ uint32_t l; /* low uint16_t */
} longKte; } longKte;
ID_UNION() { /*new (&longStkId) LONG_STKID_TYPE();*/} ID_UNION() { /*new (&longStkId) LONG_STKID_TYPE();*/}
} id; } id;

View File

@ -1,57 +1,132 @@
#pragma once #pragma once
#include <string>
#include <stdint.h>
#include <cassert>
#include <list>
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <unordered_set>
#include <QtCore/QString>
#include "symtab.h" #include "symtab.h"
#include "BinaryImage.h" #include "BinaryImage.h"
#include "Procedure.h" #include "Procedure.h"
#include "state.h"
#include "src/Command.h"
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <QtCore/QString>
#include <list>
#include <unordered_set>
#include <unordered_map>
#include <string>
#include <stdint.h>
#include <assert.h>
class QString; class QString;
class SourceMachine; class SourceMachine;
struct CALL_GRAPH; struct CALL_GRAPH;
class IProject struct DosLoader;
{ struct SegOffAddr {
virtual PROG *binary()=0; uint16_t seg;
virtual const QString & project_name() const =0; uint32_t addr;
virtual const QString & binary_path() const =0;
}; };
class Project : public IProject 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);
default:
return "xxx";
}
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());
case eUnknownVendor:
return "xxx";
}
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';
}
return 'x';
}
};
class Project : public QObject
{ {
static Project *s_instance; Q_OBJECT
QString m_fname;
QString m_project_name;
QString m_output_path;
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
CALL_GRAPH * callGraph; //!< Pointer to the head of the call graph
STATE m_entry_state; //!< Machine state at program load
typedef std::list<Function> FunctionListType; PROG prog; /* Loaded program image parameters */
typedef FunctionListType lFunction; CommandStream m_project_command_stream;
typedef FunctionListType::iterator ilFunction; std::unordered_map<PtrFunction,CommandStream> m_function_streams;
SYMTAB symtab; /* Global symbol table */ bool m_error_state;
FunctionListType pProcList; struct PatternLocator *m_pattern_locator;
CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */ public:
PROG prog; /* Loaded program image parameters */ // prevent Project instance copying
// no copies
Project(const Project&) = delete; Project(const Project&) = delete;
const Project & operator=(const Project & l) =delete; const Project & operator=(const Project & l) =delete;
// only moves // only moves
Project(); // default constructor, Project(); // default constructor,
public:
void create(const QString &a); void create(const QString &a);
bool load();
bool addLoadCommands(QString fname);
void processAllCommands();
void resetCommandsAndErrorState();
const QString & output_path() const {return m_output_path;} const QString & output_path() const {return m_output_path;}
const QString & project_name() const {return m_project_name;} const QString & project_name() const {return m_project_name;}
const QString & binary_path() const {return m_fname;} const QString & binary_path() const {return m_fname;}
QString output_name(const char *ext); QString output_name(const char *ext);
ilFunction funcIter(Function *to_find); ilFunction funcIter(Function *to_find);
ilFunction findByEntry(uint32_t entry); PtrFunction findByEntry(uint32_t entry);
ilFunction createFunction(FunctionType *f, const QString & name); PtrFunction findByName(const QString &name);
PtrFunction createFunction(FunctionType *f, const QString & name, SegOffAddr addr);
bool valid(ilFunction iter); bool valid(ilFunction iter);
int getSymIdxByAdd(uint32_t adr); int getSymIdxByAdd(uint32_t adr);
@ -61,14 +136,39 @@ 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();
const FunctionListType &functions() const { return pProcList; } const FunctionListType &functions() const { return pProcList; }
FunctionListType &functions() { return pProcList; } FunctionListType &functions() { return pProcList; }
bool addCommand(Command *cmd);
bool addCommand(PtrFunction f, Command *cmd); // Add function level command
bool hasCommands(const PtrFunction &f);
CommandStream *functionCommands(const PtrFunction &f);
void dumpAllErrors();
void setLoader(DosLoader *ins);
void processCommands(int count=1);
void processFunctionCommands(const PtrFunction & func, int count);
public slots:
void onCommandStreamFinished(bool state);
signals:
void newFunctionCreated(PtrFunction);
void functionUpdate(const PtrFunction &);
void loaderSelected();
void commandListChanged();
protected: protected:
void initialize(); void initialize();
void writeGlobSymTable(); void writeGlobSymTable();
protected:
static Project * s_instance;
QString m_fname;
QString m_project_name;
QString m_output_path;
CommandContext m_command_ctx;
}; };
//extern Project g_proj;

View File

@ -3,21 +3,22 @@
* (C) Cristina Cifuentes, Mike van Emmerik * (C) Cristina Cifuentes, Mike van Emmerik
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <stdint.h>
#include <cstring>
#include "machine_x86.h" #include "machine_x86.h"
#include <stdint.h>
#include <string.h>
/* STATE TABLE */ /* STATE TABLE */
struct STATE struct STATE
{ {
uint32_t IP; /* Offset into Image */ uint32_t IP; /* Offset into Image */
int16_t r[INDEX_BX_SI]; /* Value of segs and AX */ int16_t r[INDEX_BX_SI]; /* Register values */
bool f[INDEX_BX_SI]; /* True if r[.] has a value */ bool f[INDEX_BX_SI]; /* True if r[.] has a value */
struct struct
{ /* For case stmt indexed reg */ { /* For case stmt indexed reg */
uint8_t regi; /* Last conditional jump */ uint8_t regi; /* Last conditional jump */
int16_t immed; /* Contents of the previous register */ int16_t immed; /* Contents of the previous register */
} JCond; } JCond;
void setState(uint16_t reg, int16_t value); void setState(uint16_t reg, int16_t value);
void checkStartup(); void checkStartup();
bool isKnown(eReg v) {return f[v];} bool isKnown(eReg v) {return f[v];}

View File

@ -9,7 +9,11 @@
#include <QtCore/QString> #include <QtCore/QString>
#include <string> #include <string>
#include <vector>
#include <stdint.h> #include <stdint.h>
class QTextStream;
struct Expr; struct Expr;
struct AstIdent; struct AstIdent;
struct TypeContainer; struct TypeContainer;
@ -18,10 +22,10 @@ struct TypeContainer;
/* * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * */
struct SymbolCommon struct SymbolCommon
{ {
QString name; /* New name for this variable/symbol/argument */ QString name; /* New name for this variable/symbol/argument */
int size; /* Size/maximum size */ int size; /* Size/maximum size */
hlType type; /* probable type */ hlType type; /* probable type */
eDuVal duVal; /* DEF, USE, VAL */ eDuVal duVal; /* DEF, USE, VAL */
SymbolCommon() : size(0),type(TYPE_UNKNOWN) SymbolCommon() : size(0),type(TYPE_UNKNOWN)
{} {}
}; };
@ -39,13 +43,14 @@ struct SYM : public SymbolCommon
struct STKSYM : public SymbolCommon struct STKSYM : public SymbolCommon
{ {
typedef int16_t tLabel; typedef int16_t tLabel;
Expr * actual=0; /* Expression tree of actual parameter */ Expr * actual=0; /* Expression tree of actual parameter */
AstIdent * regs=0; /* For register arguments only */ AstIdent * regs=0; /* For register arguments only */
tLabel label=0; /* Immediate off from BP (+:args, -:params) */ tLabel label=0; /* Immediate off from BP (+:args, -:params) */
uint8_t regOff=0; /* Offset is a register (e.g. SI, DI) */ uint8_t regOff=0; /* Offset is a register (e.g. SI, DI) */
bool hasMacro=false; /* This type needs a macro */ bool hasMacro=false; /* This type needs a macro */
QString macro; /* Macro name */ QString macro; /* Macro name */
bool invalid=false; /* Boolean: invalid entry in formal arg list*/ bool invalid=false; /* Boolean: invalid entry in formal arg list*/
int arrayMembers=1; // for local variables if >1 marks this stack symbol as an array
void setArgName(int i) void setArgName(int i)
{ {
char buf[32]; char buf[32];
@ -81,7 +86,7 @@ public:
void updateSymType(uint32_t symbol, const TypeContainer &tc); void updateSymType(uint32_t symbol, const TypeContainer &tc);
SYM *updateGlobSym(uint32_t operand, int size, uint16_t duFlag, bool &inserted_new); SYM *updateGlobSym(uint32_t operand, int size, uint16_t duFlag, bool &inserted_new);
}; };
struct Function; class Function;
struct SYMTABLE struct SYMTABLE
{ {
std::string pSymName; /* Ptr to symbolic name or comment */ std::string pSymName; /* Ptr to symbolic name or comment */
@ -101,9 +106,9 @@ struct SYMTABLE
enum tableType /* The table types */ enum tableType /* The table types */
{ {
Label=0, /* The label table */ Label=0, /* The label table */
Comment /* The comment table */ Comment, /* The comment table */
NUM_TABLE_TYPES /* Number of entries: must be last */
}; };
constexpr int NUM_TABLE_TYPES = int(Comment)+1; /* Number of entries: must be last */
void createSymTables(void); void createSymTables(void);
void destroySymTables(void); void destroySymTables(void);

View File

@ -105,6 +105,8 @@ struct TypeContainer
return 4; return 4;
case TYPE_FLOAT: case TYPE_FLOAT:
return 4; return 4;
case TYPE_PTR:
return 2;
default: default:
return ~0; return ~0;
} }

BIN
sigs/dccb3l.sig Normal file

Binary file not shown.

BIN
sigs/dccb3s.SIG Normal file

Binary file not shown.

6
src/Address.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
typedef uint32_t LinearAddress;
#define INVALID_ADDR Address(~0U)

60
src/AutomatedPlanner.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "AutomatedPlanner.h"
#include "project.h"
#include "FollowControlFlow.h"
#include <QtCore/QDebug>
/**
* @class AutomatedPlanner
* @brief Class responsible for building command lists
*
* The goal for top level [Project] plan is to build a fully decompiled representation of source binaries
*/
AutomatedPlanner::AutomatedPlanner()
{
}
/**
* @brief Given a state of a project, add actions that will advance the decompilation
* @param project
*/
void AutomatedPlanner::planFor(Project &project) {
// TODO: For now this logic is sprinkled all over the place, should move it here
// IF NO BINARY IMAGE LOADED - > add SelectImage/SelectProject command
// IF NO LOADER SELECTED -> add SelectLoader command
// ...
}
void AutomatedPlanner::planFor(Function & func) {
if(func.doNotDecompile())
return; // for functions marked as non-decompileable we don't add any commands
//TODO: Consider cases where commands are queued, but we can still plan some additional steps
bool function_has_commands = Project::get()->hasCommands(func.shared_from_this());
if(function_has_commands) {
qDebug() << "Function "<<func.name<<"still has some commands queued, planning skipped";
}
switch(func.nStep) {
case eNotDecoded:
addAction(func,new FollowControlFlow(func.state));
break;
case eDisassemblyInProgress:
// The command queue is empty and function is in eDisassemblyInProgress state ? Switch to eDisassembled
assert(false and "Not implemented yet");
break;
case eDissassembled:
// addAction(func,new LowLevelMarkImpure(func)
assert(false and "Not implemented yet");
break;
}
}
void AutomatedPlanner::addAction(Function & func, Command * cmd)
{
Project::get()->addCommand(func.shared_from_this(),cmd);
}
void AutomatedPlanner::addAction(Project & func, Command * cmd)
{
func.addCommand(cmd);
}

20
src/AutomatedPlanner.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef AUTOMATEDPLANNER_H
#define AUTOMATEDPLANNER_H
class Project;
class Function;
class Command;
class AutomatedPlanner
{
public:
AutomatedPlanner();
void planFor(Project & project);
void planFor(Function & func);
protected:
void addAction(Function &func,Command *cmd);
void addAction(Project &func,Command *cmd);
};
#endif // AUTOMATEDPLANNER_H

View File

@ -28,7 +28,7 @@ BB *BB::Create(const rCODE &r,eBBKind _nodeType, Function *parent)
{ {
BB* pnewBB; BB* pnewBB;
pnewBB = new BB; pnewBB = new BB;
pnewBB->nodeType = _nodeType; /* Initialise */ pnewBB->nodeType = _nodeType; /* Initialise */
pnewBB->immedDom = NO_DOM; pnewBB->immedDom = NO_DOM;
pnewBB->loopHead = pnewBB->caseHead = pnewBB->caseTail = pnewBB->loopHead = pnewBB->caseHead = pnewBB->caseTail =
pnewBB->latchNode= pnewBB->loopFollow = NO_NODE; pnewBB->latchNode= pnewBB->loopFollow = NO_NODE;
@ -46,7 +46,7 @@ BB *BB::Create(const rCODE &r,eBBKind _nodeType, Function *parent)
parent->m_actual_cfg.push_back(pnewBB); parent->m_actual_cfg.push_back(pnewBB);
pnewBB->Parent = parent; pnewBB->Parent = parent;
if ( r.begin() != parent->Icode.end() ) /* Only for code BB's */ if ( r.begin() != parent->Icode.end() ) /* Only for code BB's */
stats.numBBbef++; stats.numBBbef++;
} }
return pnewBB; return pnewBB;
@ -201,12 +201,12 @@ bool BB::isEndOfPath(int latch_node_idx) const
} }
void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode, int _ifFollow) void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode, int _ifFollow)
{ {
int follow; /* ifFollow */ int follow; /* ifFollow */
BB * succ, *latch; /* Successor and latching node */ BB * succ, *latch; /* Successor and latching node */
ICODE * picode; /* Pointer to HLI_JCOND instruction */ ICODE * picode; /* Pointer to HLI_JCOND instruction */
QString l; /* Pointer to HLI_JCOND expression */ QString l; /* Pointer to HLI_JCOND expression */
bool emptyThen, /* THEN clause is empty */ bool emptyThen, /* THEN clause is empty */
repCond; /* Repeat condition for while() */ repCond; /* Repeat condition for while() */
/* Check if this basic block should be analysed */ /* Check if this basic block should be analysed */
if ((_ifFollow != UN_INIT) and (this == pProc->m_dfsLast[_ifFollow])) if ((_ifFollow != UN_INIT) and (this == pProc->m_dfsLast[_ifFollow]))
@ -236,10 +236,10 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
return; return;
/* Check type of loop/node and process code */ /* Check type of loop/node and process code */
if ( loopType!=eNodeHeaderType::NO_TYPE ) /* there is a loop */ if ( loopType!=eNodeHeaderType::NO_TYPE ) /* there is a loop */
{ {
assert(latch); assert(latch);
if (this != latch) /* loop is over several bbs */ if (this != latch) /* loop is over several bbs */
{ {
if (loopType == eNodeHeaderType::WHILE_TYPE) if (loopType == eNodeHeaderType::WHILE_TYPE)
{ {
@ -251,7 +251,7 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
succ = edges[0].BBptr; succ = edges[0].BBptr;
if (succ->traversed != DFS_ALPHA) if (succ->traversed != DFS_ALPHA)
succ->writeCode (indLevel, pProc, numLoc, latch->dfsLastNum,_ifFollow); succ->writeCode (indLevel, pProc, numLoc, latch->dfsLastNum,_ifFollow);
else /* has been traversed so we need a goto */ else /* has been traversed so we need a goto */
succ->front().ll()->emitGotoLabel (indLevel); succ->front().ll()->emitGotoLabel (indLevel);
} }
@ -293,20 +293,20 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
succ = pProc->m_dfsLast[loopFollow]; succ = pProc->m_dfsLast[loopFollow];
if (succ->traversed != DFS_ALPHA) if (succ->traversed != DFS_ALPHA)
succ->writeCode (indLevel, pProc, numLoc, _latchNode, _ifFollow); succ->writeCode (indLevel, pProc, numLoc, _latchNode, _ifFollow);
else /* has been traversed so we need a goto */ else /* has been traversed so we need a goto */
succ->front().ll()->emitGotoLabel (indLevel); succ->front().ll()->emitGotoLabel (indLevel);
} }
} }
else /* no loop, process nodeType of the graph */ else /* no loop, process nodeType of the graph */
{ {
if (nodeType == TWO_BRANCH) /* if-then[-else] */ if (nodeType == TWO_BRANCH) /* if-then[-else] */
{ {
stats.numHLIcode++; stats.numHLIcode++;
indLevel++; indLevel++;
emptyThen = false; emptyThen = false;
if (ifFollow != MAX) /* there is a follow */ if (ifFollow != MAX) /* there is a follow */
{ {
/* process the THEN part */ /* process the THEN part */
follow = ifFollow; follow = ifFollow;
@ -319,7 +319,7 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
cCode.appendCode( "\n%s%s", indentStr(indLevel-1), qPrintable(l)); cCode.appendCode( "\n%s%s", indentStr(indLevel-1), qPrintable(l));
succ->writeCode (indLevel, pProc, numLoc, _latchNode,follow); succ->writeCode (indLevel, pProc, numLoc, _latchNode,follow);
} }
else /* empty THEN part => negate ELSE part */ else /* empty THEN part => negate ELSE part */
{ {
l = writeJcondInv ( *back().hl(), pProc, numLoc); l = writeJcondInv ( *back().hl(), pProc, numLoc);
cCode.appendCode( "\n%s%s", indentStr(indLevel-1), qPrintable(l)); cCode.appendCode( "\n%s%s", indentStr(indLevel-1), qPrintable(l));
@ -332,9 +332,9 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
/* process the ELSE part */ /* process the ELSE part */
succ = edges[ELSE].BBptr; succ = edges[ELSE].BBptr;
if (succ->traversed != DFS_ALPHA) /* not visited */ if (succ->traversed != DFS_ALPHA) /* not visited */
{ {
if (succ->dfsLastNum != follow) /* ELSE part */ if (succ->dfsLastNum != follow) /* ELSE part */
{ {
cCode.appendCode( "%s}\n%selse {\n", cCode.appendCode( "%s}\n%selse {\n",
indentStr(indLevel-1), indentStr(indLevel - 1)); indentStr(indLevel-1), indentStr(indLevel - 1));
@ -355,7 +355,7 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
if (succ->traversed != DFS_ALPHA) if (succ->traversed != DFS_ALPHA)
succ->writeCode (indLevel, pProc, numLoc, _latchNode,_ifFollow); succ->writeCode (indLevel, pProc, numLoc, _latchNode,_ifFollow);
} }
else /* no follow => if..then..else */ else /* no follow => if..then..else */
{ {
l = writeJcond ( *back().hl(), pProc, numLoc); l = writeJcond ( *back().hl(), pProc, numLoc);
cCode.appendCode( "%s%s", indentStr(indLevel-1), qPrintable(l)); cCode.appendCode( "%s%s", indentStr(indLevel-1), qPrintable(l));
@ -368,7 +368,7 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
else /* fall, call, 1w */ else /* fall, call, 1w */
{ {
succ = edges[0].BBptr; /* fall-through edge */ succ = edges[0].BBptr; /* fall-through edge */
assert(succ->size()>0); assert(succ->size()>0);
if (succ->traversed != DFS_ALPHA) if (succ->traversed != DFS_ALPHA)
{ {
@ -379,8 +379,8 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
} }
/* Writes the code for the current basic block. /* Writes the code for the current basic block.
* Args: pBB: pointer to the current basic block. * Args: pBB: pointer to the current basic block.
* Icode: pointer to the array of icodes for current procedure. * Icode: pointer to the array of icodes for current procedure.
* lev: indentation level - used for formatting. */ * lev: indentation level - used for formatting. */
void BB::writeBB(QTextStream &ostr,int lev, Function * pProc, int *numLoc) void BB::writeBB(QTextStream &ostr,int lev, Function * pProc, int *numLoc)
{ {
/* Save the index into the code table in case there is a later goto /* Save the index into the code table in case there is a later goto

View File

@ -1,13 +1,131 @@
SET(dcc_test_SOURCES set(dcc_LIB_SOURCES
tests/comwrite.cpp CallConvention.cpp
tests/project.cpp ast.cpp
tests/loader.cpp backend.cpp
bundle.cpp
chklib.cpp
comwrite.cpp
control.cpp
dataflow.cpp
disassem.cpp
DccFrontend.cpp
error.cpp
fixwild.cpp
graph.cpp
hlicode.cpp
hltype.cpp
machine_x86.cpp
icode.cpp
RegisterNode
idioms.cpp
idioms/idiom1.cpp
idioms/arith_idioms.cpp
idioms/call_idioms.cpp
idioms/epilogue_idioms.cpp
idioms/mov_idioms.cpp
idioms/neg_idioms.cpp
idioms/shift_idioms.cpp
idioms/xor_idioms.cpp
locident.cpp
liveness_set.cpp
parser.h
parser.cpp
procs.cpp
project.cpp
Procedure.cpp
proplong.cpp
reducible.cpp
scanner.cpp
symtab.cpp
udm.cpp
BasicBlock.cpp
dcc_interface.cpp
MemoryChunk
MemorySegment
MemorySegmentCoordinator
Command.cpp
Command.h
Loaders.cpp
Loaders.h
FollowControlFlow.cpp
FollowControlFlow.h
AutomatedPlanner
)
set(dcc_UI_SOURCES
ui/DccMainWindow.ui
ui/DccMainWindow.h
ui/DccMainWindow.cpp
ui/FunctionViewWidget.ui
ui/FunctionViewWidget.h
ui/FunctionViewWidget.cpp
ui/FunctionListDockWidget.ui
ui/FunctionListDockWidget.cpp
ui/FunctionListDockWidget.h
ui/RenderTags.cpp
ui/RenderTags.h
ui/CommandQueueView.cpp
ui/CommandQueueView.h
ui/CommandQueueView.ui
)
set(dcc_HEADERS
../include/ast.h
../include/bundle.h
../include/BinaryImage.h
../include/DccFrontend.h
../include/Enums.h
../include/dcc.h
../include/disassem.h
../include/dosdcc.h
../include/error.h
../include/graph.h
../include/hlicode.h
../include/machine_x86.h
../include/icode.h
../include/idioms/idiom.h
../include/idioms/idiom1.h
../include/idioms/arith_idioms.h
../include/idioms/call_idioms.h
../include/idioms/epilogue_idioms.h
../include/idioms/mov_idioms.h
../include/idioms/neg_idioms.h
../include/idioms/shift_idioms.h
../include/idioms/xor_idioms.h
../include/locident.h
../include/CallConvention.h
../include/project.h
../include/scanner.h
../include/state.h
../include/symtab.h
../include/types.h
../include/Procedure.h
../include/StackFrame.h
../include/BasicBlock.h
../include/dcc_interface.h
) )
include_directories(${GMOCK_INCLUDE_DIRS} ${GMOCK_ROOT}/gtest/include)
add_executable(tester ${dcc_test_SOURCES})
ADD_DEPENDENCIES(tester dcc_lib)
target_link_libraries(tester dcc_lib disasm_s SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
${GMOCK_BOTH_LIBRARIES} ${REQ_LLVM_LIBRARIES})
add_test(dcc-tests tester) set(dcc_SOURCES
dcc.cpp
)
SOURCE_GROUP(Source FILES ${dcc_SOURCES} ${dcc_LIB_SOURCES})
ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS})
qt5_use_modules(dcc_lib Core)
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)
qt5_use_modules(dcc_original Core Widgets)
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD 11)
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD_REQUIRED ON)
if(dcc_build_tests)
ADD_SUBDIRECTORY(tests)
endif()

View File

@ -1,9 +1,89 @@
#include "CallConvention.h"
#include "Procedure.h"
#include <QtCore/QTextStream>
#include <ostream> #include <ostream>
#include <cassert> #include <cassert>
#include "CallConvention.h" static void calculateReturnLocations(Function *func) {
#include <QtCore/QTextStream> switch(func->getReturnType()) {
case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN:
func->getFunctionType()->setReturnLocation(LONGID_TYPE(rDX,rAX));
break;
case TYPE_WORD_SIGN:
case TYPE_WORD_UNSIGN:
func->getFunctionType()->setReturnLocation(rAX);
break;
case TYPE_BYTE_SIGN:
case TYPE_BYTE_UNSIGN:
func->getFunctionType()->setReturnLocation(rAL);
break;
}
}
static void calculateArgLocations_allOnStack(Function *func) {
FunctionType *type = func->type;
int stack_offset=2;
if(func->args.size() == type->ContainedTys.size())
return;
func->args.resize(type->ContainedTys.size());
func->args.numArgs=0;
for(Type & argtype : type->ContainedTys) {
STKSYM &arg(func->args[func->args.numArgs]);
arg.label= stack_offset;
arg.size = TypeContainer::typeSize(argtype.dcc_type);
arg.type = argtype.dcc_type;
arg.setArgName(func->args.numArgs);
stack_offset+=arg.size;
func->args.m_maxOff=stack_offset;
func->args.numArgs++;
}
func->cbParam = stack_offset;
}
CConv *CConv::create(Type v) static void rebuildArguments_FromStackLayout(Function *func) {
STKFRAME &stk(func->args);
std::map<int,const STKSYM *> arg_locations;
FunctionType *f;
for(const STKSYM & s: stk) {
if(s.label>0) {
arg_locations[s.label] = &s;
}
}
if(arg_locations.empty())
return;
std::vector<Type> argtypes;
auto stack_loc_iter = arg_locations.begin();
for(int i=stack_loc_iter->first; i<=arg_locations.rbegin()->first; ) {
int till_next_loc=stack_loc_iter->first-i;
if(till_next_loc==0) {
int entry_size=stack_loc_iter->second->size;
argtypes.push_back({stack_loc_iter->second->type});
i+=entry_size;
++stack_loc_iter;
} else {
if(till_next_loc>=4) {
argtypes.push_back({TYPE_LONG_SIGN});
i+=4;
} else if(till_next_loc>=2) {
argtypes.push_back({TYPE_WORD_SIGN});
i+=2;
} else {
argtypes.push_back({TYPE_BYTE_SIGN});
i+=1;
}
}
}
f = FunctionType::get({func->type->getReturnType()},argtypes,func->type->isVarArg());
f->retVal = func->type->retVal;
delete func->type;
func->type = f;
}
CConv *CConv::create(CC_Type v)
{ {
static C_CallingConvention *c_call = nullptr; static C_CallingConvention *c_call = nullptr;
static Pascal_CallingConvention *p_call = nullptr; static Pascal_CallingConvention *p_call = nullptr;
@ -27,11 +107,31 @@ void C_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * C calling convention.\n"; ostr << " * C calling convention.\n";
} }
void C_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Pascal_CallingConvention::writeComments(QTextStream & ostr) void Pascal_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * Pascal calling convention.\n"; ostr << " * Pascal calling convention.\n";
} }
void Pascal_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
//TODO: pascal args are passed in reverse order ?
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Unknown_CallingConvention::writeComments(QTextStream & ostr) void Unknown_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * Unknown calling convention.\n"; ostr << " * Unknown calling convention.\n";
} }
void Unknown_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}

138
src/Command.cpp Normal file
View File

@ -0,0 +1,138 @@
#include "Command.h"
#include "DccFrontend.h"
#include "dcc.h"
#include "project.h"
#include "Loaders.h"
#include <QFile>
bool LoaderSelection::execute(CommandContext * ctx)
{
Project *proj=ctx->m_project;
if(nullptr==proj) {
ctx->recordFailure(this,"No active project ");
return false;
}
if(m_filename.isEmpty()) {
ctx->recordFailure(this,"No executable path given to loader selector");
return false;
}
QFile finfo(m_filename);
/* Open the input file */
if(not finfo.open(QFile::ReadOnly)) {
ctx->recordFailure(this,QString("Cannot open file %1").arg(m_filename));
return false;
}
/* Read in first 2 bytes to check EXE signature */
if (finfo.size()<=2)
{
ctx->recordFailure(this,QString("File %1 is too small").arg(m_filename));
}
ComLoader com_loader;
ExeLoader exe_loader;
if(exe_loader.canLoad(finfo)) {
proj->setLoader(new ExeLoader);
return true;
}
if(com_loader.canLoad(finfo)) {
proj->setLoader(new ComLoader);
return true;
}
ctx->recordFailure(this,QString("None of the available loaders can load file %1").arg(m_filename));
return true;
}
bool LoaderApplication::execute(CommandContext * ctx)
{
Project *proj=ctx->m_project;
if(nullptr==proj) {
ctx->recordFailure(this,"No active project ");
return false;
}
if(!proj->m_selected_loader) {
ctx->recordFailure(this,QString("No loader selected for project %1").arg(proj->project_name()));
return false;
}
QFile finfo(m_filename);
if(not finfo.open(QFile::ReadOnly)) {
ctx->recordFailure(this,QString("Cannot open file %1").arg(m_filename));
return false;
}
bool load_res = proj->m_selected_loader->load(proj->prog,finfo);
if(!load_res) {
ctx->recordFailure(this,QString("Failure during load: %1").arg(m_filename));
return false;
}
if (option.verbose)
proj->prog.displayLoadInfo();
FunctionType *main_type = FunctionType::get(Type{TYPE_UNKNOWN},{ },false);
main_type->setCallingConvention(CConv::UNKNOWN);
/* Create initial procedure at program start address */
PROG &prog(proj->prog);
CreateFunction *cmd = new CreateFunction("start",
SegOffAddr {prog.segMain,((uint32_t)prog.initCS << 4) + prog.initIP},
main_type);
proj->addCommand(cmd);
return true;
}
bool CommandStream::add(Command * c) {
if(m_commands.size()>=m_maximum_command_count)
return false;
m_commands.push_back(c);
return true;
}
void CommandStream::setMaximumCommandCount(int maximum_command_count) {
m_maximum_command_count = maximum_command_count;
}
void CommandStream::processAll(CommandContext *ctx)
{
while(not m_commands.isEmpty()) {
Command *cmd = m_commands.takeFirst();
if(false==cmd->execute(ctx)) {
emit streamCompleted(false);
break;
}
m_recently_executed.push_back(cmd);
}
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);
qDeleteAll(m_recently_executed);
m_commands.clear();
m_recently_executed.clear();
}
void CommandContext::reset()
{
for(int i=0; i<m_failures.size(); ++i) {
delete m_failures[i].first;
}
m_failures.clear();
}

95
src/Command.h Normal file
View File

@ -0,0 +1,95 @@
#ifndef COMMAND_H
#define COMMAND_H
#include <memory>
#include <QtCore/QObject>
#include <QtCore/QVector>
#include <QtCore/QPair>
class Project;
class Function;
typedef std::shared_ptr<Function> PtrFunction;
enum CommandLevel {
eProject,
eBinary,
eFunction,
eBasicBlock,
eInstruction
};
class Command;
class CommandContext {
public:
void recordFailure(Command *cmd,QString error_message) {
m_failures.push_back({cmd,error_message});
}
Project *m_project;
PtrFunction m_func;
QVector<QPair<Command *,QString>> m_failures;
void reset();
};
class Command
{
QString m_command_name;
CommandLevel m_level;
public:
Command(QString n,CommandLevel level) : m_command_name(n),m_level(level) {}
virtual ~Command() {}
QString name() const { return m_command_name;}
virtual QString instanceDescription() const { return m_command_name; }
virtual bool execute(CommandContext *) { return false; }
};
class CompoundCommand : public Command {
QVector<Command *> m_contained;
public:
CompoundCommand(QString n,CommandLevel l) : Command(n,l) {
}
void addCommand(Command *c) {
m_contained.push_back(c);
}
bool execute(CommandContext * ctx) {
for(Command * c : m_contained) {
if(!c->execute(ctx))
return false;
}
return true;
}
};
class CommandStream : public QObject
{
Q_OBJECT
int m_maximum_command_count=5;
public:
QVector<Command *> m_recently_executed;
QVector<Command *> m_commands;
bool add(Command *c);
void setMaximumCommandCount(int maximum_command_count);
bool processOne(CommandContext *ctx);
void processAll(CommandContext *ctx);
void clear();
bool isEmpty() const { return m_commands.isEmpty(); }
signals:
void streamCompleted(bool success);
void streamChanged();
};
// Effect: loader has been selected and set in current project
class LoaderSelection : public Command {
QString m_filename;
public:
virtual ~LoaderSelection() {}
LoaderSelection(QString f) : Command("Select loader",eProject),m_filename(f) {}
bool execute(CommandContext * ctx) override;
};
// trigger Project->m_selected_loader has changed
// Effect: the PROG object is loaded using the current loader
class LoaderApplication : public Command {
QString m_filename;
public:
virtual ~LoaderApplication() {}
LoaderApplication(QString f) : Command("Apply loader",eProject),m_filename(f) {}
bool execute(CommandContext * ctx) override;
};
#endif // COMMAND_H

View File

@ -1,60 +1,19 @@
#include "DccFrontend.h" #include "DccFrontend.h"
#include "Loaders.h"
#include "dcc.h" #include "dcc.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "project.h" #include "project.h"
#include "disassem.h" #include "disassem.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "Command.h"
#include "chklib.h"
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <cstdio> #include <cstdio>
class Loader
{
bool loadIntoProject(IProject *);
};
struct PSP { /* PSP structure */
uint16_t int20h; /* interrupt 20h */
uint16_t eof; /* segment, end of allocation block */
uint8_t res1; /* reserved */
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
uint8_t int22h[4]; /* vector for terminate routine */
uint8_t int23h[4]; /* vector for ctrl+break routine */
uint8_t int24h[4]; /* vector for error routine */
uint8_t res2[22]; /* reserved */
uint16_t segEnv; /* segment address of environment block */
uint8_t res3[34]; /* reserved */
uint8_t int21h[6]; /* opcode for int21h and far return */
uint8_t res4[6]; /* reserved */
uint8_t fcb1[16]; /* default file control block 1 */
uint8_t fcb2[16]; /* default file control block 2 */
uint8_t res5[4]; /* reserved */
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
};
static struct MZHeader { /* EXE file header */
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
uint8_t sigHi;
uint16_t lastPageSize; /* Size of the last page */
uint16_t numPages; /* Number of pages in the file */
uint16_t numReloc; /* Number of relocation items */
uint16_t numParaHeader; /* # of paragraphs in the header */
uint16_t minAlloc; /* Minimum number of paragraphs */
uint16_t maxAlloc; /* Maximum number of paragraphs */
uint16_t initSS; /* Segment displacement of stack */
uint16_t initSP; /* Contents of SP at entry */
uint16_t checkSum; /* Complemented checksum */
uint16_t initIP; /* Contents of IP at entry */
uint16_t initCS; /* Segment displacement of code */
uint16_t relocTabOffset; /* Relocation table offset */
uint16_t overlayNum; /* Overlay number */
} header;
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
//static void LoadImage(char *filename); //static void LoadImage(char *filename);
static void displayMemMap(void); static void displayMemMap(void);
/**************************************************************************** /****************************************************************************
@ -62,19 +21,19 @@ static void displayMemMap(void);
***************************************************************************/ ***************************************************************************/
void PROG::displayLoadInfo(void) void PROG::displayLoadInfo(void)
{ {
int i; int i;
printf("File type is %s\n", (fCOM)?"COM":"EXE"); printf("File type is %s\n", (fCOM)?"COM":"EXE");
if (not fCOM) { // if (not fCOM) {
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi); // printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize)); // printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
printf("File size / 512 = %04X pages\n", LH(&header.numPages)); // printf("File size / 512 = %04X pages\n", LH(&header.numPages));
printf("# relocation items = %04X\n", LH(&header.numReloc)); // printf("# relocation items = %04X\n", LH(&header.numReloc));
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader)); // printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc)); // printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc)); // printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
} // }
printf("Load image size = %08lX\n", cbImage - sizeof(PSP)); printf("Load image size = %08lX\n", cbImage); // - sizeof(PSP)
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP); printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP); printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
@ -96,7 +55,7 @@ static void fill(int ip, char *bf)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
static uint8_t type[4] = {'.', 'd', 'c', 'x'}; static uint8_t type[4] = {'.', 'd', 'c', 'x'};
uint8_t i; uint8_t i;
for (i = 0; i < 16; i++, ip++) for (i = 0; i < 16; i++, ip++)
{ {
@ -114,7 +73,7 @@ static void displayMemMap(void)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
char c, b1[33], b2[33], b3[33]; char c, b1[33], b2[33], b3[33];
uint8_t i; uint8_t i;
int ip = 0; int ip = 0;
@ -125,10 +84,10 @@ static void displayMemMap(void)
printf("%06X %s\n", ip, b1); printf("%06X %s\n", ip, b1);
ip += 16; ip += 16;
for (i = 3, c = b1[1]; i < 32 and c == b1[i]; i += 2) for (i = 3, c = b1[1]; i < 32 and c == b1[i]; i += 2)
; /* Check if all same */ ; /* Check if all same */
if (i > 32) if (i > 32)
{ {
fill(ip, b2); /* Skip until next two are not same */ fill(ip, b2); /* Skip until next two are not same */
fill(ip+16, b3); fill(ip+16, b3);
if (not (strcmp(b1, b2) || strcmp(b1, b3))) if (not (strcmp(b1, b2) || strcmp(b1, b3)))
{ {
@ -166,249 +125,106 @@ bool DccFrontend::FrontEnd ()
/* Search through code looking for impure references and flag them */ /* Search through code looking for impure references and flag them */
Disassembler ds(1); Disassembler ds(1);
for(Function &f : Project::get()->pProcList) for(PtrFunction &f : Project::get()->pProcList)
{ {
f.markImpure(); f->markImpure();
if (option.asm1) if (option.asm1)
{ {
ds.disassem(&f); ds.disassem(f);
} }
} }
if (option.Interact) if (option.Interact)
{ {
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */ interactDis(Project::get()->pProcList.front(), 0); /* Interactive disassembler */
} }
/* Converts jump target addresses to icode offsets */ /* Converts jump target addresses to icode offsets */
for(Function &f : Project::get()->pProcList) for(PtrFunction &f : Project::get()->pProcList)
{ {
f.bindIcodeOff(); f->bindIcodeOff();
} }
/* Print memory bitmap */ /* Print memory bitmap */
if (option.Map) if (option.Map)
displayMemMap(); displayMemMap();
return(true); // we no longer own proj ! return(true); // we no longer own proj !
} }
struct DosLoader {
protected:
void prepareImage(PROG &prog,size_t sz,QFile &fp) {
/* Allocate a block of memory for the program. */
prog.cbImage = sz + sizeof(PSP);
prog.Imagez = new uint8_t [prog.cbImage];
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
prog.Imagez[1] = 0x20; /* for termination checking */
/* Read in the image past where a PSP would go */
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
}
};
struct ComLoader : public DosLoader {
bool canLoad(QFile &fp) {
fp.seek(0);
char sig[2];
if(2==fp.read(sig,2)) {
return not (sig[0] == 0x4D and sig[1] == 0x5A);
}
return false;
}
bool load(PROG &prog,QFile &fp) {
fp.seek(0);
/* COM file
* In this case the load module size is just the file length
*/
auto cb = fp.size();
/* COM programs start off with an ORG 100H (to leave room for a PSP)
* This is also the implied start address so if we load the image
* at offset 100H addresses should all line up properly again.
*/
prog.initCS = 0;
prog.initIP = 0x100;
prog.initSS = 0;
prog.initSP = 0xFFFE;
prog.cReloc = 0;
prepareImage(prog,cb,fp);
/* Set up memory map */
cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb);
return true;
}
};
struct ExeLoader : public DosLoader {
bool canLoad(QFile &fp) {
if(fp.size()<sizeof(header))
return false;
MZHeader tmp_header;
fp.seek(0);
fp.read((char *)&tmp_header, sizeof(header));
if(not (tmp_header.sigLo == 0x4D and tmp_header.sigHi == 0x5A))
return false;
/* This is a typical DOS kludge! */
if (LH(&header.relocTabOffset) == 0x40)
{
qDebug() << "Don't understand new EXE format";
return false;
}
return true;
}
bool load(PROG &prog,QFile &fp) {
/* Read rest of header */
fp.seek(0);
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
return false;
/* Calculate the load module size.
* This is the number of pages in the file
* less the length of the header and reloc table
* less the number of bytes unused on last page
*/
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
if (header.lastPageSize)
{
cb -= 512 - LH(&header.lastPageSize);
}
/* We quietly ignore minAlloc and maxAlloc since for our
* purposes it doesn't really matter where in real memory
* the program would end up. EXE programs can't really rely on
* their load location so setting the PSP segment to 0 is fine.
* Certainly programs that prod around in DOS or BIOS are going
* to have to load DS from a constant so it'll be pretty
* obvious.
*/
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
prog.initIP = (int16_t)LH(&header.initIP);
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
prog.initSP = (int16_t)LH(&header.initSP);
prog.cReloc = (int16_t)LH(&header.numReloc);
/* Allocate the relocation table */
if (prog.cReloc)
{
prog.relocTable.resize(prog.cReloc);
fp.seek(LH(&header.relocTabOffset));
/* Read in seg:offset pairs and convert to Image ptrs */
uint8_t buf[4];
for (int i = 0; i < prog.cReloc; i++)
{
fp.read((char *)buf,4);
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
}
}
/* Seek to start of image */
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
fp.seek(start_of_image);
/* Allocate a block of memory for the program. */
prepareImage(prog,cb,fp);
/* Set up memory map */
cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb);
/* Relocate segment constants */
for(uint32_t v : prog.relocTable) {
uint8_t *p = &prog.Imagez[v];
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
*p++ = (uint8_t)(w & 0x00FF);
*p = (uint8_t)((w & 0xFF00) >> 8);
}
return true;
}
};
/***************************************************************************** /*****************************************************************************
* LoadImage * LoadImage
****************************************************************************/ ****************************************************************************/
bool Project::load()
{
// addTask(loaderSelection,PreCond(BinaryImage))
// addTask(applyLoader,PreCond(Loader))
const char *fname = binary_path().toLocal8Bit().data();
QFile finfo(binary_path());
/* Open the input file */
if(not finfo.open(QFile::ReadOnly)) {
fatalError(CANNOT_OPEN, fname);
}
/* Read in first 2 bytes to check EXE signature */
if (finfo.size()<=2)
{
fatalError(CANNOT_READ, fname);
}
ComLoader com_loader;
ExeLoader exe_loader;
if(exe_loader.canLoad(finfo)) {
prog.fCOM = false;
return exe_loader.load(prog,finfo);
}
if(com_loader.canLoad(finfo)) {
prog.fCOM = true;
return com_loader.load(prog,finfo);
}
return false;
}
uint32_t SynthLab;
/* Parses the program, builds the call graph, and returns the list of /* 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)
{ {
PROG &prog(proj.prog);
STATE state;
/* Set initial state */ /* Set initial state */
state.setState(rES, 0); /* PSP segment */ proj.addCommand(new MachineStateInitialization);
state.setState(rDS, 0); proj.addCommand(new FindMain);
state.setState(rCS, prog.initCS); }
state.setState(rSS, prog.initSS);
state.setState(rSP, prog.initSP); bool MachineStateInitialization::execute(CommandContext *ctx)
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP; {
SynthLab = SYNTHESIZED_MIN; assert(ctx && ctx->m_project);
Project &proj(*ctx->m_project);
/* Check for special settings of initial state, based on idioms of the const PROG &prog(proj.prog);
startup code */ proj.m_entry_state.setState(rES, 0); /* PSP segment */
state.checkStartup(); proj.m_entry_state.setState(rDS, 0);
ilFunction start_proc; proj.m_entry_state.setState(rCS, prog.initCS);
/* Make a struct for the initial procedure */ proj.m_entry_state.setState(rSS, prog.initSS);
if (prog.offMain != -1) proj.m_entry_state.setState(rSP, prog.initSP);
{ proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
start_proc = proj.createFunction(0,"main"); proj.SynthLab = SYNTHESIZED_MIN;
start_proc->retVal.loc = REG_FRAME; return true;
start_proc->retVal.type = TYPE_WORD_SIGN; }
start_proc->retVal.id.regi = rAX;
/* We know where main() is. Start the flow of control from there */ bool FindMain::execute(CommandContext *ctx) {
start_proc->procEntry = prog.offMain; Project &proj(*ctx->m_project);
/* In medium and large models, the segment of main may (will?) not be const PROG &prog(proj.prog);
the same as the initial CS segment (of the startup code) */
state.setState(rCS, prog.segMain); PtrFunction start_func = proj.findByName("start");
state.IP = prog.offMain; if(ctx->m_project->m_entry_state.IP==0) {
} ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
else return false;
{ }
start_proc = proj.createFunction(0,"start"); /* Check for special settings of initial state, based on idioms of the startup code */
/* Create initial procedure at program start address */ if(checkStartup(ctx->m_project->m_entry_state)) {
start_proc->procEntry = (uint32_t)state.IP; start_func->markDoNotDecompile(); // we have main, do not decompile the start proc
} //TODO: main arguments and return values should depend on detected compiler/library
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
/* The state info is for the first procedure */ main_type->setCallingConvention(CConv::C);
start_proc->state = state; proj.addCommand(new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type));
/* Set up call graph initial node */ proj.addCommand(new LoadPatternLibrary());
proj.callGraph = new CALL_GRAPH; } else {
proj.callGraph->proc = start_proc; start_func->state = proj.m_entry_state; // just in case we fail to find main, initialize 'state' for start func
/* 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 */ return true;
prog.bSigs = SetupLibCheck(); }
//BUG: proj and g_proj are 'live' at this point !
QString CreateFunction::instanceDescription() const {
/* Recursively build entire procedure list */ return QString("%1 \"%2\" @ 0x%3").arg(name()).arg(m_name).arg(m_addr.addr,0,16,QChar('0'));
start_proc->FollowCtrl(proj.callGraph, &state); }
/* This proc needs to be called to clean things up from SetupLibCheck() */ bool CreateFunction::execute(CommandContext *ctx) {
CleanupLibCheck(); Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction func = proj.createFunction(m_type,m_name,m_addr);
if(m_name=="main") {
/* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */
proj.m_entry_state.setState(rCS, prog.segMain);
proj.m_entry_state.IP = prog.offMain;
func->state = proj.m_entry_state;
}
if(m_name=="start") {
proj.addCommand(new MachineStateInitialization);
proj.addCommand(new FindMain);
}
// proj.addCommand(new ProcessFunction);
//proj.addCommand(new FollowControl());
/* Recursively build entire procedure list */
//proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
return true;
} }

49
src/FollowControlFlow.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "FollowControlFlow.h"
#include "project.h"
#include "parser.h"
QString FollowControlFlow::instanceDescription() const
{
return name() + " @ 0x"+QString::number(m_start_state.IP,16);
}
bool FollowControlFlow::execute(CommandContext *ctx)
{
Project &proj(*ctx->m_project);
PtrFunction scanned_func(ctx->m_func);
scanned_func->switchState(eDisassemblyInProgress);
FollowCtrl(*scanned_func,proj.callGraph, &m_start_state);
return false;
}
QString MarkAsSwitchCase::instanceDescription() const
{
return name() + QString(" 0x%1 -> 0x%2 ; case %3")
.arg(m_src_addr,8,16,QChar('0'))
.arg(m_dst_addr,8,16,QChar('0'))
.arg(m_case_label);
}
bool MarkAsSwitchCase::execute(CommandContext * ctx)
{
//TODO: record code/data referneces in project for navigation UI purposes ?
auto switch_insn = ctx->m_func->Icode.labelSrch(m_src_addr);
if(switch_insn==ctx->m_func->Icode.end()) {
ctx->recordFailure(this,QString("switch instruction @ 0x%1 not found in procedure's instructions ?")
.arg(m_src_addr,8,16,QChar('0')));
return false;
}
auto insn = ctx->m_func->Icode.labelSrch(m_dst_addr);
if(insn==ctx->m_func->Icode.end()) {
ctx->recordFailure(this,QString("switch target instruction 0x%1 not found in procedure's instructions ?")
.arg(m_dst_addr,8,16,QChar('0')));
return false;
}
insn->ll()->caseEntry = m_case_label;
insn->ll()->setFlags(CASE);
switch_insn->ll()->caseTbl2.push_back( m_dst_addr );
return true;
}

39
src/FollowControlFlow.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef FOLLOWCONTROLFLOW_H
#define FOLLOWCONTROLFLOW_H
#include "Command.h"
#include "state.h"
class FollowControlFlow : public Command
{
STATE m_start_state;
public:
FollowControlFlow(STATE addr) : Command("Follow control flow",eFunction),m_start_state(addr) {}
// Command interface
public:
QString instanceDescription() const override;
bool execute(CommandContext *ctx) override;
};
// mark instruction at address m_dst_addr as a case m_case_label of switch located at m_src_addr
class MarkAsSwitchCase : public Command
{
uint32_t m_src_addr;
uint32_t m_dst_addr;
int m_case_label;
public:
MarkAsSwitchCase(uint32_t src_addr,uint32_t dst_addr,int lab) :
Command("Mark as switch case",eFunction),
m_src_addr(src_addr),
m_dst_addr(dst_addr),
m_case_label(lab)
{}
// Command interface
public:
QString instanceDescription() const override;
bool execute(CommandContext *ctx) override;
};
#endif // FOLLOWCONTROLFLOW_H

177
src/Loaders.cpp Normal file
View File

@ -0,0 +1,177 @@
#include "Loaders.h"
#include "dcc.h"
#include <QtCore/QDebug>
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
struct PSP { /* PSP structure */
uint16_t int20h; /* interrupt 20h */
uint16_t eof; /* segment, end of allocation block */
uint8_t res1; /* reserved */
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
uint8_t int22h[4]; /* vector for terminate routine */
uint8_t int23h[4]; /* vector for ctrl+break routine */
uint8_t int24h[4]; /* vector for error routine */
uint8_t res2[22]; /* reserved */
uint16_t segEnv; /* segment address of environment block */
uint8_t res3[34]; /* reserved */
uint8_t int21h[6]; /* opcode for int21h and far return */
uint8_t res4[6]; /* reserved */
uint8_t fcb1[16]; /* default file control block 1 */
uint8_t fcb2[16]; /* default file control block 2 */
uint8_t res5[4]; /* reserved */
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
};
static struct MZHeader { /* EXE file header */
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
uint8_t sigHi;
uint16_t lastPageSize; /* Size of the last page */
uint16_t numPages; /* Number of pages in the file */
uint16_t numReloc; /* Number of relocation items */
uint16_t numParaHeader; /* # of paragraphs in the header*/
uint16_t minAlloc; /* Minimum number of paragraphs */
uint16_t maxAlloc; /* Maximum number of paragraphs */
uint16_t initSS; /* Segment displacement of stack */
uint16_t initSP; /* Contents of SP at entry */
uint16_t checkSum; /* Complemented checksum */
uint16_t initIP; /* Contents of IP at entry */
uint16_t initCS; /* Segment displacement of code */
uint16_t relocTabOffset; /* Relocation table offset */
uint16_t overlayNum; /* Overlay number */
} header;
void DosLoader::prepareImage(PROG & prog, size_t sz, QFile & fp) {
/* Allocate a block of memory for the program. */
prog.cbImage = sz + sizeof(PSP);
prog.Imagez = new uint8_t [prog.cbImage];
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
prog.Imagez[1] = 0x20; /* for termination checking */
/* Read in the image past where a PSP would go */
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
}
bool ComLoader::canLoad(QFile & fp) {
fp.seek(0);
char sig[2];
if(2==fp.read(sig,2)) {
return not (sig[0] == 0x4D and sig[1] == 0x5A);
}
return false;
}
bool ComLoader::load(PROG & prog, QFile & fp) {
prog.fCOM = true;
fp.seek(0);
/* COM file
* In this case the load module size is just the file length
*/
auto cb = fp.size();
/* COM programs start off with an ORG 100H (to leave room for a PSP)
* This is also the implied start address so if we load the image
* at offset 100H addresses should all line up properly again.
*/
prog.initCS = 0;
prog.initIP = 0x100;
prog.initSS = 0;
prog.initSP = 0xFFFE;
prog.cReloc = 0;
prepareImage(prog,cb,fp);
/* Set up memory map */
cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb);
return true;
}
bool ExeLoader::canLoad(QFile & fp) {
if(fp.size()<sizeof(header))
return false;
MZHeader tmp_header;
fp.seek(0);
fp.read((char *)&tmp_header, sizeof(header));
if(not (tmp_header.sigLo == 0x4D and tmp_header.sigHi == 0x5A))
return false;
/* This is a typical DOS kludge! */
if (LH(&header.relocTabOffset) == 0x40)
{
qDebug() << "Don't understand new EXE format";
return false;
}
return true;
}
bool ExeLoader::load(PROG & prog, QFile & fp) {
prog.fCOM = false;
/* Read rest of header */
fp.seek(0);
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
return false;
/* Calculate the load module size.
* This is the number of pages in the file
* less the length of the header and reloc table
* less the number of bytes unused on last page
*/
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
if (header.lastPageSize)
{
cb -= 512 - LH(&header.lastPageSize);
}
/* We quietly ignore minAlloc and maxAlloc since for our
* purposes it doesn't really matter where in real memory
* the program would end up. EXE programs can't really rely on
* their load location so setting the PSP segment to 0 is fine.
* Certainly programs that prod around in DOS or BIOS are going
* to have to load DS from a constant so it'll be pretty
* obvious.
*/
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
prog.initIP = (int16_t)LH(&header.initIP);
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
prog.initSP = (int16_t)LH(&header.initSP);
prog.cReloc = (int16_t)LH(&header.numReloc);
/* Allocate the relocation table */
if (prog.cReloc)
{
prog.relocTable.resize(prog.cReloc);
fp.seek(LH(&header.relocTabOffset));
/* Read in seg:offset pairs and convert to Image ptrs */
uint8_t buf[4];
for (int i = 0; i < prog.cReloc; i++)
{
fp.read((char *)buf,4);
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
}
}
/* Seek to start of image */
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
fp.seek(start_of_image);
/* Allocate a block of memory for the program. */
prepareImage(prog,cb,fp);
/* Set up memory map */
cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb);
/* Relocate segment constants */
for(uint32_t v : prog.relocTable) {
uint8_t *p = &prog.Imagez[v];
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
*p++ = (uint8_t)(w & 0x00FF);
*p = (uint8_t)((w & 0xFF00) >> 8);
}
return true;
}

31
src/Loaders.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef LOADERS_H
#define LOADERS_H
#include "BinaryImage.h"
#include <QtCore/QFile>
#include <stdlib.h>
struct DosLoader {
protected:
void prepareImage(PROG &prog,size_t sz,QFile &fp);
public:
virtual bool canLoad(QFile &fp)=0;
virtual QString loaderName() const =0;
virtual bool load(PROG &prog,QFile &fp)=0;
};
struct ComLoader : public DosLoader {
virtual ~ComLoader() {}
bool canLoad(QFile &fp) override;
bool load(PROG &prog,QFile &fp) override;
QString loaderName() const override { return "16-bit DOS - COM loader"; }
};
struct ExeLoader : public DosLoader {
virtual ~ExeLoader() {}
bool canLoad(QFile &fp) override;
bool load(PROG &prog,QFile &fp) override;
QString loaderName() const override { return "16-bit DOS - EXE loader"; }
};
#endif // LOADERS_H

22
src/MemoryChunk.cpp Normal file
View File

@ -0,0 +1,22 @@
#include "MemoryChunk.h"
#include <boost/icl/interval.hpp>
#include <boost/icl/right_open_interval.hpp>
#include <boost/icl/left_open_interval.hpp>
#include <boost/icl/closed_interval.hpp>
#include <boost/icl/open_interval.hpp>
using namespace boost::icl;
MemoryChunk::MemoryChunk(LinearAddress start, LinearAddress fin) : m_start(start),m_fin(fin)
{
}
bool MemoryChunk::contains(LinearAddress addr) const
{
return addr>=m_start && addr<m_fin;
}
uint64_t MemoryChunk::size() const
{
return m_fin-m_start;
}

24
src/MemoryChunk.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef BYTECHUNK_H
#define BYTECHUNK_H
#include "Address.h"
#include <utility>
#include <inttypes.h>
/**
* @brief The MemoryChunk class represents a continuous range of Addresses
*/
class MemoryChunk
{
private:
LinearAddress m_start;
LinearAddress m_fin;
public:
MemoryChunk(LinearAddress start,LinearAddress fin);
bool contains(LinearAddress addr) const;
uint64_t size() const;
std::pair<LinearAddress,LinearAddress> bounds() const { return std::make_pair(m_start,m_fin); }
};
#endif // BYTECHUNK_H

5
src/MemorySegment.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "MemorySegment.h"
MemorySegment::MemorySegment(LinearAddress base, LinearAddress start, LinearAddress fin) : MemoryChunk(start,fin) {
m_base = base;
}

19
src/MemorySegment.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "MemoryChunk.h"
#include <QtCore/QString>
/**
* @brief The MemorySegment represents a single chunk of memory with additional properties.
*/
class MemorySegment : public MemoryChunk
{
uint16_t m_base;
int m_flags;
QString m_name;
public:
MemorySegment(LinearAddress base,LinearAddress start,LinearAddress fin);
const QString &getName() const { return m_name; }
void setName(const QString &v) { m_name = v; }
};

View File

@ -0,0 +1,54 @@
#include "MemorySegmentCoordinator.h"
#include <boost/icl/interval_map.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <utility>
using namespace boost::icl;
class MemorySegmentCoordinatorImpl {
boost::icl::interval_map<LinearAddress,SegmentHolder> m_segmentation_map;
public:
bool addSegment(LinearAddress base, LinearAddress start, LinearAddress fin, const char * name, int flags) {
if(start>fin)
return false;
if(start<base)
return false;
MemorySegment *seg = new MemorySegment(base,start,fin);
seg->setName(name);
//
auto segment_bounds(seg->bounds());
m_segmentation_map.add(std::make_pair(
interval<LinearAddress>::right_open(segment_bounds.first,segment_bounds.second),
seg)
);
return true;
}
uint32_t numberOfSegments() const { return interval_count(m_segmentation_map); }
const MemorySegment *get(LinearAddress addr) {
auto iter = m_segmentation_map.find(addr);
if(iter==m_segmentation_map.end()) {
return nullptr;
}
return iter->second;
}
};
MemorySegmentCoordinator::MemorySegmentCoordinator()
{
m_impl = new MemorySegmentCoordinatorImpl;
}
bool MemorySegmentCoordinator::addSegment(LinearAddress base, LinearAddress start, LinearAddress fin, const char * name, int flags)
{
return m_impl->addSegment(base,start,fin,name,flags);
}
uint32_t MemorySegmentCoordinator::size()
{
return m_impl->numberOfSegments();
}
MemorySegment *MemorySegmentCoordinator::getSegment(LinearAddress addr)
{
return const_cast<MemorySegment *>(m_impl->get(addr));
}

View File

@ -0,0 +1,34 @@
#pragma once
#include "MemorySegment.h"
struct SegmentHolder {
SegmentHolder() : val(nullptr) {}
SegmentHolder(MemorySegment *inf) : val(inf) {}
MemorySegment *operator->() { return val;}
MemorySegment &operator*() const { return *val;}
operator MemorySegment *() { return val;}
operator const MemorySegment *() const { return val;}
SegmentHolder operator+=(const SegmentHolder &/*s*/) {
throw std::runtime_error("Cannot aggregate MemorySegments !");
}
MemorySegment *val;
};
/**
* @brief The MemorySegmentCoordinator class is responsible for:
* - Managing the lifetime of MemorySegments
* - Providing convenience functions for querying the segment-related data
*/
class MemorySegmentCoordinator
{
class MemorySegmentCoordinatorImpl *m_impl;
public:
MemorySegmentCoordinator();
bool addSegment(LinearAddress base,LinearAddress start,LinearAddress fin,const char *name,int flags);
uint32_t size();
MemorySegment *getSegment(LinearAddress addr);
};

View File

@ -3,6 +3,9 @@
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "project.h" #include "project.h"
#include "scanner.h" #include "scanner.h"
#include "ui/StructuredTextTarget.h"
#include <QtCore/QDebug>
//FunctionType *Function::getFunctionType() const //FunctionType *Function::getFunctionType() const
//{ //{
@ -35,6 +38,100 @@ void JumpTable::pruneEntries(uint16_t cs)
} }
void Function::callingConv(CConv::Type v) { void Function::callingConv(CConv::CC_Type v) {
m_call_conv=CConv::create(v); type->setCallingConvention(v);
getFunctionType()->m_call_conv->calculateStackLayout(this);
}
static QString sizeToPtrName(int size)
{
switch(size)
{
case 1:
return "BYTE ptr" ;
case 2:
return "WORD ptr";
case 4:
return "DWORD ptr";
}
return "UNKOWN ptr";
}
static void toStructuredText(STKFRAME &stk,IStructuredTextTarget *out, int level) {
int curlevel = 0;
int maxlevel = stk.m_maxOff - stk.m_minOff;
for(STKSYM & p : stk)
{
if (curlevel > p.label)
{
qWarning() << "error, var collapse!!!";
curlevel = p.label;
}
else if (curlevel < p.label)
{
out->addSpace(4);
out->prtt(QString("gap len = %1").arg(p.label - curlevel,0,16));
curlevel = p.label;
out->addEOL();
}
out->addSpace(4);
out->addTaggedString(XT_Symbol,p.name,&p);
out->prtt("equ");
out->addSpace();
out->prtt(sizeToPtrName(p.size));
out->addSpace();
if (p.arrayMembers>1)
{
out->addTaggedString(XT_Number,QString::number(p.arrayMembers,16));
out->prtt("dup (?)");
out->addSpace();
}
out->TAGbegin(XT_Number, NULL);
out->prtt(QString("%1h").arg(p.label,0,16));
out->TAGend(XT_Number);
out->addEOL();
curlevel += p.size * p.arrayMembers;
}
if (curlevel < maxlevel)
{
out->prtt(QString(" gap len = %1h").arg(maxlevel - curlevel,0,16));
}
}
extern void toStructuredText(LLInst *insn,IStructuredTextTarget *out, int level);
static void toStructuredText(ICODE &stk,IStructuredTextTarget *out, int level) {
if(level==0) {
toStructuredText(stk.ll(),out,level);
}
}
void Function::toStructuredText(IStructuredTextTarget *out, int level)
{
out->TAGbegin(XT_Function, this);
out->addTaggedString(XT_FuncName,name);
out->prtt(" proc");
out->addEOL();
::toStructuredText(args,out,level);
out->addEOL();
for(ICODE &ic : Icode) {
::toStructuredText(ic,out,level);
}
out->addTaggedString(XT_FuncName,name);
out->addSpace();
out->prtt("endp");
out->addEOL();
out->TAGend(XT_Function);
}
void FunctionType::setCallingConvention(CConv::CC_Type cc)
{
m_call_conv=CConv::create(cc);
assert(m_call_conv);
}
void Function::switchState(DecompilationStep s)
{
nStep = s;
} }

View File

@ -63,7 +63,7 @@ QString RegisterNode::walkCondExpr(Function *pProc, int *numLoc) const
QString o; QString o;
assert(&pProc->localId==m_syms); assert(&pProc->localId==m_syms);
ID *id = &pProc->localId.id_arr[regiIdx]; ID *id = &pProc->localId.id_arr[regiIdx];
if (id->name[0] == '\0') /* no name */ if (id->name[0] == '\0') /* no name */
{ {
id->setLocalName(++(*numLoc)); id->setLocalName(++(*numLoc));
codeOut += QString("%1 %2; ").arg(TypeContainer::typeName(id->type)).arg(id->name); codeOut += QString("%1 %2; ").arg(TypeContainer::typeName(id->type)).arg(id->name);

View File

@ -114,7 +114,7 @@ void ICODE::copyDU(const ICODE &duIcode, operDu _du, operDu duDu)
/* Returns a unary conditional expression node. This procedure should /* Returns a unary conditional expression node. This procedure should
* only be used with the following conditional node types: NEGATION, * only be used with the following conditional node types: NEGATION,
* ADDRESSOF, DEREFERENCE, POST_INC, POST_DEC, PRE_INC, PRE_DEC */ * ADDRESSOF, DEREFERENCE, POST_INC, POST_DEC, PRE_INC, PRE_DEC */
/* Returns an identifier conditional expression node of type GLOB_VAR */ /* Returns an identifier conditional expression node of type GLOB_VAR */
@ -222,7 +222,7 @@ AstIdent *AstIdent::Long(LOCAL_ID *localId, opLoc sd, iICODE pIcode, hlFirst f,
{ {
AstIdent *newExp; AstIdent *newExp;
/* Check for long constant and save it as a constant expression */ /* Check for long constant and save it as a constant expression */
if ((sd == SRC) and pIcode->ll()->testFlags(I)) /* constant */ if ((sd == SRC) and pIcode->ll()->srcIsImmed()) /* constant */
{ {
int value; int value;
if (f == HIGH_FIRST) if (f == HIGH_FIRST)
@ -256,7 +256,7 @@ AstIdent *AstIdent::Other(eReg seg, eReg regi, int16_t off)
/* Returns an identifier conditional expression node of type TYPE_LONG or /* Returns an identifier conditional expression node of type TYPE_LONG or
* TYPE_WORD_SIGN */ * TYPE_WORD_SIGN */
AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_) AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_)
{ {
int idx; int idx;
@ -313,7 +313,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
duIcode.setRegDU(rTMP, (operDu)eUSE); duIcode.setRegDU(rTMP, (operDu)eUSE);
} }
else if ((sd == SRC) and ll_insn.testFlags(I)) /* constant */ else if ((sd == SRC) and ll_insn.srcIsImmed()) /* constant */
newExp = new Constant(ll_insn.src().getImm2(), 2); newExp = new Constant(ll_insn.src().getImm2(), 2);
else if (pm.regi == rUNDEF) /* global variable */ else if (pm.regi == rUNDEF) /* global variable */
newExp = new GlobalVariable(pm.segValue, pm.off); newExp = new GlobalVariable(pm.segValue, pm.off);
@ -377,7 +377,7 @@ condId LLInst::idType(opLoc sd) const
{ {
const LLOperand &pm((sd == SRC) ? src() : m_dst); const LLOperand &pm((sd == SRC) ? src() : m_dst);
if ((sd == SRC) and testFlags(I)) if ((sd == SRC) and srcIsImmed())
return (CONSTANT); return (CONSTANT);
else if (pm.regi == 0) else if (pm.regi == 0)
return (GLOB_VAR); return (GLOB_VAR);
@ -402,9 +402,9 @@ int hlSize[] = {2, 1, 1, 2, 2, 4, 4, 4, 2, 2, 1, 4, 4};
int Expr::hlTypeSize(Function * pproc) const int Expr::hlTypeSize(Function * pproc) const
{ {
if (this == nullptr) if (this == nullptr)
return (2); /* for TYPE_UNKNOWN */ return (2); /* for TYPE_UNKNOWN */
fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type); fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type);
return 2; // CC: is this correct? return 2; // CC: is this correct?
} }
/* Returns the type of the expression */ /* Returns the type of the expression */
@ -897,10 +897,10 @@ QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
int FuncNode::hlTypeSize(Function *) const int FuncNode::hlTypeSize(Function *) const
{ {
return hlSize[call.proc->retVal.type]; return hlSize[call.proc->getReturnType()];
} }
hlType FuncNode::expType(Function *) const hlType FuncNode::expType(Function *) const
{ {
return call.proc->retVal.type; return call.proc->getReturnType();
} }

View File

@ -30,12 +30,12 @@ using namespace boost;
using namespace boost::adaptors; using namespace boost::adaptors;
using namespace std; using namespace std;
bundle cCode; /* Procedure declaration and code */ bundle cCode; /* Procedure declaration and code */
/* Returns a unique index to the next label */ /* Returns a unique index to the next label */
int getNextLabel() int getNextLabel()
{ {
static int labelIdx = 1; /* index of the next label */ static int labelIdx = 1; /* index of the next label */
return (labelIdx++); return (labelIdx++);
} }
@ -62,8 +62,8 @@ static void fixupLabels (PPROC pProc)
* a unique label number for it. This label is placed in the associated * a unique label number for it. This label is placed in the associated
* icode for the node (pProc->Icode). The procedure is done in sequential * icode for the node (pProc->Icode). The procedure is done in sequential
* order of dsfLast numbering. */ * order of dsfLast numbering. */
{ int i; /* index into the dfsLast array */ { int i; /* index into the dfsLast array */
PBB *dfsLast; /* pointer to the dfsLast array */ PBB *dfsLast; /* pointer to the dfsLast array */
dfsLast = pProc->dfsLast; dfsLast = pProc->dfsLast;
for (i = 0; i < pProc->numBBs; i++) for (i = 0; i < pProc->numBBs; i++)
@ -82,10 +82,10 @@ char *cChar (uint8_t c)
static char res[3]; static char res[3];
switch (c) { switch (c) {
case 0x8: /* backspace */ case 0x8: /* backspace */
sprintf (res, "\\b"); sprintf (res, "\\b");
break; break;
case 0x9: /* horizontal tab */ case 0x9: /* horizontal tab */
sprintf (res, "\\t"); sprintf (res, "\\t");
break; break;
case 0x0A: /* new line */ case 0x0A: /* new line */
@ -97,7 +97,7 @@ char *cChar (uint8_t c)
case 0x0D: /* carriage return */ case 0x0D: /* carriage return */
sprintf (res, "\\r"); sprintf (res, "\\r");
break; break;
default: /* any other character*/ default: /* any other character*/
sprintf (res, "%c", c); sprintf (res, "%c", c);
} }
return (res); return (res);
@ -106,8 +106,8 @@ char *cChar (uint8_t c)
/* Prints the variable's name and initial contents on the file. /* Prints the variable's name and initial contents on the file.
* Note: to get to the value of the variable: * Note: to get to the value of the variable:
* com file: prog.Image[operand] * com file: prog.Image[operand]
* exe file: prog.Image[operand+0x100] */ * exe file: prog.Image[operand+0x100] */
static void printGlobVar (QTextStream &ostr,SYM * psym) static void printGlobVar (QTextStream &ostr,SYM * psym)
{ {
int j; int j;
@ -124,7 +124,7 @@ static void printGlobVar (QTextStream &ostr,SYM * psym)
break; break;
case 4: if (psym->type == TYPE_PTR) /* pointer */ case 4: if (psym->type == TYPE_PTR) /* pointer */
ostr << "uint16_t *\t"<<psym->name<<" = "<<LH(prog.image()+relocOp)<<";\n"; ostr << "uint16_t *\t"<<psym->name<<" = "<<LH(prog.image()+relocOp)<<";\n";
else /* char */ else /* char */
ostr << "char\t"<<psym->name<<"[4] = \""<< ostr << "char\t"<<psym->name<<"[4] = \""<<
prog.image()[relocOp]<<prog.image()[relocOp+1]<< prog.image()[relocOp]<<prog.image()[relocOp+1]<<
prog.image()[relocOp+2]<<prog.image()[relocOp+3]<<";\n"; prog.image()[relocOp+2]<<prog.image()[relocOp+3]<<";\n";
@ -155,7 +155,7 @@ void Project::writeGlobSymTable()
{ {
if (sym.duVal.isUSE_VAL()) /* first used */ if (sym.duVal.isUSE_VAL()) /* first used */
printGlobVar (ostr,&sym); printGlobVar (ostr,&sym);
else { /* first defined */ else { /* first defined */
switch (sym.size) { switch (sym.size) {
case 1: ostr<<"uint8_t\t"; break; case 1: ostr<<"uint8_t\t"; break;
case 2: ostr<<"int\t"; break; case 2: ostr<<"int\t"; break;
@ -198,7 +198,7 @@ static void writeHeader (QIODevice &_ios, const std::string &fileName)
* to it. If so, a goto is emitted to this label; otherwise, a new label * to it. If so, a goto is emitted to this label; otherwise, a new label
* is created and a goto is also emitted. * is created and a goto is also emitted.
* Note: this procedure is to be used when the label is to be forward on * Note: this procedure is to be used when the label is to be forward on
* the code; that is, the target code has not been traversed yet. */ * the code; that is, the target code has not been traversed yet. */
#if 0 #if 0
static void emitFwdGotoLabel (ICODE * pt, int indLevel) static void emitFwdGotoLabel (ICODE * pt, int indLevel)
{ {
@ -226,8 +226,8 @@ void Function::codeGen (QIODevice &fs)
/* Write procedure/function header */ /* Write procedure/function header */
cCode.init(); cCode.init();
if (flg & PROC_IS_FUNC) /* Function */ if (getReturnType() != TYPE_UNKNOWN) /* Function */
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(retVal.type)).arg(name); ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name);
else /* Procedure */ else /* Procedure */
ostr << "\nvoid "+name+" ("; ostr << "\nvoid "+name+" (";
@ -279,12 +279,12 @@ void Function::codeGen (QIODevice &fs)
fs.write(ostr_contents.toLatin1()); fs.write(ostr_contents.toLatin1());
/* Write procedure's code */ /* Write procedure's code */
if (flg & PROC_ASM) /* generate assembler */ if (flg & PROC_ASM) /* generate assembler */
{ {
Disassembler ds(3); Disassembler ds(3);
ds.disassem(this); ds.disassem(this->shared_from_this());
} }
else /* generate C */ else /* generate C */
{ {
m_actual_cfg.front()->writeCode (1, this, &numLoc, MAX, UN_INIT); m_actual_cfg.front()->writeCode (1, this, &numLoc, MAX, UN_INIT);
} }
@ -325,7 +325,7 @@ void Function::codeGen (QIODevice &fs)
static void backBackEnd (CALL_GRAPH * pcallGraph, QIODevice &_ios) static void backBackEnd (CALL_GRAPH * pcallGraph, QIODevice &_ios)
{ {
// IFace.Yield(); /* This is a good place to yield to other apps */ // IFace.Yield(); /* This is a good place to yield to other apps */
/* Check if this procedure has been processed already */ /* Check if this procedure has been processed already */
if ((pcallGraph->proc->flg & PROC_OUTPUT) or if ((pcallGraph->proc->flg & PROC_OUTPUT) or

File diff suppressed because it is too large Load Diff

51
src/chklib.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef CHKLIB_H
#define CHKLIB_H
#include "Command.h"
#include "Enums.h"
#include "perfhlib.h"
#include <QtCore/QFile>
#include <QtCore/QString>
#include <vector>
class 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=0; /* Number of func names actually stored */
int numArg=0; /* Number of param names actually stored */
public:
struct HT * ht =nullptr; //!< The hash table
struct PH_FUNC_STRUCT * pFunc=nullptr; //!< Points to the array of func names
PatternLocator(QString name) : pattern_id(name) {}
~PatternLocator();
bool load();
int searchPList(const char * name);
bool LibCheck(Function & pProc);
private:
bool readProtoFile();
PerfectHash g_pattern_hasher;
int numKeys=0; /* Number of hash table entries (keys) */
int numVert=0; /* Number of vertices in the graph (also size of g[]) */
unsigned PatLen=0; /* Size of the keys (pattern length) */
unsigned SymLen=0; /* Max size of the symbols, including null */
/* Pointers to start of T1, T2 */
uint16_t * T1base = nullptr;
uint16_t * T2base = nullptr;
uint16_t * g = nullptr; /* g[] */
};
extern bool checkStartup(struct STATE &state);
#endif // CHKLIB_H

View File

@ -14,7 +14,7 @@
#include <sstream> #include <sstream>
#include <QTextStream> #include <QTextStream>
using namespace std; using namespace std;
#define intSize 40 #define intSize 40
static const char *int21h[] = static const char *int21h[] =
{ {
@ -131,21 +131,21 @@ static const char *int21h[] =
static const char *intOthers[] = { static const char *intOthers[] = {
"Exit", /* 0x20 */ "Exit", /* 0x20 */
"", /* other table */ "", /* other table */
"Terminate handler address", /* 0x22 */ "Terminate handler address", /* 0x22 */
"Ctrl-C handler address", /* 0x23 */ "Ctrl-C handler address", /* 0x23 */
"Critical-error handler address", /* 0x24 */ "Critical-error handler address", /* 0x24 */
"Absolute disk read", /* 0x25 */ "Absolute disk read", /* 0x25 */
"Absolute disk write", /* 0x26 */ "Absolute disk write", /* 0x26 */
"Terminate and stay resident", /* 0x27 */ "Terminate and stay resident", /* 0x27 */
"Reserved", /* 0x28 */ "Reserved", /* 0x28 */
"Reserved", /* 0x29 */ "Reserved", /* 0x29 */
"Reserved", /* 0x2A */ "Reserved", /* 0x2A */
"Reserved", /* 0x2B */ "Reserved", /* 0x2B */
"Reserved", /* 0x2C */ "Reserved", /* 0x2C */
"Reserved", /* 0x2D */ "Reserved", /* 0x2D */
"Reserved" /* 0x2E */ "Reserved" /* 0x2E */
}; };
@ -200,8 +200,8 @@ void Function::writeProcComments()
void Function::writeProcComments(QTextStream &ostr) void Function::writeProcComments(QTextStream &ostr)
{ {
int i; int i;
ID *id; /* Pointer to register argument identifier */ ID *id; /* Pointer to register argument identifier */
STKSYM * psym; /* Pointer to register argument symbol */ STKSYM * psym; /* Pointer to register argument symbol */
/* About the parameters */ /* About the parameters */
if (this->cbParam) if (this->cbParam)
@ -218,7 +218,7 @@ void Function::writeProcComments(QTextStream &ostr)
id = &this->localId.id_arr[((RegisterNode *)psym->regs)->regiIdx]; id = &this->localId.id_arr[((RegisterNode *)psym->regs)->regiIdx];
ostr << Machine_X86::regName(id->id.regi); ostr << Machine_X86::regName(id->id.regi);
} }
else /* long register */ else /* long register */
{ {
id = &this->localId.id_arr[psym->regs->ident.idNode.longIdx]; id = &this->localId.id_arr[psym->regs->ident.idNode.longIdx];
ostr << Machine_X86::regName(id->longId().h()) << ":"; ostr << Machine_X86::regName(id->longId().h()) << ":";
@ -239,21 +239,24 @@ void Function::writeProcComments(QTextStream &ostr)
if (this->flg & PROC_ASM) if (this->flg & PROC_ASM)
{ {
ostr << " * Untranslatable routine. Assembler provided.\n"; ostr << " * Untranslatable routine. Assembler provided.\n";
if (this->flg & PROC_IS_FUNC) switch (getReturnType()) { // TODO: Functions return value in various regs
switch (this->retVal.type) { // TODO: Functions return value in various regs case TYPE_BYTE_SIGN:
case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN: case TYPE_BYTE_UNSIGN:
ostr << " * Return value in register al.\n"; ostr << " * Return value in register al.\n";
break; break;
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN: case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
ostr << " * Return value in register ax.\n"; ostr << " * Return value in register ax.\n";
break; break;
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN: case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
ostr << " * Return value in registers dx:ax.\n"; ostr << " * Return value in registers dx:ax.\n";
break; break;
default: case TYPE_UNKNOWN:
fprintf(stderr,"Unknown retval type %d",this->retVal.type); // void return type
break; break;
} /* eos */ default:
fprintf(stderr,"Unknown retval type %d",getReturnType());
break;
} /* eos */
} }
/* Calling convention */ /* Calling convention */

View File

@ -17,7 +17,7 @@
typedef std::list<int> nodeList; /* dfsLast index to the node */ typedef std::list<int> nodeList; /* dfsLast index to the node */
#define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum)) #define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum))
/* there is a path on the DFST from a to b if the a was first visited in a /* there is a path on the DFST from a to b if the a was first visited in a
* dfs, and a was later visited than b when doing the last visit of each * dfs, and a was later visited than b when doing the last visit of each
* node. */ * node. */
@ -69,7 +69,7 @@ void Function::findImmedDom ()
for (size_t currIdx = 0; currIdx < numBBs; currIdx++) for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
{ {
currNode = m_dfsLast[currIdx]; currNode = m_dfsLast[currIdx];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */ if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue; continue;
for (BB * inedge : currNode->inEdges) for (BB * inedge : currNode->inEdges)
{ {
@ -134,7 +134,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
{ {
int i, headDfsNum, intNodeType; int i, headDfsNum, intNodeType;
nodeList loopNodes; nodeList loopNodes;
int immedDom, /* dfsLast index to immediate dominator */ int immedDom, /* dfsLast index to immediate dominator */
thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */ thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */
BB * pbb; BB * pbb;
@ -144,7 +144,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
insertList (loopNodes, headDfsNum); insertList (loopNodes, headDfsNum);
for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++) for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++)
{ {
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */ if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
continue; continue;
immedDom = pProc->m_dfsLast[i]->immedDom; immedDom = pProc->m_dfsLast[i]->immedDom;
@ -192,7 +192,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum; head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum;
latchNode->back().ll()->setFlags(JX_LOOP); latchNode->back().ll()->setFlags(JX_LOOP);
} }
else /* latch = 1-way */ else /* latch = 1-way */
if (latchNode->nodeType == LOOP_NODE) if (latchNode->nodeType == LOOP_NODE)
{ {
head->loopType = eNodeHeaderType::REPEAT_TYPE; head->loopType = eNodeHeaderType::REPEAT_TYPE;
@ -228,7 +228,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
pbb = pProc->m_dfsLast[pbb->immedDom]; pbb = pProc->m_dfsLast[pbb->immedDom];
} }
if (pbb->dfsLastNum > head->dfsLastNum) if (pbb->dfsLastNum > head->dfsLastNum)
pProc->m_dfsLast[head->loopFollow]->loopHead = NO_NODE; /*****/ pProc->m_dfsLast[head->loopFollow]->loopHead = NO_NODE; /*****/
head->back().ll()->setFlags(JX_LOOP); head->back().ll()->setFlags(JX_LOOP);
} }
else else
@ -266,12 +266,12 @@ static void findNodesInInt (queue &intNodes, int level, interval *Ii)
void Function::structLoops(derSeq *derivedG) void Function::structLoops(derSeq *derivedG)
{ {
interval *Ii; interval *Ii;
BB * intHead, /* interval header node */ BB * intHead, /* interval header node */
* pred, /* predecessor node */ * pred, /* predecessor node */
* latchNode;/* latching node (in case of loops) */ * latchNode;/* latching node (in case of loops) */
size_t level = 0; /* derived sequence level */ size_t level = 0; /* derived sequence level */
interval *initInt; /* initial interval */ interval *initInt; /* initial interval */
queue intNodes; /* list of interval nodes */ queue intNodes; /* list of interval nodes */
/* Structure loops */ /* Structure loops */
/* for all derived sequences Gi */ /* for all derived sequences Gi */
@ -369,7 +369,7 @@ static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
* has a case node. */ * has a case node. */
void Function::structCases() void Function::structCases()
{ {
int exitNode = NO_NODE; /* case exit node */ int exitNode = NO_NODE; /* case exit node */
nodeList caseNodes; /* temporary: list of nodes in case */ nodeList caseNodes; /* temporary: list of nodes in case */
/* Linear scan of the nodes in reverse dfsLast order, searching for /* Linear scan of the nodes in reverse dfsLast order, searching for
@ -428,21 +428,21 @@ static void flagNodes (nodeList &l, int f, Function * pProc)
/* Structures if statements */ /* Structures if statements */
void Function::structIfs () void Function::structIfs ()
{ {
size_t followInEdges; /* Largest # in-edges so far */ size_t followInEdges; /* Largest # in-edges so far */
int curr, /* Index for linear scan of nodes */ int curr, /* Index for linear scan of nodes */
/*desc,*/ /* Index for descendant */ /*desc,*/ /* Index for descendant */
follow; /* Possible follow node */ follow; /* Possible follow node */
nodeList domDesc, /* List of nodes dominated by curr */ nodeList domDesc, /* List of nodes dominated by curr */
unresolved /* List of unresolved if nodes */ unresolved /* List of unresolved if nodes */
; ;
BB * currNode, /* Pointer to current node */ BB * currNode, /* Pointer to current node */
* pbb; * pbb;
/* Linear scan of nodes in reverse dfsLast order */ /* Linear scan of nodes in reverse dfsLast order */
for (curr = numBBs - 1; curr >= 0; curr--) for (curr = numBBs - 1; curr >= 0; curr--)
{ {
currNode = m_dfsLast[curr]; currNode = m_dfsLast[curr];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */ if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue; continue;
if ((currNode->nodeType == TWO_BRANCH) and (not currNode->back().ll()->testFlags(JX_LOOP))) if ((currNode->nodeType == TWO_BRANCH) and (not currNode->back().ll()->testFlags(JX_LOOP)))

View File

@ -196,7 +196,7 @@ void Function::elimCondCodes ()
notSup = true; notSup = true;
std::cout << hex<<defIcode.loc_ip; std::cout << hex<<defIcode.loc_ip;
reportError (JX_NOT_DEF, defIcode.ll()->getOpcode()); reportError (JX_NOT_DEF, defIcode.ll()->getOpcode());
flg |= PROC_ASM; /* generate asm */ flg |= PROC_ASM; /* generate asm */
} }
if (not notSup) if (not notSup)
{ {
@ -224,7 +224,7 @@ void Function::elimCondCodes ()
ICODE &a(*defAt); ICODE &a(*defAt);
ICODE &b(*useAt); ICODE &b(*useAt);
reportError (NOT_DEF_USE,a.ll()->label,a.ll()->getOpcode(),b.ll()->getOpcode()); reportError (NOT_DEF_USE,a.ll()->label,a.ll()->getOpcode(),b.ll()->getOpcode());
flg |= PROC_ASM; /* generate asm */ flg |= PROC_ASM; /* generate asm */
} }
break; break;
} }
@ -269,7 +269,7 @@ void Function::genLiveKtes ()
def.reset(); def.reset();
pbb = m_dfsLast[i]; pbb = m_dfsLast[i];
if (pbb->flg & INVALID_BB) if (pbb->flg & INVALID_BB)
continue; // skip invalid BBs continue; // skip invalid BBs
for(ICODE &insn : *pbb) for(ICODE &insn : *pbb)
{ {
if ((insn.type == HIGH_LEVEL_ICODE) and ( insn.valid() )) if ((insn.type == HIGH_LEVEL_ICODE) and ( insn.valid() ))
@ -295,9 +295,9 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
Function * pcallee; /* invoked subroutine */ Function * pcallee; /* invoked subroutine */
//ICODE *ticode /* icode that invokes a subroutine */ //ICODE *ticode /* icode that invokes a subroutine */
; ;
LivenessSet prevLiveOut, /* previous live out */ LivenessSet prevLiveOut, /* previous live out */
prevLiveIn; /* previous live in */ prevLiveIn; /* previous live in */
bool change; /* is there change in the live sets?*/ bool change; /* is there change in the live sets?*/
/* liveOut for this procedure */ /* liveOut for this procedure */
liveOut = in_liveOut; liveOut = in_liveOut;
@ -322,12 +322,12 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
pbb->liveOut = in_liveOut; pbb->liveOut = in_liveOut;
/* Get return expression of function */ /* Get return expression of function */
if (flg & PROC_IS_FUNC) if (getReturnType()!=TYPE_UNKNOWN)
{ {
auto picode = pbb->rbegin(); /* icode of function return */ auto picode = pbb->rbegin(); /* icode of function return */
if (picode->hl()->opcode == HLI_RET) if (picode->hl()->opcode == HLI_RET)
{ {
picode->hlU()->expr(AstIdent::idID(&retVal, &localId, (++pbb->rbegin()).base())); picode->hlU()->expr(AstIdent::idID(&type->retVal, &localId, (++pbb->rbegin()).base()));
picode->du.use = in_liveOut; picode->du.use = in_liveOut;
} }
} }
@ -354,7 +354,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
} }
else /* library routine */ else /* library routine */
{ {
if ( (pcallee->flg & PROC_IS_FUNC) and /* returns a value */ if ( (pcallee->getReturnType()!=TYPE_UNKNOWN) and /* returns a value */
(pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any() (pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any()
) )
pbb->liveOut = pcallee->liveOut; pbb->liveOut = pcallee->liveOut;
@ -364,7 +364,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() )) if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() ))
{ {
switch (pcallee->retVal.type) { switch (pcallee->getReturnType()) {
case TYPE_LONG_SIGN: case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN: case TYPE_LONG_UNSIGN:
ticode.du1.setDef(rAX).addDef(rDX); ticode.du1.setDef(rAX).addDef(rDX);
@ -448,7 +448,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
if (not ticode->du.def.testRegAndSubregs(regi) and liveOut.testRegAndSubregs(regi) ) if (not ticode->du.def.testRegAndSubregs(regi) and liveOut.testRegAndSubregs(regi) )
start_at->du.lastDefRegi.addReg(regi); start_at->du.lastDefRegi.addReg(regi);
} }
else /* only 1 instruction in this basic block */ else /* only 1 instruction in this basic block */
{ {
/* Check if last definition of this register */ /* Check if last definition of this register */
if ( liveOut.testRegAndSubregs(regi) ) if ( liveOut.testRegAndSubregs(regi) )
@ -462,7 +462,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
* on optimized code. */ * on optimized code. */
void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode) void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
{ {
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->flg & PROC_IS_FUNC))) if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->getReturnType()!=TYPE_UNKNOWN)))
return; return;
BB *tbb = this->edges[0].BBptr; BB *tbb = this->edges[0].BBptr;
@ -489,7 +489,7 @@ void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
* thus remove it. Also check that this is not a return * thus remove it. Also check that this is not a return
* from a library function (routines such as printf * from a library function (routines such as printf
* return an integer, which is normally not taken into * return an integer, which is normally not taken into
* account by the programmer). */ * account by the programmer). */
void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode) void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
{ {
if (picode->valid() and not picode->du1.used(defRegIdx) and if (picode->valid() and not picode->du1.used(defRegIdx) and
@ -497,7 +497,7 @@ void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
(not ((picode->hl()->opcode == HLI_CALL) and (not ((picode->hl()->opcode == HLI_CALL) and
(picode->hl()->call.proc->flg & PROC_ISLIB)))) (picode->hl()->call.proc->flg & PROC_ISLIB))))
{ {
if (not (this->liveOut.testRegAndSubregs(regi))) /* not liveOut */ if (not (this->liveOut.testRegAndSubregs(regi))) /* not liveOut */
{ {
bool res = picode->removeDefRegi (regi, defRegIdx+1,&Parent->localId); bool res = picode->removeDefRegi (regi, defRegIdx+1,&Parent->localId);
if (res == true) if (res == true)
@ -512,7 +512,7 @@ void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
} }
} }
} }
else /* liveOut */ else /* liveOut */
picode->du.lastDefRegi.addReg(regi); picode->du.lastDefRegi.addReg(regi);
} }
} }
@ -579,7 +579,7 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
return; return;
/* Insert on rhs of ticode, if possible */ /* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.rhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this); res = Expr::insertSubTreeReg (ticode->hlU()->asgn.m_rhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
if (res) if (res)
{ {
picode->invalidate(); picode->invalidate();
@ -618,7 +618,7 @@ static void forwardSubsLong (int longIdx, Expr *_exp, iICODE picode, iICODE tico
return; return;
/* Insert on rhs of ticode, if possible */ /* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.rhs, longIdx); res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.m_rhs, longIdx);
if (res) if (res)
{ {
picode->invalidate(); picode->invalidate();
@ -637,7 +637,7 @@ static void forwardSubsLong (int longIdx, Expr *_exp, iICODE picode, iICODE tico
} }
/* Returns whether the elements of the expression rhs are all x-clear from /* Returns whether the elements of the expression rhs are all x-clear from
* instruction f up to instruction t. */ * instruction f up to instruction t. */
bool UnaryOperator::xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locs) bool UnaryOperator::xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locs)
{ {
if(nullptr==unaryExp) if(nullptr==unaryExp)
@ -672,9 +672,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);
@ -694,7 +692,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());
@ -722,7 +720,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
} }
} }
} }
else /* user function */ else /* user function */
{ {
if (callee->args.numArgs > 0) if (callee->args.numArgs > 0)
{ {
@ -761,11 +759,11 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
if(isLong) if(isLong)
{ {
forwardSubsLong (lhs_ident->ident.idNode.longIdx, forwardSubsLong (lhs_ident->ident.idNode.longIdx,
p_hl.asgn.rhs, picode,ticode, p_hl.asgn.m_rhs, picode,ticode,
&numHlIcodes); &numHlIcodes);
} }
else else
this->forwardSubs (lhs_ident, p_hl.asgn.rhs, picode, ticode, numHlIcodes); this->forwardSubs (lhs_ident, p_hl.asgn.m_rhs, picode, ticode, numHlIcodes);
break; break;
case HLI_JCOND: case HLI_PUSH: case HLI_RET: case HLI_JCOND: case HLI_PUSH: case HLI_RET:
@ -773,7 +771,7 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
{ {
assert(lhs_ident); assert(lhs_ident);
res = Expr::insertSubTreeLongReg ( res = Expr::insertSubTreeLongReg (
p_hl.asgn.rhs, p_hl.asgn.m_rhs,
t_hl.exp.v, t_hl.exp.v,
lhs_ident->ident.idNode.longIdx); lhs_ident->ident.idNode.longIdx);
} }
@ -783,7 +781,7 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
assert(lhs_reg); assert(lhs_reg);
res = Expr::insertSubTreeReg ( res = Expr::insertSubTreeReg (
t_hl.exp.v, t_hl.exp.v,
p_hl.asgn.rhs, p_hl.asgn.m_rhs,
id_arr[lhs_reg->regiIdx].id.regi, id_arr[lhs_reg->regiIdx].id.regi,
this); this);
} }
@ -837,19 +835,19 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
int k; int k;
pp = picode->hl()->call.proc; pp = picode->hl()->call.proc;
cb = pp->cbParam; /* fixed # arguments */ cb = pp->cbParam; /* fixed # arguments */
k = 0; k = 0;
numArgs = 0; numArgs = 0;
while(k<cb) while(k<cb)
{ {
_exp = g_exp_stk.pop(); _exp = g_exp_stk.pop();
if (pp->flg & PROC_ISLIB) /* library function */ if (pp->flg & PROC_ISLIB) /* library function */
{ {
if (pp->args.numArgs > 0) if (pp->args.numArgs > 0)
_exp = func->adjustActArgType(_exp, pp->args[numArgs].type); _exp = func->adjustActArgType(_exp, pp->args[numArgs].type);
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), func); res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), func);
} }
else /* user function */ else /* user function */
{ {
if (pp->args.numArgs >0) if (pp->args.numArgs >0)
{ {
@ -878,15 +876,15 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
{ {
bool res; bool res;
ID *_retVal; // function return value ID *_retVal; // function return value
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL */ Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL
//Expr *lhs; // exp ptr for return value of a HLI_CALL */ //Expr *lhs; // exp ptr for return value of a HLI_CALL
iICODE ticode; // Target icode */ iICODE ticode; // Target icode
HLTYPE *ti_hl=nullptr; HLTYPE *ti_hl=nullptr;
uint8_t regi; uint8_t regi;
numHlIcodes = 0; numHlIcodes = 0;
assert(&fnc->localId==&locals); assert(&fnc->localId==&locals);
// register(s) to be forward substituted */ // register(s) to be forward substituted
auto valid_and_highlevel = instructions | filtered(ICODE::TypeAndValidFilter<HIGH_LEVEL_ICODE>()); auto valid_and_highlevel = instructions | filtered(ICODE::TypeAndValidFilter<HIGH_LEVEL_ICODE>());
for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++) for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++)
{ {
@ -917,7 +915,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
(ticode->hl()->opcode != HLI_RET))) (ticode->hl()->opcode != HLI_RET)))
continue; continue;
if (_icHl.asgn.rhs->xClear (make_iterator_range(picode.base(),picode->du1.idx[0].uses[0]), if (_icHl.asgn.m_rhs->xClear (make_iterator_range(picode.base(),picode->du1.idx[0].uses[0]),
end(), locals)) end(), locals))
{ {
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,false); locals.processTargetIcode(picode.base(), numHlIcodes, ticode,false);
@ -962,7 +960,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
newRegArg (pProc, picode, ticode); newRegArg (pProc, picode, ticode);
picode->invalidate(); picode->invalidate();
numHlIcodes--; numHlIcodes--;
break; */ break; */
default: default:
fprintf(stderr,"unhandled BB::findBBExps target opcode %d\n",ticode->hl()->opcode); fprintf(stderr,"unhandled BB::findBBExps target opcode %d\n",ticode->hl()->opcode);
@ -972,13 +970,13 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
case HLI_CALL: case HLI_CALL:
ticode = picode->du1.idx[0].uses.front(); ticode = picode->du1.idx[0].uses.front();
ti_hl = ticode->hlU(); ti_hl = ticode->hlU();
_retVal = &_icHl.call.proc->retVal; _retVal = &_icHl.call.proc->type->retVal;
switch (ti_hl->opcode) switch (ti_hl->opcode)
{ {
case HLI_ASSIGN: case HLI_ASSIGN:
assert(ti_hl->asgn.rhs); assert(ti_hl->asgn.m_rhs);
_exp = _icHl.call.toAst(); _exp = _icHl.call.toAst();
res = Expr::insertSubTreeReg (ti_hl->asgn.rhs,_exp, _retVal->id.regi, &locals); res = Expr::insertSubTreeReg (ti_hl->asgn.m_rhs,_exp, _retVal->id.regi, &locals);
if (not res) if (not res)
Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals); Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals);
//TODO: HERE missing: 2 regs //TODO: HERE missing: 2 regs
@ -995,12 +993,12 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
case HLI_JCOND: case HLI_JCOND:
_exp = _icHl.call.toAst(); _exp = _icHl.call.toAst();
res = Expr::insertSubTreeReg (ti_hl->exp.v, _exp, _retVal->id.regi, &locals); res = Expr::insertSubTreeReg (ti_hl->exp.v, _exp, _retVal->id.regi, &locals);
if (res) /* was substituted */ if (res) /* was substituted */
{ {
picode->invalidate(); picode->invalidate();
numHlIcodes--; numHlIcodes--;
} }
else /* cannot substitute function */ else /* cannot substitute function */
{ {
auto lhs = AstIdent::idID(_retVal,&locals,picode.base()); auto lhs = AstIdent::idID(_retVal,&locals,picode.base());
picode->setAsgn(lhs, _exp); picode->setAsgn(lhs, _exp);
@ -1026,8 +1024,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
switch (_icHl.opcode) switch (_icHl.opcode)
{ {
case HLI_ASSIGN: case HLI_ASSIGN:
/* Replace rhs of current icode into target /* Replace rhs of current icode into target icode expression */
* icode expression */
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0]) if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0])
{ {
ticode = picode->du1.idx[0].uses.front(); ticode = picode->du1.idx[0].uses.front();
@ -1051,10 +1048,11 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
_exp = g_exp_stk.pop(); /* pop last exp pushed */ _exp = g_exp_stk.pop(); /* pop last exp pushed */
switch (ticode->hl()->opcode) { switch (ticode->hl()->opcode) {
case HLI_ASSIGN: case HLI_ASSIGN:
forwardSubsLong (dynamic_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx, forwardSubsLong (static_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
_exp, picode.base(), ticode, &numHlIcodes); _exp, picode.base(), ticode, &numHlIcodes);
break; break;
case HLI_JCOND: case HLI_PUSH: case HLI_JCOND:
case HLI_PUSH:
res = Expr::insertSubTreeLongReg (_exp, res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v, ticode->hlU()->exp.v,
dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx); dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx);
@ -1064,7 +1062,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
numHlIcodes--; numHlIcodes--;
} }
break; break;
case HLI_CALL: /*** missing ***/ case HLI_CALL: /*** missing ***/
break; break;
default: default:
fprintf(stderr,"BB::findBBExps Unhandled target op %d\n",ticode->hl()->opcode); fprintf(stderr,"BB::findBBExps Unhandled target op %d\n",ticode->hl()->opcode);
@ -1082,7 +1080,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
AstIdent::Long(&locals, DST, AstIdent::Long(&locals, DST,
ticode,HIGH_FIRST, picode.base(), ticode,HIGH_FIRST, picode.base(),
eDEF, *(++iICODE(ticode))->ll())); eDEF, *(++iICODE(ticode))->ll()));
ticode->hlU()->asgn.rhs = _exp; ticode->hlU()->asgn.m_rhs = _exp;
picode->invalidate(); picode->invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
@ -1096,16 +1094,16 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
case HLI_JCOND: case HLI_JCOND:
_exp = _icHl.call.toAst(); _exp = _icHl.call.toAst();
_retVal = &picode->hl()->call.proc->retVal; _retVal = &picode->hl()->call.proc->type->retVal;
res = Expr::insertSubTreeLongReg (_exp, res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v, ticode->hlU()->exp.v,
locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base())); locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base()));
if (res) /* was substituted */ if (res) /* was substituted */
{ {
picode->invalidate(); picode->invalidate();
numHlIcodes--; numHlIcodes--;
} }
else /* cannot substitute function */ else /* cannot substitute function */
{ {
auto lhs = locals.createId(_retVal,picode.base()); auto lhs = locals.createId(_retVal,picode.base());
picode->setAsgn(lhs, _exp); picode->setAsgn(lhs, _exp);
@ -1147,7 +1145,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
if ( not _icHl.call.proc->isLibrary() and (not picode->du1.used(0)) and (picode->du1.getNumRegsDef() > 0)) if ( not _icHl.call.proc->isLibrary() and (not picode->du1.used(0)) and (picode->du1.getNumRegsDef() > 0))
{ {
_exp = new FuncNode(_icHl.call.proc, _icHl.call.args); _exp = new FuncNode(_icHl.call.proc, _icHl.call.args);
auto lhs = AstIdent::idID (&_icHl.call.proc->retVal, &locals, picode.base()); auto lhs = AstIdent::idID (&_icHl.call.proc->type->retVal, &locals, picode.base());
picode->setAsgn(lhs, _exp); picode->setAsgn(lhs, _exp);
} }
} }
@ -1184,7 +1182,6 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if(not _liveOut.any()) if(not _liveOut.any())
return; return;
} }
flg |= PROC_IS_FUNC;
isAx = _liveOut.testReg(rAX); isAx = _liveOut.testReg(rAX);
isBx = _liveOut.testReg(rBX); isBx = _liveOut.testReg(rBX);
isCx = _liveOut.testReg(rCX); isCx = _liveOut.testReg(rCX);
@ -1220,53 +1217,55 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if (isAx and isDx) /* long or pointer */ if (isAx and isDx) /* long or pointer */
{ {
retVal.type = TYPE_LONG_SIGN; type->setReturnType(TYPE_LONG_SIGN);
retVal.loc = REG_FRAME; type->m_call_conv->calculateStackLayout(this);
retVal.longId() = LONGID_TYPE(rDX,rAX);
/*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin()); /*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin());
localId.propLongId (rAX, rDX, ""); localId.propLongId (rAX, rDX, "");
} }
else if (isAx or isBx or isCx or isDx) /* uint16_t */ else if (isAx or isBx or isCx or isDx) /* uint16_t */
{ {
retVal.type = TYPE_WORD_SIGN; eReg selected_reg;
retVal.loc = REG_FRAME;
if (isAx) if (isAx)
retVal.id.regi = rAX; selected_reg = rAX;
else if (isBx) else if (isBx)
retVal.id.regi = rBX; selected_reg = rBX;
else if (isCx) else if (isCx)
retVal.id.regi = rCX; selected_reg = rCX;
else else
retVal.id.regi = rDX; selected_reg = rDX;
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,retVal.id.regi); type->setReturnType(TYPE_WORD_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,selected_reg);
} }
else if(isAL or isBL or isCL or isDL) else if(isAL or isBL or isCL or isDL)
{ {
retVal.type = TYPE_BYTE_SIGN; eReg selected_reg;
retVal.loc = REG_FRAME;
if (isAL) if (isAL)
retVal.id.regi = rAL; selected_reg = rAL;
else if (isBL) else if (isBL)
retVal.id.regi = rBL; selected_reg = rBL;
else if (isCL) else if (isCL)
retVal.id.regi = rCL; selected_reg = rCL;
else else
retVal.id.regi = rDL; selected_reg = rDL;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi); type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
} }
else if(isAH or isBH or isCH or isDH) else if(isAH or isBH or isCH or isDH)
{ {
retVal.type = TYPE_BYTE_SIGN; eReg selected_reg;
retVal.loc = REG_FRAME;
if (isAH) if (isAH)
retVal.id.regi = rAH; selected_reg = rAH;
else if (isBH) else if (isBH)
retVal.id.regi = rBH; selected_reg = rBH;
else if (isCH) else if (isCH)
retVal.id.regi = rCH; selected_reg = rCH;
else else
retVal.id.regi = rDH; selected_reg = rDH;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi); type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
} }
} }
} }
@ -1289,10 +1288,10 @@ void Function::dataFlow(LivenessSet &_liveOut)
liveAnal = true; liveAnal = true;
elimCondCodes(); elimCondCodes();
genLiveKtes(); genLiveKtes();
liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */ liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */
if (not (flg & PROC_ASM)) /* can generate C for pProc */ if (not (flg & PROC_ASM)) /* can generate C for pProc */
{ {
genDU1 (); /* generate def/use level 1 chain */ genDU1 (); /* generate def/use level 1 chain */
findExps (); /* forward substitution algorithm */ findExps (); /* forward substitution algorithm */
} }
} }

View File

@ -14,16 +14,16 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#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 */
extern SYMTAB symtab; /* Global symbol table */ extern SYMTAB symtab; /* Global symbol table */
extern STATS stats; /* cfg statistics */ extern STATS stats; /* cfg statistics */
extern OPTION option; /* Command line options */ extern OPTION option; /* Command line options */
static char *initargs(int argc, char *argv[]); static char *initargs(int argc, char *argv[]);
static void displayTotalStats(void); static void displayTotalStats(void);
@ -91,23 +91,36 @@ void setupOptions(QCoreApplication &app) {
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
QCoreApplication::setApplicationName("dcc");
QCoreApplication::setApplicationVersion("0.2");
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();
/* Front end reads in EXE or COM file, parses it into I-code while /* Front end reads in EXE or COM file, parses it into I-code while
* building the call graph and attaching appropriate bits of code for * building the call graph and attaching appropriate bits of code for
* each procedure. * each procedure.
*/ */
Project::get()->create(option.filename); proj->create(option.filename);
DccFrontend fe(&app); DccFrontend fe(&app);
if(not Project::get()->load()) { proj->addLoadCommands(option.filename);
proj->processAllCommands();
if(proj->m_error_state) {
proj->dumpAllErrors();
return -1; return -1;
} }
if (option.verbose) if (option.verbose)
Project::get()->prog.displayLoadInfo(); proj->prog.displayLoadInfo();
if(false==fe.FrontEnd ()) if(false==fe.FrontEnd ())
return -1; return -1;
if(option.asm1) if(option.asm1)
@ -124,9 +137,9 @@ int main(int argc, char **argv)
* analysis, data flow etc. and outputs it to output file ready for * analysis, data flow etc. and outputs it to output file ready for
* re-compilation. * re-compilation.
*/ */
BackEnd(Project::get()->callGraph); BackEnd(proj->callGraph);
Project::get()->callGraph->write(); proj->callGraph->write();
if (option.Stats) if (option.Stats)
displayTotalStats(); displayTotalStats();

View File

@ -2,55 +2,20 @@
#include "dcc.h" #include "dcc.h"
#include "project.h" #include "project.h"
struct DccImpl : public IDcc { struct DccImpl : public IDcc {
ilFunction m_current_func; PtrFunction m_current_func;
// IDcc interface // IDcc interface
public: public:
void BaseInit() bool load(QString name)
{
m_current_func = Project::get()->functions().end();
}
void Init(QObject *tgt)
{
}
ilFunction GetFirstFuncHandle()
{
return Project::get()->functions().begin();
}
ilFunction GetCurFuncHandle()
{
return m_current_func;
}
void analysis_Once()
{
}
void 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_cpp(IXmlTarget *, int level)
{
}
size_t getFuncCount()
{
return Project::get()->functions().size();
}
const lFunction &validFunctions() const
{
return Project::get()->functions();
} }
void SetCurFunc_by_Name(QString v) void SetCurFunc_by_Name(QString v)
{ {
lFunction & funcs(Project::get()->functions()); PtrFunction p(Project::get()->findByName(v));
for(auto iter=funcs.begin(),fin=funcs.end(); iter!=fin; ++iter) { if(p!=nullptr)
if(iter->name==v) { m_current_func = p;
m_current_func = iter;
return;
}
}
} }
QDir installDir() { QDir installDir() {
return QDir("."); return QDir(".");

View File

@ -18,6 +18,7 @@
#include <iomanip> #include <iomanip>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "src/ui/StructuredTextTarget.h"
// Note: for the time being, there is no interactive disassembler // Note: for the time being, there is no interactive disassembler
// for unix // for unix
@ -28,7 +29,7 @@ using namespace std;
#define POS_LAB 15 /* Position of label */ #define POS_LAB 15 /* Position of label */
#define POS_OPC 20 /* Position of opcode */ #define POS_OPC 20 /* Position of opcode */
#define POS_OPR 25 /* Position of operand */ #define POS_OPR 25 /* Position of operand */
#define WID_PTR 10 /* Width of the "xword ptr" lingo */ #define WID_PTR 10 /* Width of the "xword ptr" lingo */
#define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */ #define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */
#define POS_CMT 54 /* Position of comment */ #define POS_CMT 54 /* Position of comment */
@ -86,12 +87,12 @@ bool callArg(uint16_t off, char *temp); /* Check for procedure name */
//static FILE *dis_g_fp; //static FILE *dis_g_fp;
static CIcodeRec pc; static CIcodeRec pc;
static int cb, j, numIcode, allocIcode; static int cb, numIcode, allocIcode;
static map<int,int> pl; static map<int,int> pl;
static uint32_t nextInst; static uint32_t nextInst;
static bool fImpure; //static bool fImpure;
//static int g_lab; //static int g_lab;
static Function * pProc; /* Points to current proc struct */ static PtrFunction pProc; /* Points to current proc struct */
struct POSSTACK_ENTRY struct POSSTACK_ENTRY
{ {
@ -107,12 +108,12 @@ static vector<POSSTACK_ENTRY> posStack; /* position stack */
#define printfd(x) printf(x) #define printfd(x) printf(x)
#define dis_newline() printf("\n") #define dis_newline() printf("\n")
#define dis_show() // Nothing to do unless using Curses #define dis_show() // Nothing to do unless using Curses
void LLInst::findJumpTargets(CIcodeRec &_pc) void LLInst::findJumpTargets(CIcodeRec &_pc)
{ {
if (testFlags(I) and not testFlags(JMP_ICODE) and isJmpInst()) if (srcIsImmed() and not testFlags(JMP_ICODE) and isJmpInst())
{ {
/* Replace the immediate operand with an icode index */ /* Replace the immediate operand with an icode index */
iICODE labTgt=_pc.labelSrch(src().getImm2()); iICODE labTgt=_pc.labelSrch(src().getImm2());
@ -133,12 +134,12 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
} }
/***************************************************************************** /*****************************************************************************
* disassem - Prints a disassembled listing of a procedure. * disassem - Prints a disassembled listing of a procedure.
* pass == 1 generates output on file .a1 * pass == 1 generates output on file .a1
* pass == 2 generates output on file .a2 * pass == 2 generates output on file .a2
* pass == 3 generates output on file .b * pass == 3 generates output on file .b
****************************************************************************/ ****************************************************************************/
void Disassembler::disassem(Function * ppProc) void Disassembler::disassem(PtrFunction ppProc)
{ {
@ -213,364 +214,7 @@ void Disassembler::disassem(Function * ppProc)
****************************************************************************/ ****************************************************************************/
void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass) void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass)
{ {
PROG &prog(Project::get()->prog); assert(false);
QString oper_contents;
QTextStream oper_stream(&oper_contents);
QString hex_bytes;
QString result_contents;
QTextStream result_stream(&result_contents);
QString opcode_with_mods;
QString operands_contents;
QTextStream operands_s(&operands_contents);
oper_stream.setNumberFlags(QTextStream::UppercaseBase|QTextStream::UppercaseDigits);
/* Disassembly stage 1 --
* Do not try to display NO_CODE entries or synthetic instructions,
* other than JMPs, that have been introduced for def/use analysis. */
if ((option.asm1) and
( inst.testFlags(NO_CODE) or
(inst.testFlags(SYNTHETIC) and (inst.getOpcode() != iJMP))))
{
return;
}
else if (inst.testFlags(NO_CODE))
{
return;
}
if (inst.testFlags(TARGET | CASE))
{
if (pass == 3)
cCode.appendCode("\n"); /* Print to c code buffer */
else
m_fp<< "\n"; /* No, print to the stream */
}
/* Find next instruction label and print hex bytes */
if (inst.testFlags(SYNTHETIC))
nextInst = inst.label;
else
{
cb = (uint32_t) inst.numBytes;
nextInst = inst.label + cb;
/* Output hex code in program image */
if (pass != 3)
{
for (j = 0; j < cb; j++)
{
hex_bytes += QString("%1").arg(uint16_t(prog.image()[inst.label + j]),2,16,QChar('0')).toUpper();
}
hex_bytes += ' ';
}
}
oper_stream.setFieldWidth(POS_LAB);
oper_stream.setFieldAlignment(QTextStream::AlignLeft);
oper_stream << hex_bytes;
/* Check if there is a symbol here */
selectTable(Label);
oper_stream.setFieldWidth(5); // align for the labels
{
QString lab_contents;
QTextStream lab_stream(&lab_contents);
if (readVal(lab_stream, inst.label, nullptr))
{
lab_stream << ':'; /* Also removes the null */
}
else if (inst.testFlags(TARGET)) /* Symbols override Lnn labels */
{
/* Print label */
if (pl.count(loc_ip)==0)
{
pl[loc_ip] = ++g_lab;
}
lab_stream<< "L"<<pl[loc_ip]<<':';
}
lab_stream.flush();
oper_stream << lab_contents;
oper_stream.setFieldWidth(0);
}
if ((inst.getOpcode()==iSIGNEX )and inst.testFlags(B))
{
inst.setOpcode(iCBW);
}
opcode_with_mods += Machine_X86::opcodeName(inst.getOpcode());
switch ( inst.getOpcode() )
{
case iADD: case iADC: case iSUB: case iSBB: case iAND: case iOR:
case iXOR: case iTEST: case iCMP: case iMOV: case iLEA: case iXCHG:
strDst(operands_s,inst.getFlag(), inst.m_dst);
inst.strSrc(operands_s);
break;
case iESC:
inst.flops(operands_s);
break;
case iSAR: case iSHL: case iSHR: case iRCL: case iRCR: case iROL:
case iROR:
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
if(inst.testFlags(I))
inst.strSrc(operands_s);
else
operands_s<<", cl";
break;
case iINC: case iDEC: case iNEG: case iNOT: case iPOP:
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
break;
case iPUSH:
if (inst.testFlags(I))
{
operands_s<<strHex(inst.src().getImm2());
}
else
{
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
}
break;
case iDIV: case iIDIV: case iMUL: case iIMUL: case iMOD:
if (inst.testFlags(I))
{
strDst(operands_s,inst.getFlag(), inst.m_dst) <<", ";
formatRM(operands_s, inst.src());
inst.strSrc(operands_s);
}
else
strDst(operands_s,inst.getFlag() | I, inst.src());
break;
case iLDS: case iLES: case iBOUND:
strDst(operands_s,inst.getFlag(), inst.m_dst)<<", dword ptr";
inst.strSrc(operands_s,true);
break;
case iJB: case iJBE: case iJAE: case iJA:
case iJL: case iJLE: case iJGE: case iJG:
case iJE: case iJNE: case iJS: case iJNS:
case iJO: case iJNO: case iJP: case iJNP:
case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
case iJMP: case iJMPF:
/* Check if there is a symbol here */
{
ICODE *lab=pc.GetIcode(inst.src().getImm2());
selectTable(Label);
if ((inst.src().getImm2() < (uint32_t)numIcode) and /* Ensure in range */
readVal(operands_s, lab->ll()->label, nullptr))
{
break; /* Symbolic label. Done */
}
}
if (inst.testFlags(NO_LABEL))
{
//strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op));
operands_s<<strHex(inst.src().getImm2());
}
else if (inst.testFlags(I) )
{
j = inst.src().getImm2();
if (pl.count(j)==0) /* Forward jump */
{
pl[j] = ++g_lab;
}
if (inst.getOpcode() == iJMPF)
{
operands_s<<" far ptr ";
}
operands_s<<"L"<<pl[j];
}
else if (inst.getOpcode() == iJMPF)
{
operands_s<<"dword ptr";
inst.strSrc(operands_s,true);
}
else
{
strDst(operands_s,I, inst.src());
}
break;
case iCALL: case iCALLF:
if (inst.testFlags(I))
{
QString oper = QString("%1 ptr %2")
.arg((inst.getOpcode() == iCALL) ? "near" : "far")
.arg((inst.src().proc.proc)->name);
operands_s<< qPrintable(oper);
}
else if (inst.getOpcode() == iCALLF)
{
operands_s<<"dword ptr ";
inst.strSrc(operands_s,true);
}
else
strDst(operands_s,I, inst.src());
break;
case iENTER:
operands_s<<strHex(inst.m_dst.off) << ", " << strHex(inst.src().getImm2());
break;
case iRET: case iRETF: case iINT:
if (inst.testFlags(I))
{
operands_s<<strHex(inst.src().getImm2());
}
break;
case iCMPS: case iREPNE_CMPS: case iREPE_CMPS:
case iSCAS: case iREPNE_SCAS: case iREPE_SCAS:
case iSTOS: case iREP_STOS:
case iLODS: case iREP_LODS:
case iMOVS: case iREP_MOVS:
case iINS: case iREP_INS:
case iOUTS: case iREP_OUTS:
if (inst.src().segOver)
{
bool is_dx_src=(inst.getOpcode() == iOUTS or inst.getOpcode() == iREP_OUTS);
if(is_dx_src)
operands_s<<"dx, "<<szPtr[inst.getFlag() & B];
else
operands_s<<szPtr[inst.getFlag() & B];
if (inst.getOpcode() == iLODS or
inst.getOpcode() == iREP_LODS or
inst.getOpcode() == iOUTS or
inst.getOpcode() == iREP_OUTS)
{
operands_s<<Machine_X86::regName(inst.src().segOver); // szWreg[src.segOver-rAX]
}
else
{
operands_s<<"es:[di], "<<Machine_X86::regName(inst.src().segOver);
}
operands_s<<":[si]";
}
else
{
if(inst.getFlag() & B)
opcode_with_mods+='B';
else
opcode_with_mods+='W';
}
break;
case iXLAT:
if (inst.src().segOver)
{
operands_s<<" "<<szPtr[1];
operands_s<<Machine_X86::regName(inst.src().segOver)<<":[bx]";
}
break;
case iIN:
(inst.getFlag() & B)? operands_s<<"al, " : operands_s<< "ax, ";
(inst.testFlags(I))? operands_s << strHex(inst.src().getImm2()) : operands_s<< "dx";
break;
case iOUT:
{
QString d1=((inst.testFlags(I))? strHex(inst.src().getImm2()): "dx");
QString d2=((inst.getFlag() & B) ? ", al": ", ax");
operands_s<<d1 << d2;
}
break;
default:
break;
}
oper_stream.setFieldWidth(15);
operands_s.flush();
oper_stream << qSetFieldWidth(15) << opcode_with_mods << qSetFieldWidth(0) << operands_contents;
/* Comments */
if (inst.testFlags(SYNTHETIC))
{
fImpure = false;
}
else
{
for (j = inst.label, fImpure = 0; j > 0 and j < (int)nextInst; j++)
{
fImpure |= BITMAP(j, BM_DATA);
}
}
result_stream.setFieldWidth(54);
result_stream.setFieldAlignment(QTextStream::AlignLeft);
oper_stream.flush();
result_stream << oper_contents;
result_stream.setFieldWidth(0);
/* Check for user supplied comment */
selectTable(Comment);
QString cbuf_contents;
QTextStream cbuf(&cbuf_contents);
if (readVal(cbuf, inst.label, nullptr))
{
cbuf.flush();
result_stream <<"; "<<*cbuf.string();
}
else if (fImpure or (inst.testFlags(SWITCH | CASE | SEG_IMMED | IMPURE | SYNTHETIC | TERMINATES)))
{
if (inst.testFlags(CASE))
{
result_stream << ";Case l"<< inst.caseEntry;
}
if (inst.testFlags(SWITCH))
{
result_stream << ";Switch ";
}
if (fImpure)
{
result_stream << ";Accessed as data ";
}
if (inst.testFlags(IMPURE))
{
result_stream << ";Impure operand ";
}
if (inst.testFlags(SEG_IMMED))
{
result_stream << ";Segment constant";
}
if (inst.testFlags(TERMINATES))
{
result_stream << ";Exit to DOS";
}
}
/* Comment on iINT icodes */
if (inst.getOpcode() == iINT)
inst.writeIntComment(result_stream);
/* Display output line */
if(pass==3)
{
/* output to .b code buffer */
if (inst.testFlags(SYNTHETIC))
result_stream<<";Synthetic inst";
if (pass == 3) { /* output to .b code buffer */
cCode.appendCode("%s\n", qPrintable(result_contents));
}
}
else
{
char buf[12];
/* output to .a1 or .a2 file */
if (not inst.testFlags(SYNTHETIC) )
{
sprintf(buf,"%03d %06X",loc_ip, inst.label);
}
else /* SYNTHETIC instruction */
{
sprintf(buf,"%03d ",loc_ip);
result_stream<<";Synthetic inst";
}
result_stream.flush();
m_fp<<buf<< " " << result_contents << "\n";
}
} }
@ -629,19 +273,19 @@ static QTextStream & strDst(QTextStream &os,uint32_t flg, const LLOperand &pm)
/**************************************************************************** /****************************************************************************
* strSrc * * strSrc *
****************************************************************************/ ****************************************************************************/
QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma) //QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
{ //{
if(false==skip_comma) // if(false==skip_comma)
os<<", "; // os<<", ";
if (testFlags(I)) // if (srcIsImmed())
os<<strHex(src().getImm2()); // os<<strHex(src().getImm2());
else if (testFlags(IM_SRC)) /* level 2 */ // else if (testFlags(IM_SRC)) /* level 2 */
os<<"dx:ax"; // os<<"dx:ax";
else // else
formatRM(os, src()); // formatRM(os, src());
return os; // return os;
} //}
@ -660,7 +304,7 @@ static char *strHex(uint32_t d)
/**************************************************************************** /****************************************************************************
* interactDis - interactive disassembler * * interactDis - interactive disassembler *
****************************************************************************/ ****************************************************************************/
void interactDis(Function * initProc, int initIC) void interactDis(const PtrFunction & initProc, int initIC)
{ {
QString procname = "UNKNOWN"; QString procname = "UNKNOWN";
if(initProc) if(initProc)
@ -690,29 +334,29 @@ void LLInst::flops(QTextStream &out)
} }
else switch (op & 0x30) else switch (op & 0x30)
{ {
case 0x00: case 0x00:
case 0x10: case 0x10:
out << "dword ptr "; out << "dword ptr ";
break;
case 0x20:
out << "qword ptr ";
break;
case 0x30:
switch (op)
{
case 0x3C: /* FBLD */
case 0x3E: /* FBSTP */
out << "tbyte ptr ";
break; break;
case 0x20: case 0x3D: /* FILD 64 bit */
case 0x3F: /* FISTP 64 bit */
out << "qword ptr "; out << "qword ptr ";
break; break;
case 0x30:
switch (op)
{
case 0x3C: /* FBLD */
case 0x3E: /* FBSTP */
out << "tbyte ptr ";
break;
case 0x3D: /* FILD 64 bit */
case 0x3F: /* FISTP 64 bit */
out << "qword ptr ";
break;
default: default:
out << "uint16_t ptr "; out << "uint16_t ptr ";
break; break;
} }
} }
out.setFieldWidth(0); out.setFieldWidth(0);
formatRM(out, m_dst); formatRM(out, m_dst);
@ -727,46 +371,271 @@ void LLInst::flops(QTextStream &out)
int destRegIdx=m_dst.regi - rAX; int destRegIdx=m_dst.regi - rAX;
switch (op) switch (op)
{ {
case 0x0C: case 0x0C:
out << szFlops0C[destRegIdx]; out << szFlops0C[destRegIdx];
break; break;
case 0x0D: case 0x0D:
out << szFlops0D[destRegIdx]; out << szFlops0D[destRegIdx];
break; break;
case 0x0E: case 0x0E:
out << szFlops0E[destRegIdx]; out << szFlops0E[destRegIdx];
break; break;
case 0x0F: case 0x0F:
out << szFlops0F[destRegIdx]; out << szFlops0F[destRegIdx];
break; break;
case 0x15: case 0x15:
out << szFlops15[destRegIdx]; out << szFlops15[destRegIdx];
break; break;
case 0x1C: case 0x1C:
out << szFlops1C[destRegIdx]; out << szFlops1C[destRegIdx];
break; break;
case 0x33: case 0x33:
out << szFlops33[destRegIdx]; out << szFlops33[destRegIdx];
break; break;
case 0x3C: case 0x3C:
out << szFlops3C[destRegIdx]; out << szFlops3C[destRegIdx];
break; break;
default: default:
out << Machine_X86::floatOpName(0x40+op); out << Machine_X86::floatOpName(0x40+op);
if ((op >= 0x20) and (op <= 0x27)) if ((op >= 0x20) and (op <= 0x27))
{ {
/* This is the ST(i), ST form. */ /* This is the ST(i), ST form. */
out << "ST("<<destRegIdx - rAX<<"),ST"; out << "ST("<<destRegIdx - rAX<<"),ST";
} }
else else
{ {
/* ST, ST(i) */ /* ST, ST(i) */
out << "ST,ST("<<destRegIdx; out << "ST,ST("<<destRegIdx;
} }
break; break;
} }
} }
} }
struct AsmFormatter {
IStructuredTextTarget * target;
int operand_count;
void visitOperand(const LLOperand &pm) {
if(not pm.isSet())
return;
if(operand_count>0) {
target->prtt(", ");
}
operand_count++;
if (pm.immed and not pm.isReg()) {
//target->addTaggedString(XT_Keyword,szPtr[flg&B]);
target->addTaggedString(XT_Number,strHex(pm.getImm2()));
return;
}
if (pm.segOver)
{
target->prtt(Machine_X86::regName(pm.segOver)+':');
}
if (pm.regi == rUNDEF)
{
target->prtt(QString("[")+strHex((uint32_t)pm.off)+"]");
}
else if (pm.isReg())
{
target->prtt(Machine_X86::regName(pm.regi));
}
else if (pm.off)
{
if (pm.off < 0)
{
target->prtt("["+Machine_X86::regName(pm.regi)+"-"+strHex((uint32_t)(- pm.off))+"]");
}
else
{
target->prtt("["+Machine_X86::regName(pm.regi)+"+"+strHex((uint32_t)(pm.off))+"]");
}
}
else
target->prtt("["+Machine_X86::regName(pm.regi)+"]");
}
};
void toStructuredText(LLInst *insn,IStructuredTextTarget *out, int level) {
AsmFormatter formatter {out};
const LLInst &inst(*insn);
QString opcode = Machine_X86::opcodeName(insn->getOpcode());
out->addSpace(4);
out->addTaggedString(XT_Number,QString("%1").arg(insn->label,8,16,QChar('0').toUpper()));
out->addSpace(4);
out->addTaggedString(XT_Keyword,Machine_X86::opcodeName(insn->getOpcode()),insn);
out->addSpace(2);
switch(insn->getOpcode()) {
case iADD: case iADC: case iSUB: case iSBB: case iAND: case iOR:
case iXOR: case iTEST: case iCMP: case iMOV: case iLEA: case iXCHG:
case iSAR: case iSHL: case iSHR: case iRCL: case iRCR: case iROL:
case iROR:
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
break;
case iINC: case iDEC: case iNEG: case iNOT: case iPOP:
formatter.visitOperand(insn->dst());
break;
case iPUSH:
formatter.visitOperand(insn->dst());
break;
case iDIV: case iIDIV: case iMUL: case iIMUL: case iMOD:
if (inst.srcIsImmed())
{
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
}
else
formatter.visitOperand(insn->dst());
break;
case iLDS: case iLES: case iBOUND:
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
break;
case iJB: case iJBE: case iJAE: case iJA:
case iJL: case iJLE: case iJGE: case iJG:
case iJE: case iJNE: case iJS: case iJNS:
case iJO: case iJNO: case iJP: case iJNP:
case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
case iJMP: case iJMPF:
/* Check if there is a symbol here */
{
// ICODE *lab=pc.GetIcode(inst.src().getImm2());
// selectTable(Label);
// if ((inst.src().getImm2() < (uint32_t)numIcode) and /* Ensure in range */
// readVal(operands_s, lab->ll()->label, nullptr))
// {
// break; /* Symbolic label. Done */
// }
}
if (inst.testFlags(NO_LABEL))
{
//strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op));
out->addTaggedString(XT_AsmLabel,strHex(inst.src().getImm2()));
}
else if (inst.srcIsImmed() )
{
int64_t tgt_addr = inst.src().getImm2();
if (inst.getOpcode() == iJMPF)
{
out->addTaggedString(XT_Keyword," far ptr ");
}
out->addTaggedString(XT_AsmLabel,QString("L_%1").arg(strHex(tgt_addr)));
}
else if (inst.getOpcode() == iJMPF)
{
out->addTaggedString(XT_Keyword,"dword ptr");
formatter.visitOperand(inst.src());
}
else
{
formatter.visitOperand(inst.src());
}
break;
case iCALL: case iCALLF:
if (inst.srcIsImmed())
{
out->addTaggedString(XT_Keyword,QString("%1 ptr ").arg((inst.getOpcode() == iCALL) ? "near" : "far"));
out->addTaggedString(XT_AsmLabel,(inst.src().proc.proc)->name);
}
else if (inst.getOpcode() == iCALLF)
{
out->addTaggedString(XT_Keyword,"dword ptr ");
formatter.visitOperand(inst.src());
}
else
formatter.visitOperand(inst.src());
break;
case iENTER:
formatter.visitOperand(inst.dst());
formatter.visitOperand(inst.src());
break;
case iRET:
case iRETF:
case iINT:
formatter.visitOperand(inst.src());
break;
case iCMPS: case iREPNE_CMPS: case iREPE_CMPS:
case iSCAS: case iREPNE_SCAS: case iREPE_SCAS:
case iSTOS: case iREP_STOS:
case iLODS: case iREP_LODS:
case iMOVS: case iREP_MOVS:
case iINS: case iREP_INS:
case iOUTS: case iREP_OUTS:
if (inst.src().segOver)
{
bool is_dx_src=(inst.getOpcode() == iOUTS or inst.getOpcode() == iREP_OUTS);
if(is_dx_src)
{
out->addTaggedString(XT_Symbol,"dx");
out->prtt(", ");
out->addTaggedString(XT_Keyword,szPtr[inst.getFlag() & B]);
out->addSpace(2);
}
else
out->addTaggedString(XT_Keyword,szPtr[inst.getFlag() & B]);
if (inst.getOpcode() == iLODS or
inst.getOpcode() == iREP_LODS or
inst.getOpcode() == iOUTS or
inst.getOpcode() == iREP_OUTS)
{
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver)); // szWreg[src.segOver-rAX]
}
else
{
out->addTaggedString(XT_Symbol,"es:[di]");
out->prtt(", ");
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver));
}
out->addTaggedString(XT_Symbol,":[si]");
}
else
{
out->delChars(2); // TODO: this is wonky way of adding instruction suffix
if(inst.getFlag() & B)
out->addTaggedString(XT_Keyword,"B");
else
out->addTaggedString(XT_Keyword,"W");
out->addSpace(2);
}
break;
case iXLAT:
if (inst.src().segOver)
{
out->addTaggedString(XT_Keyword,QString(" ") + szPtr[1]);
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver)+":[bx]");
}
break;
case iIN:
out->addTaggedString(XT_Symbol, (inst.getFlag() & B)? "al" : "ax");
out->prtt(", ");
formatter.visitOperand(inst.src());
break;
case iOUT:
{
formatter.visitOperand(inst.src());
if(inst.srcIsImmed())
out->addTaggedString(XT_Number, strHex(inst.src().getImm2()));
else
out->addTaggedString(XT_Symbol, "dx");
out->prtt(", ");
out->addTaggedString(XT_Symbol, (inst.getFlag() & B)? "al" : "ax");
}
}
out->addEOL();
}

View File

@ -190,7 +190,7 @@ void fixWildCards(uint8_t pat[])
op = pat[pc++]; op = pat[pc++];
if (pc >= PATLEN) return; if (pc >= PATLEN) return;
quad = (uint8_t) (op & 0xC0); /* Quadrant of the opcode map */ quad = (uint8_t) (op & 0xC0); /* Quadrant of the opcode map */
if (quad == 0) if (quad == 0)
{ {
/* Arithmetic group 00-3F */ /* Arithmetic group 00-3F */

View File

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* dcc project CFG related functions * dcc project CFG related functions
* (C) Cristina Cifuentes * (C) Cristina Cifuentes
****************************************************************************/ ****************************************************************************/
@ -15,7 +15,6 @@
using namespace std; using namespace std;
using namespace boost; using namespace boost;
extern Project g_proj;
//static BB * rmJMP(Function * pProc, int marker, BB * pBB); //static BB * rmJMP(Function * pProc, int marker, BB * pBB);
//static void mergeFallThrough(Function * pProc, BB * pBB); //static void mergeFallThrough(Function * pProc, BB * pBB);
//static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last); //static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last);
@ -47,7 +46,7 @@ void Function::createCFG()
BB * psBB; BB * psBB;
BB * pBB; BB * pBB;
iICODE pIcode = Icode.begin(); iICODE pIcode = Icode.begin();
stats.numBBbef = stats.numBBaft = 0; stats.numBBbef = stats.numBBaft = 0;
rICODE current_range=make_iterator_range(pIcode,++iICODE(pIcode)); rICODE current_range=make_iterator_range(pIcode,++iICODE(pIcode));
@ -93,7 +92,7 @@ void Function::createCFG()
pBB->addOutEdge(elem); pBB->addOutEdge(elem);
hasCase = true; hasCase = true;
} }
else if ((ll->getFlag() & (I | NO_LABEL)) == I) //TODO: WHY NO_LABEL TESTIT else if (ll->srcIsImmed() and not ll->testFlags(NO_LABEL)) //TODO: WHY NO_LABEL TESTIT
{ {
pBB = BB::Create(current_range, ONE_BRANCH, this); pBB = BB::Create(current_range, ONE_BRANCH, this);
pBB->addOutEdge(ll->src().getImm2()); pBB->addOutEdge(ll->src().getImm2());
@ -205,7 +204,7 @@ void Function::freeCFG()
void Function::compressCFG() void Function::compressCFG()
{ {
BB *pNxt; BB *pNxt;
int ip, first=0, last; int ip, first=0, last;
/* First pass over BB list removes redundant jumps of the form /* First pass over BB list removes redundant jumps of the form
* (Un)Conditional -> Unconditional jump */ * (Un)Conditional -> Unconditional jump */
@ -241,7 +240,7 @@ void Function::compressCFG()
{ {
if (pBB->inEdges.empty()) if (pBB->inEdges.empty())
{ {
if (entry_node) /* Init it misses out on */ if (entry_node) /* Init it misses out on */
pBB->index = UN_INIT; pBB->index = UN_INIT;
else else
{ {
@ -321,7 +320,7 @@ BB *BB::rmJMP(int marker, BB * pBB)
****************************************************************************/ ****************************************************************************/
void BB::mergeFallThrough( CIcodeRec &Icode) void BB::mergeFallThrough( CIcodeRec &Icode)
{ {
BB * pChild; BB * pChild;
if (nullptr==this) if (nullptr==this)
{ {
printf("mergeFallThrough on empty BB!\n"); printf("mergeFallThrough on empty BB!\n");
@ -374,7 +373,7 @@ void BB::mergeFallThrough( CIcodeRec &Icode)
****************************************************************************/ ****************************************************************************/
void BB::dfsNumbering(std::vector<BB *> &dfsLast, int *first, int *last) void BB::dfsNumbering(std::vector<BB *> &dfsLast, int *first, int *last)
{ {
BB * pChild; BB * pChild;
traversed = DFS_NUM; traversed = DFS_NUM;
dfsFirstNum = (*first)++; dfsFirstNum = (*first)++;

View File

@ -332,7 +332,7 @@ void Function::highLevelGen()
lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE); lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
} }
if(ll->getOpcode()==iPUSH) { if(ll->getOpcode()==iPUSH) {
if(ll->testFlags(I)) { if(ll->srcIsImmed()) {
lhs = new Constant(src_ll->opz,src_ll->byteWidth()); lhs = new Constant(src_ll->opz,src_ll->byteWidth());
} }
// lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE); // lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
@ -399,7 +399,8 @@ void Function::highLevelGen()
} }
break; break;
case iMOV: pIcode->setAsgn(lhs, rhs); case iMOV:
pIcode->setAsgn(lhs, rhs);
break; break;
case iMUL: case iMUL:
@ -432,7 +433,8 @@ void Function::highLevelGen()
break; break;
case iRET: case iRET:
case iRETF: pIcode->setUnary(HLI_RET, nullptr); case iRETF:
pIcode->setUnary(HLI_RET, nullptr);
break; break;
case iSHL: case iSHL:
@ -461,6 +463,8 @@ void Function::highLevelGen()
rhs = new BinaryOperator(XOR,lhs, rhs); rhs = new BinaryOperator(XOR,lhs, rhs);
pIcode->setAsgn(lhs, rhs); pIcode->setAsgn(lhs, rhs);
break; break;
//TODO: default: // mostly to silence static analyzer warnings ?
// delete rhs;
} }
} }
@ -516,7 +520,7 @@ QString writeJcond (const HLTYPE &h, Function * pProc, int *numLoc)
/* Displays the inverse output of a HLI_JCOND icode. This is used in the case /* Displays the inverse output of a HLI_JCOND icode. This is used in the case
* when the THEN clause of an if..then..else is empty. The clause is * when the THEN clause of an if..then..else is empty. The clause is
* negated and the ELSE clause is used instead. */ * negated and the ELSE clause is used instead. */
QString writeJcondInv(HLTYPE h, Function * pProc, int *numLoc) QString writeJcondInv(HLTYPE h, Function * pProc, int *numLoc)
{ {
QString _form; QString _form;
@ -532,7 +536,7 @@ QString AssignType::writeOut(Function *pProc, int *numLoc) const
{ {
return QString("%1 = %2;\n") return QString("%1 = %2;\n")
.arg(m_lhs->walkCondExpr (pProc, numLoc)) .arg(m_lhs->walkCondExpr (pProc, numLoc))
.arg(rhs->walkCondExpr (pProc, numLoc)); .arg(m_rhs->walkCondExpr (pProc, numLoc));
} }
QString CallType::writeOut(Function *pProc, int *numLoc) const QString CallType::writeOut(Function *pProc, int *numLoc) const
{ {
@ -553,12 +557,13 @@ void HLTYPE::set(Expr *l, Expr *r)
//assert((asgn.lhs==0) and (asgn.rhs==0)); //prevent memory leaks //assert((asgn.lhs==0) and (asgn.rhs==0)); //prevent memory leaks
assert(dynamic_cast<UnaryOperator *>(l)); assert(dynamic_cast<UnaryOperator *>(l));
asgn.m_lhs=l; asgn.m_lhs=l;
asgn.rhs=r; asgn.m_rhs=r;
} }
/* Returns a string with the contents of the current high-level icode. /** Returns a string with the contents of the current high-level icode.
* Note: this routine does not output the contens of HLI_JCOND icodes. This is * \note this routine does not output the contens of HLI_JCOND icodes. This is
* done in a separate routine to be able to support the removal of * done in a separate routine to be able to support the removal of
* empty THEN clauses on an if..then..else. */ * empty THEN clauses on an if..then..else.
*/
QString HLTYPE::write1HlIcode (Function * pProc, int *numLoc) const QString HLTYPE::write1HlIcode (Function * pProc, int *numLoc) const
{ {
const HlTypeSupport *p = get(); const HlTypeSupport *p = get();

View File

@ -4,8 +4,8 @@
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "dcc.h" #include "dcc.h"
#include "types.h" // Common types like uint8_t, etc #include "types.h" // Common types like uint8_t, etc
#include "ast.h" // Some icode types depend on these #include "ast.h" // Some icode types depend on these
#include <stdlib.h> #include <stdlib.h>
@ -15,10 +15,8 @@ CIcodeRec::CIcodeRec()
{ {
} }
/* Copies the icode that is pointed to by pIcode to the icode array. /* Copies the icode that is pointed to by pIcode to the icode array. */
* If there is need to allocate extra memory, it is done so, and ICODE * CIcodeRec::addIcode(const ICODE *pIcode)
* the alloc variable is adjusted. */
ICODE * CIcodeRec::addIcode(ICODE *pIcode)
{ {
push_back(*pIcode); push_back(*pIcode);
back().loc_ip = size()-1; back().loc_ip = size()-1;
@ -67,6 +65,15 @@ extern bundle cCode;
* is created and a goto is also emitted. * is created and a goto is also emitted.
* Note: this procedure is to be used when the label is to be backpatched * Note: this procedure is to be used when the label is to be backpatched
* onto code in cCode.code */ * onto code in cCode.code */
void LLInst::clrFlags(uint32_t flag)
{
if(getOpcode()==iMOD)
{
assert(false);
}
flg &= ~flag;
}
void LLInst::emitGotoLabel (int indLevel) void LLInst::emitGotoLabel (int indLevel)
{ {
if ( not testFlags(HLL_LABEL) ) /* node hasn't got a lab */ if ( not testFlags(HLL_LABEL) ) /* node hasn't got a lab */
@ -75,8 +82,7 @@ void LLInst::emitGotoLabel (int indLevel)
hllLabNum = getNextLabel(); hllLabNum = getNextLabel();
setFlags(HLL_LABEL); setFlags(HLL_LABEL);
/* Node has been traversed already, so backpatch this label into /* Node has been traversed already, so backpatch this label into the code */
* the code */
cCode.code.addLabelBundle (codeIdx, hllLabNum); cCode.code.addLabelBundle (codeIdx, hllLabNum);
} }
cCode.appendCode( "%sgoto L%ld;\n", indentStr(indLevel), hllLabNum); cCode.appendCode( "%sgoto L%ld;\n", indentStr(indLevel), hllLabNum);
@ -89,7 +95,7 @@ bool LLOperand::isReg() const
{ {
return (regi>=rAX) and (regi<=rTMP); return (regi>=rAX) and (regi<=rTMP);
} }
void LLOperand::addProcInformation(int param_count, CConv::Type call_conv) void LLOperand::addProcInformation(int param_count, CConv::CC_Type call_conv)
{ {
proc.proc->cbParam = (int16_t)param_count; proc.proc->cbParam = (int16_t)param_count;
proc.cb = param_count; proc.cb = param_count;

View File

@ -124,11 +124,10 @@ void Function::findIdioms()
/* Check for library functions that return a long register. /* Check for library functions that return a long register.
* Propagate this result */ * Propagate this result */
if (pIcode->ll()->src().proc.proc != nullptr) if (pIcode->ll()->src().proc.proc != nullptr)
if ((pIcode->ll()->src().proc.proc->flg & PROC_ISLIB) and if ( pIcode->ll()->src().proc.proc->flg & PROC_ISLIB )
(pIcode->ll()->src().proc.proc->flg & PROC_IS_FUNC))
{ {
if ((pIcode->ll()->src().proc.proc->retVal.type==TYPE_LONG_SIGN) if ((pIcode->ll()->src().proc.proc->getReturnType()==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->retVal.type == TYPE_LONG_UNSIGN)) or (pIcode->ll()->src().proc.proc->getReturnType() == TYPE_LONG_UNSIGN))
localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/); localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/);
} }
@ -188,7 +187,7 @@ void Function::findIdioms()
(pIcode++)->invalidate(); (pIcode++)->invalidate();
break; break;
case iENTER: /* ENTER is equivalent to init PUSH bp */ case iENTER: /* ENTER is equivalent to init PUSH bp */
if (pIcode == Icode.begin()) //ip == 0 if (pIcode == Icode.begin()) //ip == 0
{ {
flg |= (PROC_HLL | PROC_IS_HLL); flg |= (PROC_HLL | PROC_IS_HLL);
@ -214,7 +213,7 @@ void Function::findIdioms()
if ((flg & PROC_HLL) and (not args.empty())) if ((flg & PROC_HLL) and (not args.empty()))
{ {
args.m_minOff += (flg & PROC_FAR ? 4 : 2); args.m_minOff += (flg & PROC_FAR ? 4 : 2);
delta = args.maxOff - args.m_minOff; delta = args.m_maxOff - args.m_minOff;
if (cbParam != delta) if (cbParam != delta)
{ {
cbParam = delta; cbParam = delta;
@ -238,7 +237,7 @@ void Function::bindIcodeOff()
for(ICODE &c : Icode) // TODO: use filtered here for(ICODE &c : Icode) // TODO: use filtered here
{ {
LLInst *ll=c.ll(); LLInst *ll=c.ll();
if (ll->testFlags(I) and ll->isJmpInst()) if (ll->srcIsImmed() and ll->isJmpInst())
{ {
iICODE loc=Icode.labelSrch(ll->src().getImm2()); iICODE loc=Icode.labelSrch(ll->src().getImm2());
if (loc!=Icode.end()) if (loc!=Icode.end())
@ -255,7 +254,7 @@ void Function::bindIcodeOff()
LLInst *ll=icode.ll(); LLInst *ll=icode.ll();
if (not ll->isJmpInst()) if (not ll->isJmpInst())
continue; continue;
if (ll->testFlags(I) ) if (ll->srcIsImmed())
{ {
uint32_t found; uint32_t found;
if (not Icode.labelSrch(ll->src().getImm2(), found)) if (not Icode.labelSrch(ll->src().getImm2(), found))

View File

@ -80,17 +80,17 @@ int Idiom6::action()
/***************************************************************************** /*****************************************************************************
* idiom 18: Post-increment or post-decrement in a conditional jump * idiom 18: Post-increment or post-decrement in a conditional jump
* Used * Used
* 0 MOV reg, var (including register variables) * 0 MOV reg, var (including register variables)
* 1 INC var or DEC var <------------------------- input point * 1 INC var or DEC var <------------------------- input point
* 2 CMP var, Y * 2 CMP var, Y
* 3 JX label * 3 JX label
* => HLI_JCOND (var++ X Y) * => HLI_JCOND (var++ X Y)
* Eg: MOV ax, si * Eg: MOV ax, si
* INC si * INC si
* CMP ax, 8 * CMP ax, 8
* JL labX * JL labX
* => HLI_JCOND (si++ < 8) * => HLI_JCOND (si++ < 8)
* Found in Borland Turbo C. Intrinsic to C languages. * Found in Borland Turbo C. Intrinsic to C languages.
****************************************************************************/ ****************************************************************************/
bool Idiom18::match(iICODE picode) bool Idiom18::match(iICODE picode)
{ {
@ -106,7 +106,7 @@ bool Idiom18::match(iICODE picode)
m_idiom_type=-1; m_idiom_type=-1;
m_is_dec = m_icodes[1]->ll()->match(iDEC); m_is_dec = m_icodes[1]->ll()->match(iDEC);
uint8_t regi; /* register of the MOV */ uint8_t regi; /* register of the MOV */
if(not m_icodes[0]->ll()->matchWithRegDst(iMOV) ) if(not m_icodes[0]->ll()->matchWithRegDst(iMOV) )
return false; return false;
regi = m_icodes[0]->ll()->m_dst.regi; regi = m_icodes[0]->ll()->m_dst.regi;
@ -115,12 +115,12 @@ bool Idiom18::match(iICODE picode)
return false; return false;
// Simple matching finished, select apropriate matcher based on dst type // Simple matching finished, select apropriate matcher based on dst type
/* Get variable */ /* Get variable */
if (m_icodes[1]->ll()->m_dst.regi == 0) /* global variable */ if (m_icodes[1]->ll()->m_dst.regi == 0) /* global variable */
{ {
/* not supported yet */ /* not supported yet */
m_idiom_type = 0; m_idiom_type = 0;
} }
else if ( m_icodes[1]->ll()->m_dst.isReg() ) /* register */ else if ( m_icodes[1]->ll()->m_dst.isReg() ) /* register */
{ {
m_idiom_type = 1; m_idiom_type = 1;
// if ((m_icodes[1]->ll()->dst.regi == rSI) and (m_func->flg & SI_REGVAR)) // if ((m_icodes[1]->ll()->dst.regi == rSI) and (m_func->flg & SI_REGVAR))
@ -128,9 +128,9 @@ bool Idiom18::match(iICODE picode)
// else if ((m_icodes[1]->ll()->dst.regi == rDI) and (m_func->flg & DI_REGVAR)) // else if ((m_icodes[1]->ll()->dst.regi == rDI) and (m_func->flg & DI_REGVAR))
// m_idiom_type = 1; // m_idiom_type = 1;
} }
else if (m_icodes[1]->ll()->m_dst.off) /* local variable */ else if (m_icodes[1]->ll()->m_dst.off) /* local variable */
m_idiom_type = 2; m_idiom_type = 2;
else /* indexed */ else /* indexed */
{ {
m_idiom_type=3; m_idiom_type=3;
/* not supported yet */ /* not supported yet */
@ -187,13 +187,13 @@ int Idiom18::action() // action length
/***************************************************************************** /*****************************************************************************
* idiom 19: pre-increment or pre-decrement in conditional jump, comparing against 0. * idiom 19: pre-increment or pre-decrement in conditional jump, comparing against 0.
* [INC | DEC] var (including register vars) * [INC | DEC] var (including register vars)
* JX lab JX lab * JX lab JX lab
* => HLI_JCOND (++var X 0) or HLI_JCOND (--var X 0) * => HLI_JCOND (++var X 0) or HLI_JCOND (--var X 0)
* Eg: INC [bp+4] * Eg: INC [bp+4]
* JG lab2 * JG lab2
* => HLI_JCOND (++[bp+4] > 0) * => HLI_JCOND (++[bp+4] > 0)
* Found in Borland Turbo C. Intrinsic to C language. * Found in Borland Turbo C. Intrinsic to C language.
****************************************************************************/ ****************************************************************************/
bool Idiom19::match(iICODE picode) bool Idiom19::match(iICODE picode)
{ {
@ -206,7 +206,7 @@ bool Idiom19::match(iICODE picode)
m_is_dec = m_icodes[0]->ll()->match(iDEC); m_is_dec = m_icodes[0]->ll()->match(iDEC);
if ( not m_icodes[1]->ll()->conditionalJump() ) if ( not m_icodes[1]->ll()->conditionalJump() )
return false; return false;
if (m_icodes[0]->ll()->m_dst.regi == 0) /* global variable */ if (m_icodes[0]->ll()->m_dst.regi == 0) /* global variable */
/* not supported yet */ ; /* not supported yet */ ;
else if ( m_icodes[0]->ll()->m_dst.isReg() ) /* register */ else if ( m_icodes[0]->ll()->m_dst.isReg() ) /* register */
{ {
@ -214,11 +214,11 @@ bool Idiom19::match(iICODE picode)
// ((picode->ll()->dst.regi == rDI) and (pproc->flg & DI_REGVAR))) // ((picode->ll()->dst.regi == rDI) and (pproc->flg & DI_REGVAR)))
return true; return true;
} }
else if (m_icodes[0]->ll()->m_dst.off) /* stack variable */ else if (m_icodes[0]->ll()->m_dst.off) /* stack variable */
{ {
return true; return true;
} }
else /* indexed */ else /* indexed */
{ {
fprintf(stderr,"idiom19 : Untested type [indexed]\n"); fprintf(stderr,"idiom19 : Untested type [indexed]\n");
return true; return true;
@ -241,23 +241,23 @@ int Idiom19::action()
/***************************************************************************** /*****************************************************************************
* idiom20: Pre increment/decrement in conditional expression (compares * idiom20: Pre increment/decrement in conditional expression (compares
* against a register, variable or constant different than 0). * against a register, variable or constant different than 0).
* INC var or DEC var (including register vars) * INC var or DEC var (including register vars)
* MOV reg, var MOV reg, var * MOV reg, var MOV reg, var
* CMP reg, Y CMP reg, Y * CMP reg, Y CMP reg, Y
* JX lab JX lab * JX lab JX lab
* => HLI_JCOND (++var X Y) or HLI_JCOND (--var X Y) * => HLI_JCOND (++var X Y) or HLI_JCOND (--var X Y)
* Eg: INC si (si is a register variable) * Eg: INC si (si is a register variable)
* MOV ax, si * MOV ax, si
* CMP ax, 2 * CMP ax, 2
* JL lab4 * JL lab4
* => HLI_JCOND (++si < 2) * => HLI_JCOND (++si < 2)
* Found in Turbo C. Intrinsic to C language. * Found in Turbo C. Intrinsic to C language.
****************************************************************************/ ****************************************************************************/
bool Idiom20::match(iICODE picode) bool Idiom20::match(iICODE picode)
{ {
uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */ uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
uint8_t regi; /* register of the MOV */ uint8_t regi; /* register of the MOV */
if(std::distance(picode,m_end)<4) if(std::distance(picode,m_end)<4)
return false; return false;
for(int i=0; i<4; ++i) for(int i=0; i<4; ++i)
@ -270,11 +270,11 @@ bool Idiom20::match(iICODE picode)
const LLOperand &ll_dest(m_icodes[0]->ll()->m_dst); const LLOperand &ll_dest(m_icodes[0]->ll()->m_dst);
/* Get variable */ /* Get variable */
if (ll_dest.regi == 0) /* global variable */ if (ll_dest.regi == 0) /* global variable */
{ {
/* not supported yet */ ; /* not supported yet */ ;
} }
else if ( ll_dest.isReg() ) /* register */ else if ( ll_dest.isReg() ) /* register */
{ {
type = 1; type = 1;
// if ((ll_dest.regi == rSI) and (m_func->flg & SI_REGVAR)) // if ((ll_dest.regi == rSI) and (m_func->flg & SI_REGVAR))
@ -282,9 +282,9 @@ bool Idiom20::match(iICODE picode)
// else if ((ll_dest.regi == rDI) and (m_func->flg & DI_REGVAR)) // else if ((ll_dest.regi == rDI) and (m_func->flg & DI_REGVAR))
// type = 1; // type = 1;
} }
else if (ll_dest.off) /* local variable */ else if (ll_dest.off) /* local variable */
type = 2; type = 2;
else /* indexed */ else /* indexed */
{ {
printf("idiom20 : Untested type [indexed]\n"); printf("idiom20 : Untested type [indexed]\n");
type = 3; type = 3;

View File

@ -11,9 +11,9 @@ using namespace std;
* Eg: CALL proc_X * Eg: CALL proc_X
* ADD SP, 6 * ADD SP, 6
* => pProc->cbParam = immed * => pProc->cbParam = immed
* Special case: when the call is at the end of the procedure, * Special case: when the call is at the end of the procedure,
* sometimes the stack gets restored by a MOV sp, bp. * sometimes the stack gets restored by a MOV sp, bp.
* Need to flag the procedure in these cases. * Need to flag the procedure in these cases.
* Used by compilers to restore the stack when invoking a procedure using * Used by compilers to restore the stack when invoking a procedure using
* the C calling convention. * the C calling convention.
****************************************************************************/ ****************************************************************************/
@ -25,7 +25,7 @@ bool Idiom3::match(iICODE picode)
/* Match ADD SP, immed */ /* Match ADD SP, immed */
for(int i=0; i<2; ++i) for(int i=0; i<2; ++i)
m_icodes[i] = picode++; m_icodes[i] = picode++;
if ( m_icodes[1]->ll()->testFlags(I) and m_icodes[1]->ll()->match(iADD,rSP)) if ( m_icodes[1]->ll()->srcIsImmed() and m_icodes[1]->ll()->match(iADD,rSP))
{ {
m_param_count = m_icodes[1]->ll()->src().getImm2(); m_param_count = m_icodes[1]->ll()->src().getImm2();
return true; return true;
@ -39,7 +39,7 @@ bool Idiom3::match(iICODE picode)
} }
int Idiom3::action() int Idiom3::action()
{ {
if (m_icodes[0]->ll()->testFlags(I) ) if (m_icodes[0]->ll()->srcIsImmed())
{ {
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C); m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
} }
@ -97,7 +97,7 @@ bool Idiom17::match(iICODE picode)
} }
int Idiom17::action() int Idiom17::action()
{ {
if (m_icodes[0]->ll()->testFlags(I)) if (m_icodes[0]->ll()->srcIsImmed())
{ {
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C); m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
for(size_t idx=1; idx<m_icodes.size(); ++idx) for(size_t idx=1; idx<m_icodes.size(); ++idx)

View File

@ -48,7 +48,7 @@ bool Idiom2::match(iICODE pIcode)
iICODE nicode; iICODE nicode;
if(pIcode==m_func->Icode.begin()) // pIcode->loc_ip == 0 if(pIcode==m_func->Icode.begin()) // pIcode->loc_ip == 0
return false; return false;
if ( pIcode->ll()->testFlags(I) or (not pIcode->ll()->match(rSP,rBP)) ) if ( pIcode->ll()->srcIsImmed() or (not pIcode->ll()->match(rSP,rBP)) )
return false; return false;
if(distance(pIcode,m_end)<3) if(distance(pIcode,m_end)<3)
return false; return false;
@ -63,7 +63,7 @@ bool Idiom2::match(iICODE pIcode)
} }
if(nicode == m_end) if(nicode == m_end)
return false; return false;
//TODO: strange test here - 'I' means instruction has immediate source operand
if (nicode->ll()->match(iPOP,rBP) and not (nicode->ll()->testFlags(I | TARGET | CASE)) ) if (nicode->ll()->match(iPOP,rBP) and not (nicode->ll()->testFlags(I | TARGET | CASE)) )
{ {
m_icodes.push_back(nicode++); // Matched POP BP m_icodes.push_back(nicode++); // Matched POP BP
@ -71,7 +71,7 @@ bool Idiom2::match(iICODE pIcode)
/* Match RET(F) */ /* Match RET(F) */
if ( nicode != m_end and if ( nicode != m_end and
not (nicode->ll()->testFlags(I | TARGET | CASE)) and not (nicode->ll()->testFlags(I | TARGET | CASE)) and
(nicode->ll()->match(iRET) or nicode->ll()->match(iRETF)) nicode->ll()->matchAny({iRET,iRETF})
) )
{ {
m_icodes.push_back(nicode); // Matched RET m_icodes.push_back(nicode); // Matched RET
@ -95,15 +95,15 @@ int Idiom2::action()
* RET(F) immed * RET(F) immed
* ==> pProc->cbParam = immed * ==> pProc->cbParam = immed
* sets CALL_PASCAL flag * sets CALL_PASCAL flag
* - Second version: check for optional pop of stack vars * - Second version: check for optional pop of stack vars
* [POP DI] * [POP DI]
* [POP SI] * [POP SI]
* POP BP * POP BP
* RET(F) [immed] * RET(F) [immed]
* - Third version: pop stack vars * - Third version: pop stack vars
* [POP DI] * [POP DI]
* [POP SI] * [POP SI]
* RET(F) [immed] * RET(F) [immed]
****************************************************************************/ ****************************************************************************/
bool Idiom4::match(iICODE pIcode) bool Idiom4::match(iICODE pIcode)
{ {
@ -120,7 +120,7 @@ bool Idiom4::match(iICODE pIcode)
{ {
iICODE prev1 = --iICODE(pIcode); iICODE prev1 = --iICODE(pIcode);
/* Check for POP BP */ /* Check for POP BP */
if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->testFlags(I) ) if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->srcIsImmed() )
m_icodes.push_back(prev1); m_icodes.push_back(prev1);
else if(prev1!=m_func->Icode.begin()) else if(prev1!=m_func->Icode.begin())
{ {
@ -131,7 +131,7 @@ bool Idiom4::match(iICODE pIcode)
} }
/* Check for RET(F) immed */ /* Check for RET(F) immed */
if (pIcode->ll()->testFlags(I) ) if (pIcode->ll()->srcIsImmed() )
{ {
m_param_count = (int16_t)pIcode->ll()->src().getImm2(); m_param_count = (int16_t)pIcode->ll()->src().getImm2();
return true; return true;

View File

@ -53,8 +53,8 @@ int Idiom1::checkStkVars (iICODE pIcode)
****************************************************************************/ ****************************************************************************/
bool Idiom1::match(iICODE picode) bool Idiom1::match(iICODE picode)
{ {
//uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */ //uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
//uint8_t regi; /* register of the MOV */ //uint8_t regi; /* register of the MOV */
if(m_func->flg & PROC_HLL) if(m_func->flg & PROC_HLL)
return false; return false;
if(picode==m_end) if(picode==m_end)
@ -63,7 +63,7 @@ bool Idiom1::match(iICODE picode)
m_icodes.clear(); m_icodes.clear();
m_min_off = 0; m_min_off = 0;
/* PUSH BP as first instruction of procedure */ /* PUSH BP as first instruction of procedure */
if ( (not picode->ll()->testFlags(I)) and picode->ll()->src().regi == rBP) if ( (not picode->ll()->srcIsImmed()) and picode->ll()->src().regi == rBP)
{ {
m_icodes.push_back( picode++ ); // insert iPUSH m_icodes.push_back( picode++ ); // insert iPUSH
if(picode==m_end) if(picode==m_end)
@ -109,10 +109,10 @@ bool Idiom1::match(iICODE picode)
m_min_off = 2 + (n * 2); m_min_off = 2 + (n * 2);
} }
else else
return false; // Cristina: check this please! return false; // Cristina: check this please!
} }
else else
return false; // Cristina: check this please! return false; // Cristina: check this please!
} }
} }
else // push di [push si] / push si [push di] else // push di [push si] / push si [push di]

View File

@ -12,14 +12,14 @@ using namespace std;
* Eg: MOV ax, di * Eg: MOV ax, di
* XOR dx, dx * XOR dx, dx
* => MOV dx:ax, di * => MOV dx:ax, di
* Note: only the following combinations are allowed: * Note: only the following combinations are allowed:
* dx:ax * dx:ax
* cx:bx * cx:bx
* this is to remove the possibility of making errors in situations * this is to remove the possibility of making errors in situations
* like this: * like this:
* MOV dx, offH * MOV dx, offH
* MOV ax, offL * MOV ax, offL
* XOR cx, cx * XOR cx, cx
* Found in Borland Turbo C, used for division of unsigned integer * Found in Borland Turbo C, used for division of unsigned integer
* operands. * operands.
****************************************************************************/ ****************************************************************************/
@ -33,10 +33,10 @@ bool Idiom14::match(iICODE pIcode)
LLInst * matched [] {m_icodes[0]->ll(),m_icodes[1]->ll()}; LLInst * matched [] {m_icodes[0]->ll(),m_icodes[1]->ll()};
/* Check for regL */ /* Check for regL */
m_regL = matched[0]->m_dst.regi; m_regL = matched[0]->m_dst.regi;
if (not matched[0]->testFlags(I) and ((m_regL == rAX) or (m_regL ==rBX))) if (not matched[0]->srcIsImmed() and ((m_regL == rAX) or (m_regL ==rBX)))
{ {
/* Check for XOR regH, regH */ /* Check for XOR regH, regH */
if (matched[1]->match(iXOR) and not matched[1]->testFlags(I)) if (matched[1]->match(iXOR) and not matched[1]->srcIsImmed())
{ {
m_regH = matched[1]->m_dst.regi; m_regH = matched[1]->m_dst.regi;
if (m_regH == matched[1]->src().getReg2()) if (m_regH == matched[1]->src().getReg2())
@ -84,7 +84,7 @@ bool Idiom13::match(iICODE pIcode)
/* Check for regL */ /* Check for regL */
regi = m_icodes[0]->ll()->m_dst.regi; regi = m_icodes[0]->ll()->m_dst.regi;
if (not m_icodes[0]->ll()->testFlags(I) and (regi >= rAL) and (regi <= rBH)) if (not m_icodes[0]->ll()->srcIsImmed() and (regi >= rAL) and (regi <= rBH))
{ {
/* Check for MOV regH, 0 */ /* Check for MOV regH, 0 */
if (m_icodes[1]->ll()->match(iMOV,I) and (m_icodes[1]->ll()->src().getImm2() == 0)) if (m_icodes[1]->ll()->match(iMOV,I) and (m_icodes[1]->ll()->src().getImm2() == 0))

View File

@ -67,15 +67,15 @@ int Idiom11::action()
/***************************************************************************** /*****************************************************************************
* idiom 16: Bitwise negation * idiom 16: Bitwise negation
* NEG reg * NEG reg
* SBB reg, reg * SBB reg, reg
* INC reg * INC reg
* => ASGN reg, !reg * => ASGN reg, !reg
* Eg: NEG ax * Eg: NEG ax
* SBB ax, ax * SBB ax, ax
* INC ax * INC ax
* => ax = !ax * => ax = !ax
* Found in Borland Turbo C when negating bitwise. * Found in Borland Turbo C when negating bitwise.
****************************************************************************/ ****************************************************************************/
bool Idiom16::match (iICODE picode) bool Idiom16::match (iICODE picode)
{ {

View File

@ -21,7 +21,7 @@ bool Idiom8::match(iICODE pIcode)
return false; return false;
m_icodes[0]=pIcode++; m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++; m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1)) if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if ( m_icodes[1]->ll()->match(iRCR,I) and if ( m_icodes[1]->ll()->match(iRCR,I) and
(m_icodes[1]->ll()->src().getImm2() == 1)) (m_icodes[1]->ll()->src().getImm2() == 1))
return true; return true;
@ -65,7 +65,7 @@ bool Idiom15::match(iICODE pIcode)
if(distance(pIcode,m_end)<2) if(distance(pIcode,m_end)<2)
return false; return false;
/* Match SHL reg, 1 */ /* Match SHL reg, 1 */
if (not pIcode->ll()->testFlags(I) or (pIcode->ll()->src().getImm2() != 1)) if (not pIcode->ll()->srcIsImmed() or (pIcode->ll()->src().getImm2() != 1))
return false; return false;
m_icodes.clear(); m_icodes.clear();
regi = pIcode->ll()->m_dst.regi; regi = pIcode->ll()->m_dst.regi;
@ -110,7 +110,7 @@ bool Idiom12::match(iICODE pIcode)
return false; return false;
m_icodes[0]=pIcode++; m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++; m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1)) if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[1]->ll()->match(iRCL,I) and (m_icodes[1]->ll()->src().getImm2() == 1)) if (m_icodes[1]->ll()->match(iRCL,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
return true; return true;
return false; return false;
@ -150,7 +150,7 @@ bool Idiom9::match(iICODE pIcode)
return false; return false;
m_icodes[0]=pIcode++; m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++; m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1)) if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[1]->ll()->match(iRCR,I) and (m_icodes[1]->ll()->src().getImm2() == 1)) if (m_icodes[1]->ll()->match(iRCR,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
return true; return true;
return false; return false;

View File

@ -7,16 +7,16 @@ using namespace std;
/***************************************************************************** /*****************************************************************************
* idiom21 - Assign long kte with high part zero * idiom21 - Assign long kte with high part zero
* XOR regH, regH * XOR regH, regH
* MOV regL, kte * MOV regL, kte
* => regH:regL = kte * => regH:regL = kte
* Eg: XOR dx, dx * Eg: XOR dx, dx
* MOV ax, 3 * MOV ax, 3
* => dx:ax = 3 * => dx:ax = 3
* Note: only the following valid combinations are available: * Note: only the following valid combinations are available:
* dx:ax * dx:ax
* cx:bx * cx:bx
* Found in Borland Turbo C code. * Found in Borland Turbo C code.
****************************************************************************/ ****************************************************************************/
bool Idiom21::match (iICODE picode) bool Idiom21::match (iICODE picode)
{ {
@ -26,7 +26,7 @@ bool Idiom21::match (iICODE picode)
m_icodes[0]=picode++; m_icodes[0]=picode++;
m_icodes[1]=picode++; m_icodes[1]=picode++;
if (not m_icodes[1]->ll()->testFlags(I)) if (not m_icodes[1]->ll()->srcIsImmed())
return false; return false;
dst = &m_icodes[0]->ll()->m_dst; dst = &m_icodes[0]->ll()->m_dst;
@ -48,7 +48,7 @@ int Idiom21::action()
lhs = AstIdent::Long (&m_func->localId, DST, m_icodes[0],HIGH_FIRST, m_icodes[0], eDEF, *m_icodes[1]->ll()); lhs = AstIdent::Long (&m_func->localId, DST, m_icodes[0],HIGH_FIRST, m_icodes[0], eDEF, *m_icodes[1]->ll());
rhs = new Constant(m_icodes[1]->ll()->src().getImm2(), 4); rhs = new Constant(m_icodes[1]->ll()->src().getImm2(), 4);
m_icodes[0]->setAsgn(lhs, rhs); m_icodes[0]->setAsgn(lhs, rhs);
m_icodes[0]->du.use.reset(); /* clear register used in iXOR */ m_icodes[0]->du.use.reset(); /* clear register used in iXOR */
m_icodes[1]->invalidate(); m_icodes[1]->invalidate();
return 2; return 2;
} }
@ -87,8 +87,8 @@ bool Idiom7::match(iICODE picode)
} }
int Idiom7::action() int Idiom7::action()
{ {
Expr *lhs; Expr *lhs = AstIdent::id (*m_icode->ll(), DST, m_func, m_icode, *m_icode, NONE);
lhs = AstIdent::id (*m_icode->ll(), DST, m_func, m_icode, *m_icode, NONE);
m_icode->setAsgn(dynamic_cast<AstIdent *>(lhs), new Constant(0, 2)); m_icode->setAsgn(dynamic_cast<AstIdent *>(lhs), new Constant(0, 2));
m_icode->du.use.reset(); /* clear register used in iXOR */ m_icode->du.use.reset(); /* clear register used in iXOR */
m_icode->ll()->setFlags(I); m_icode->ll()->setFlags(I);
@ -103,11 +103,11 @@ int Idiom7::action()
* Eg: OR ax, ax * Eg: OR ax, ax
* JNE labX * JNE labX
* => CMP reg 0 * => CMP reg 0
* JNE labX * JNE labX
* This instruction is NOT converted into the equivalent high-level * This instruction is NOT converted into the equivalent high-level
* instruction "HLI_JCOND (reg != 0) labX" because we do not know yet if * instruction "HLI_JCOND (reg != 0) labX" because we do not know yet if
* it forms part of a long register conditional test. It is therefore * it forms part of a long register conditional test. It is therefore
* modified to simplify the analysis. * modified to simplify the analysis.
* Found in Borland Turbo C. * Found in Borland Turbo C.
****************************************************************************/ ****************************************************************************/
bool Idiom10::match(iICODE pIcode) bool Idiom10::match(iICODE pIcode)
@ -117,7 +117,7 @@ bool Idiom10::match(iICODE pIcode)
m_icodes[0]=pIcode++; m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++; m_icodes[1]=pIcode++;
/* Check OR reg, reg */ /* Check OR reg, reg */
if (not m_icodes[0]->ll()->testFlags(I) and if (not m_icodes[0]->ll()->srcIsImmed() and
m_icodes[0]->ll()->src().isReg() and m_icodes[0]->ll()->src().isReg() and
(m_icodes[0]->ll()->src().getReg2() == m_icodes[0]->ll()->m_dst.getReg2())) (m_icodes[0]->ll()->src().getReg2() == m_icodes[0]->ll()->m_dst.getReg2()))
if (m_icodes[1]->ll()->match(iJNE)) //.conditionalJump() if (m_icodes[1]->ll()->match(iJNE)) //.conditionalJump()

View File

@ -204,8 +204,8 @@ int LOCAL_ID::newLongReg(hlType t, const LONGID_TYPE &longT, iICODE ix_)
id_arr.back().idx.push_back(ix_); id_arr.back().idx.push_back(ix_);
return (id_arr.size() - 1); return (id_arr.size() - 1);
} }
/* Returns an identifier conditional expression node of type TYPE_LONG or /** Returns an identifier conditional expression node of type TYPE_LONG or
* TYPE_WORD_SIGN */ * TYPE_WORD_SIGN */
AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_) AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_)
{ {
return AstIdent::idID(retVal,this,ix_); return AstIdent::idID(retVal,this,ix_);
@ -449,14 +449,15 @@ eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
else if (id->longId().l() == regi) else if (id->longId().l() == regi)
return (id->longId().h()); return (id->longId().h());
} }
return rUNDEF; // Cristina: please check this! return rUNDEF; // Cristina: please check this!
} }
/* Checks if the registers regL and regH have been used independently in /**
* Checks if the registers regL and regH have been used independently in
* the local identifier table. If so, macros for these registers are * the local identifier table. If so, macros for these registers are
* placed in the local identifier table, as these registers belong to a * placed in the local identifier table, as these registers belong to a
* long register identifier. */ * long register identifier. */
void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name) void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name)
{ {
for (ID &rid : id_arr) for (ID &rid : id_arr)

View File

@ -47,7 +47,7 @@ static const QString szOps[] =
"RCL", "RCR", "ROL", "ROR", "RET", "RETF", "SAHF", "SAR", "RCL", "RCR", "ROL", "ROR", "RET", "RETF", "SAHF", "SAR",
"SHL", "SHR", "SBB", "SCAS", "REPNE SCAS","REPE SCAS", "CWD", "STC", "SHL", "SHR", "SBB", "SCAS", "REPNE SCAS","REPE SCAS", "CWD", "STC",
"STD", "STI", "STOS", "REP STOS", "SUB", "TEST", "WAIT", "XCHG", "STD", "STI", "STOS", "REP STOS", "SUB", "TEST", "WAIT", "XCHG",
"XLAT", "XOR", "INTO", "NOP", "REPNE", "REPE", "MOD" "XLAT", "XOR", "INTO", "NOP", "REPNE", "REPE", "MOD"
}; };
/* The following opcodes are for mod != 3 */ /* The following opcodes are for mod != 3 */
static const QString szFlops1[] = static const QString szFlops1[] =

View File

@ -2,14 +2,18 @@
* dcc project procedure list builder * dcc project procedure list builder
* (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann * (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
****************************************************************************/ ****************************************************************************/
#include "parser.h"
#include "dcc.h" #include "dcc.h"
#include "project.h" #include "project.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "chklib.h"
#include "FollowControlFlow.h"
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <stdlib.h> /* For exit() */ #include <stdlib.h> /* For exit() */
#include <sstream> #include <sstream>
#include <stdio.h> #include <stdio.h>
#include <algorithm> #include <algorithm>
@ -17,15 +21,21 @@
#include <QMap> #include <QMap>
#include <QtCore/QDebug> #include <QtCore/QDebug>
//TODO: The OS service resolution should be done iteratively:
// for every unprocessed INT instruction, that calls OS service that does not terminate execution
// mark INT as non-termination instruction
// follow execution flow from next instruction
// recheck OS services
using namespace std; using namespace std;
//static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate); //static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
static void setBits(int16_t type, uint32_t start, uint32_t len); static void setBits(int16_t type, uint32_t start, uint32_t len);
static void process_MOV(LLInst &ll, STATE * pstate); static void process_MOV(LLInst &ll, STATE * pstate);
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag); static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph);
void interactDis(Function * initProc, int ic); static bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate);
extern uint32_t SynthLab; static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
//void interactDis(Function * initProc, int ic);
/* Returns the size of the string pointed by sym and delimited by delim. /* Returns the size of the string pointed by sym and delimited by delim.
* Size includes delimiter. */ * Size includes delimiter. */
@ -36,107 +46,158 @@ int strSize (const uint8_t *sym, char delim)
const uint8_t *end_ptr=std::find(sym,sym+(prog.cbImage-(till_end)),delim); const uint8_t *end_ptr=std::find(sym,sym+(prog.cbImage-(till_end)),delim);
return end_ptr-sym+1; return end_ptr-sym+1;
} }
ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
static std::vector<ICODE> rewrite_DIV(LLInst *ll, ICODE &_Icode)
{ {
/* MOV rTMP, reg */ ICODE synth_mov = ICODE(); // MOV rTMP, reg
ICODE synth_mod = ICODE(); // MOD
ICODE eIcode = ICODE(); synth_mov.type = LOW_LEVEL_ICODE;
synth_mov.ll()->set(iMOV,0,rTMP);
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,0,rTMP);
if (ll->testFlags(B) ) if (ll->testFlags(B) )
{ {
eIcode.ll()->setFlags( B ); synth_mov.ll()->setFlags( B );
eIcode.ll()->replaceSrc(rAX); synth_mov.ll()->replaceSrc(rAX);
} }
else /* implicit dx:ax */ else /* implicit dx:ax */
{ {
eIcode.ll()->setFlags( IM_SRC ); synth_mov.ll()->setFlags( IM_SRC );
eIcode.setRegDU( rDX, eUSE); synth_mov.setRegDU( rDX, eUSE);
} }
eIcode.setRegDU( rAX, eUSE); synth_mov.setRegDU( rAX, eUSE);
eIcode.setRegDU( rTMP, eDEF); synth_mov.setRegDU( rTMP, eDEF);
eIcode.ll()->setFlags( SYNTHETIC ); synth_mov.ll()->setFlags( SYNTHETIC );
/* eIcode.ll()->label = SynthLab++; */ /* eIcode.ll()->label = Project::get()->SynthLab++; */
eIcode.ll()->label = _Icode.ll()->label; synth_mov.ll()->label = _Icode.ll()->label;
Icode.addIcode(&eIcode);
/* iDIV, iIDIV */
Icode.addIcode(&_Icode);
/* iMOD */ /* iMOD */
eIcode = ICODE(); synth_mod.type = LOW_LEVEL_ICODE;
eIcode.type = LOW_LEVEL_ICODE; synth_mod.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST); synth_mod.ll()->replaceSrc(_Icode.ll()->src());
eIcode.ll()->replaceSrc(_Icode.ll()->src()); synth_mod.du = _Icode.du;
eIcode.du = _Icode.du; synth_mod.ll()->label = Project::get()->SynthLab++;
eIcode.ll()->label = SynthLab++; return {
return Icode.addIcode(&eIcode); synth_mov,
_Icode,
synth_mod
};
} }
ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode) static std::vector<ICODE> rewrite_XCHG(LLInst *ll,ICODE &_Icode)
{ {
/* MOV rTMP, regDst */ /* MOV rTMP, regDst */
ICODE eIcode; ICODE mov_tmp_dst;
eIcode.type = LOW_LEVEL_ICODE; mov_tmp_dst.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst); mov_tmp_dst.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
eIcode.setRegDU( rTMP, eDEF); mov_tmp_dst.setRegDU( rTMP, eDEF);
if(eIcode.ll()->src().getReg2()) if(mov_tmp_dst.ll()->src().getReg2())
{ {
eReg srcreg=eIcode.ll()->src().getReg2(); eReg srcreg=mov_tmp_dst.ll()->src().getReg2();
eIcode.setRegDU( srcreg, eUSE); mov_tmp_dst.setRegDU( srcreg, eUSE);
if((srcreg>=rAL) and (srcreg<=rBH)) if((srcreg>=rAL) and (srcreg<=rBH))
eIcode.ll()->setFlags( B ); mov_tmp_dst.ll()->setFlags( B );
} }
eIcode.ll()->label = ll->label; mov_tmp_dst.ll()->label = ll->label;
Icode.addIcode(&eIcode);
/* MOV regDst, regSrc */ /* MOV regDst, regSrc */
ll->set(iMOV,SYNTHETIC|ll->getFlag()); ICODE mov_dst_src = _Icode; // copy all XCHG things, but set opcode to iMOV and mark it as synthetic insn
Icode.addIcode(&_Icode); mov_dst_src.ll()->set(iMOV,SYNTHETIC|ll->getFlag());
ll->setOpcode(iXCHG); /* for next case */
/* MOV regSrc, rTMP */ /* MOV regSrc, rTMP */
eIcode = ICODE();
eIcode.type = LOW_LEVEL_ICODE; ICODE mov_src_tmp;
eIcode.ll()->set(iMOV,SYNTHETIC); mov_src_tmp.type = LOW_LEVEL_ICODE;
eIcode.ll()->replaceDst(ll->src()); mov_src_tmp.ll()->set(iMOV,SYNTHETIC);
if(eIcode.ll()->m_dst.regi) mov_src_tmp.ll()->replaceDst(ll->src());
if(mov_src_tmp.ll()->m_dst.regi)
{ {
if((eIcode.ll()->m_dst.regi>=rAL) and (eIcode.ll()->m_dst.regi<=rBH)) if((mov_src_tmp.ll()->m_dst.regi>=rAL) and (mov_src_tmp.ll()->m_dst.regi<=rBH))
eIcode.ll()->setFlags( B ); mov_src_tmp.ll()->setFlags( B );
eIcode.setRegDU( eIcode.ll()->m_dst.regi, eDEF); mov_src_tmp.setRegDU( mov_src_tmp.ll()->m_dst.regi, eDEF);
} }
eIcode.ll()->replaceSrc(rTMP); mov_src_tmp.ll()->replaceSrc(rTMP);
eIcode.setRegDU( rTMP, eUSE); mov_src_tmp.setRegDU( rTMP, eUSE);
eIcode.ll()->label = SynthLab++; mov_src_tmp.ll()->label = Project::get()->SynthLab++;
return Icode.addIcode(&eIcode); return {
mov_tmp_dst,
mov_dst_src,
mov_src_tmp
};
}
/**
* @brief resolveOSServices
* @param ll
* @param pstate
* @return true if given OS service will terminate the program
*/
//TODO: convert into Command class
static bool resolveOSServices(LLInst *ll, STATE *pstate)
{
PROG &prog(Project::get()->prog);
SYMTAB &global_symbol_table(Project::get()->symtab);
bool terminates=false;
if(pstate->isKnown(rAX))
assert(pstate->isKnown(rAH));
if (ll->src().getImm2() == 0x21 and pstate->isKnown(rAH))
{
int funcNum = pstate->r[rAH];
int operand;
int size;
/* Save function number */
ll->m_dst.off = (int16_t)funcNum;
//Icode.GetIcode(Icode.GetNumIcodes() - 1)->
/* Program termination: int21h, fn 00h, 31h, 4Ch */
terminates = (bool)(funcNum == 0x00 or funcNum == 0x31 or funcNum == 0x4C);
/* String functions: int21h, fn 09h */
/* offset goes into DX */
if (pstate->isKnown(rDX))
if (funcNum == 0x09)
{
operand = ((uint32_t)(uint16_t)pstate->r[rDS]<<4) + (uint32_t)(uint16_t)pstate->r[rDX];
size = prog.fCOM ?
strSize (&prog.image()[operand], '$') :
strSize (&prog.image()[operand], '$'); // + 0x100
global_symbol_table.updateSymType (operand, TypeContainer(TYPE_STR, size));
}
}
else if ((ll->src().getImm2() == 0x2F) and pstate->isKnown(rAH))
{
ll->m_dst.off = pstate->r[rAH];
}
else /* Program termination: int20h, int27h */
terminates = (ll->src().getImm2() == 0x20 or ll->src().getImm2() == 0x27);
return terminates;
} }
/** FollowCtrl - Given an initial procedure, state information and symbol table /** FollowCtrl - Given an initial procedure, state information and symbol table
* builds a list of procedures reachable from the initial procedure * builds a list of procedures reachable from the initial procedure
* using a depth first search. */ * using a depth first search. */
void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate) void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
{ {
Project *project(Project::get());
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */ ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
SYM * psym; SYM * psym;
uint32_t offset; uint32_t offset;
eErrorId err; eErrorId err;
bool done = false; bool done = false;
SYMTAB &global_symbol_table(Project::get()->symtab);
if (name.contains("chkstk")) if (func.name.contains("chkstk"))
{ {
// Danger! Dcc will likely fall over in this code. // Danger! Dcc will likely fall over in this code.
// So we act as though we have done with this proc // So we act as though we have done with this proc
// pProc->flg &= ~TERMINATES; // Not sure about this // pProc->flg &= ~TERMINATES; // Not sure about this
done = true; done = true;
// And mark it as a library function, so structure() won't choke on it // And mark it as a library function, so structure() won't choke on it
flg |= PROC_ISLIB; func.flg |= PROC_ISLIB;
return; return;
} }
if (option.VeryVerbose) if (option.VeryVerbose)
{ {
qDebug() << "Parsing proc" << name << "at"<< QString::number(pstate->IP,16).toUpper(); qDebug() << "Parsing proc" << func.name << "at"<< QString::number(pstate->IP,16).toUpper();
} }
while (not done ) while (not done )
@ -148,28 +209,35 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
pstate->IP += (uint32_t)ll->numBytes; pstate->IP += (uint32_t)ll->numBytes;
setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes); setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes);
process_operands(_Icode,pstate); func.process_operands(_Icode,pstate);
/* Keep track of interesting instruction flags in procedure */ /* Keep track of interesting instruction flags in procedure */
flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP)); func.flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP));
/* Check if this instruction has already been parsed */ /* Check if this instruction has already been parsed */
iICODE labLoc = Icode.labelSrch(ll->label); iICODE labLoc = func.Icode.labelSrch(ll->label);
if (Icode.end()!=labLoc) if (func.Icode.end()!=labLoc)
{ /* Synthetic jump */ { /* Synthetic jump */
_Icode.type = LOW_LEVEL_ICODE; _Icode.type = LOW_LEVEL_ICODE;
ll->set(iJMP,I | SYNTHETIC | NO_OPS); ll->set(iJMP,I | SYNTHETIC | NO_OPS);
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel())); ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
ll->label = SynthLab++; ll->label = Project::get()->SynthLab++;
} }
/* Copy Icode to Proc */ /* Copy Icode to Proc */
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV)) if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV)) {
pIcode = translate_DIV(ll, _Icode); std::vector<ICODE> translated = rewrite_DIV(ll,_Icode);
else if (_Icode.ll()->getOpcode() == iXCHG) for(const ICODE &ic : translated)
pIcode = translate_XCHG(ll, _Icode); pIcode = func.Icode.addIcode(&ic);
else }
pIcode = Icode.addIcode(&_Icode); else if (_Icode.ll()->getOpcode() == iXCHG) {
std::vector<ICODE> translated = rewrite_XCHG(ll,_Icode);
for(const ICODE &ic : translated)
pIcode = func.Icode.addIcode(&ic);
}
else {
pIcode = func.Icode.addIcode(&_Icode);
}
switch (ll->getOpcode()) { switch (ll->getOpcode()) {
/*** Conditional jumps ***/ /*** Conditional jumps ***/
@ -181,48 +249,49 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
case iJCXZ: case iJCXZ:
{ {
STATE StCopy; STATE StCopy;
int ip = Icode.size()-1; /* Index of this jump */ int ip = func.Icode.size()-1; /* Index of this jump */
ICODE &prev(*(++Icode.rbegin())); /* Previous icode */ ICODE &prev(*(++func.Icode.rbegin())); /* Previous icode */
bool fBranch = false; bool fBranch = false;
pstate->JCond.regi = 0; pstate->JCond.regi = 0;
/* This sets up range check for indexed JMPs hopefully /* This sets up range check for indexed JMPs hopefully
* Handles JA/JAE for fall through and JB/JBE on branch * Handles JA/JAE for fall through and JB/JBE on branch
*/ */
if (ip > 0 and prev.ll()->getOpcode() == iCMP and (prev.ll()->testFlags(I))) if (ip > 0 and prev.ll()->match(iCMP,I) )
{ {
pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2(); pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2();
if (ll->match(iJA) or ll->match(iJBE) ) if (ll->match(iJA) or ll->match(iJBE) )
pstate->JCond.immed++; pstate->JCond.immed++;
if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA) if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA)
pstate->JCond.regi = prev.ll()->m_dst.regi; pstate->JCond.regi = prev.ll()->m_dst.regi;
fBranch = (bool) (ll->getOpcode() == iJB or ll->getOpcode() == iJBE); fBranch = (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
} }
StCopy = *pstate; StCopy = *pstate;
/* Straight line code */ /* Straight line code */
this->FollowCtrl (pcallGraph, &StCopy); // recurrent ? project->addCommand(func.shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ?
if (fBranch) /* Do branching code */ if (fBranch) /* Do branching code */
{ {
pstate->JCond.regi = prev.ll()->m_dst.regi; pstate->JCond.regi = prev.ll()->m_dst.regi;
} }
/* Next icode. Note: not the same as GetLastIcode() because of the call /* Next icode. Note: not the same as GetLastIcode() because of the call to FollowCtrl() */
to FollowCtrl() */ pIcode = func.Icode.GetIcode(ip);
pIcode = Icode.GetIcode(ip); /* do the jump path */
} /* Fall through to do the jump path */ done = process_JMP(func.shared_from_this(),*pIcode, pstate, pcallGraph);
break;
}
/*** Jumps ***/ /*** Jumps ***/
case iJMP: case iJMP:
case iJMPF: /* Returns true if we've run into a loop */ case iJMPF: /* Returns true if we've run into a loop */
done = process_JMP (*pIcode, pstate, pcallGraph); done = process_JMP (func.shared_from_this(),*pIcode, pstate, pcallGraph);
break; break;
/*** Calls ***/ /*** Calls ***/
case iCALL: case iCALL:
case iCALLF: case iCALLF:
done = process_CALL (*pIcode, pcallGraph, pstate); done = process_CALL(func.shared_from_this(),*pIcode, pcallGraph, pstate);
pstate->kill(rBX); pstate->kill(rBX);
pstate->kill(rCX); pstate->kill(rCX);
break; break;
@ -230,46 +299,17 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
/*** Returns ***/ /*** Returns ***/
case iRET: case iRET:
case iRETF: case iRETF:
this->flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR; func.flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
/* Fall through */ func.flg &= ~TERMINATES;
done = true;
break;
case iIRET: case iIRET:
this->flg &= ~TERMINATES; func.flg &= ~TERMINATES;
done = true; done = true;
break; break;
case iINT: case iINT:
if (ll->src().getImm2() == 0x21 and pstate->f[rAH]) done = resolveOSServices(ll, pstate);
{
int funcNum = pstate->r[rAH];
int operand;
int size;
/* Save function number */
Icode.back().ll()->m_dst.off = (int16_t)funcNum;
//Icode.GetIcode(Icode.GetNumIcodes() - 1)->
/* Program termination: int21h, fn 00h, 31h, 4Ch */
done = (bool)(funcNum == 0x00 or funcNum == 0x31 or
funcNum == 0x4C);
/* String functions: int21h, fn 09h */
if (pstate->f[rDX]) /* offset goes into DX */
if (funcNum == 0x09)
{
operand = ((uint32_t)(uint16_t)pstate->r[rDS]<<4) +
(uint32_t)(uint16_t)pstate->r[rDX];
size = prog.fCOM ?
strSize (&prog.image()[operand], '$') :
strSize (&prog.image()[operand], '$'); // + 0x100
global_symbol_table.updateSymType (operand, TypeContainer(TYPE_STR, size));
}
}
else if ((ll->src().getImm2() == 0x2F) and (pstate->f[rAH]))
{
Icode.back().ll()->m_dst.off = pstate->r[rAH];
}
else /* Program termination: int20h, int27h */
done = (ll->src().getImm2() == 0x20 or ll->src().getImm2() == 0x27);
if (done) if (done)
pIcode->ll()->setFlags(TERMINATES); pIcode->ll()->setFlags(TERMINATES);
break; break;
@ -277,16 +317,10 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
case iMOV: case iMOV:
process_MOV(*pIcode->ll(), pstate); process_MOV(*pIcode->ll(), pstate);
break; break;
/* case iXCHG:
process_MOV (pIcode, pstate);
break; **** HERE ***/
case iSHL: case iSHL:
if (pstate->JCond.regi == ll->m_dst.regi) if (pstate->JCond.regi == ll->m_dst.regi)
{ {
if ((ll->testFlags(I)) and ll->src().getImm2() == 1) if (ll->srcIsImmed() and ll->src().getImm2() == 1)
pstate->JCond.immed *= 2; pstate->JCond.immed *= 2;
else else
pstate->JCond.regi = 0; pstate->JCond.regi = 0;
@ -303,7 +337,7 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
/* and (Icode.ll()->flg & SEG_IMMED) */ ) /* and (Icode.ll()->flg & SEG_IMMED) */ )
{ {
offset = LH(&prog.image()[psym->label]); offset = LH(&prog.image()[psym->label]);
pstate->setState( (ll->getOpcode() == iLDS)? rDS: rES, pstate->setState( (ll->getOpcode() == iLDS)? rDS : rES,
LH(&prog.image()[psym->label + 2])); LH(&prog.image()[psym->label + 2]));
pstate->setState( ll->m_dst.regi, (int16_t)offset); pstate->setState( ll->m_dst.regi, (int16_t)offset);
psym->type = TYPE_PTR; psym->type = TYPE_PTR;
@ -313,12 +347,12 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
} }
if (err) { if (err) {
this->flg &= ~TERMINATES; func.flg &= ~TERMINATES;
if (err == INVALID_386OP or err == INVALID_OPCODE) if (err == INVALID_386OP or err == INVALID_OPCODE)
{ {
fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label); fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label);
this->flg |= PROC_BADINST; func.flg |= PROC_BADINST;
} }
else if (err == IP_OUT_OF_RANGE) else if (err == IP_OUT_OF_RANGE)
fatalError (err, _Icode.ll()->label); fatalError (err, _Icode.ll()->label);
@ -342,34 +376,7 @@ void Function::extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &ta
table.finish = table.start + 2; table.finish = table.start + 2;
} }
/* process_JMP - Handles JMPs, returns true if we should end recursion */ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
bool Function::followAllTableEntries(JumpTable &table, uint32_t cs, ICODE& pIcode, CALL_GRAPH* pcallGraph, STATE *pstate)
{
PROG &prog(Project::get()->prog);
STATE StCopy;
setBits(BM_DATA, table.start, table.size()*table.entrySize());
pIcode.ll()->setFlags(SWITCH);
pIcode.ll()->caseTbl2.resize( table.size() );
assert(pIcode.ll()->caseTbl2.size()<512);
uint32_t k=0;
for (size_t i = table.start; i < table.finish; i += 2)
{
StCopy = *pstate;
StCopy.IP = cs + LH(&prog.image()[i]);
iICODE last_current_insn = (++Icode.rbegin()).base();
FollowCtrl (pcallGraph, &StCopy);
++last_current_insn; // incremented here because FollowCtrl might have adde more instructions after the Jmp
last_current_insn->ll()->caseEntry = k++;
last_current_insn->ll()->setFlags(CASE);
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
}
return true;
}
bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
// mov cx,NUM_CASES // mov cx,NUM_CASES
@ -386,9 +393,9 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
// jmp word ptr [bx+2*NUM_CASES] // jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP}; static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(Icode.size()<8) if(func->Icode.size()<8)
return false; return false;
if(&Icode.back()!=&pIcode) // not the last insn in the list skip it if(&func->Icode.back()!=&pIcode) // not the last insn in the list skip it
return false; return false;
if(pIcode.ll()->src().regi != INDEX_BX) { if(pIcode.ll()->src().regi != INDEX_BX) {
return false; return false;
@ -396,7 +403,7 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
// find address-wise predecessors of the icode // find address-wise predecessors of the icode
std::deque<ICODE *> matched; std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap; QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : Icode) { for(ICODE & ic : func->Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic; addrmap[ic.ll()->GetLlLabel()] = &ic;
} }
auto iter = addrmap.find(pIcode.ll()->GetLlLabel()); auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -409,11 +416,11 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
// pattern starts at the last jmp // pattern starts at the last jmp
ICODE *load_num_cases = matched[0]; ICODE *load_num_cases = matched[0];
ICODE *load_jump_table_addr = matched[1]; ICODE *load_jump_table_addr = matched[1];
ICODE *read_case_entry_insn = matched[2]; // ICODE *read_case_entry_insn = matched[2];
ICODE *cmp_case_val_insn = matched[3]; // ICODE *cmp_case_val_insn = matched[3];
ICODE *exit_loop_insn = matched[4]; // ICODE *exit_loop_insn = matched[4];
ICODE *add_bx_insn = matched[5]; // ICODE *add_bx_insn = matched[5];
ICODE *loop_insn = matched[6]; // ICODE *loop_insn = matched[6];
ICODE *default_jmp = matched[7]; ICODE *default_jmp = matched[7];
ICODE *last_jmp = matched[8]; ICODE *last_jmp = matched[8];
for(int i=0; i<8; ++i) { for(int i=0; i<8; ++i) {
@ -446,16 +453,12 @@ bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pca
STATE StCopy = *pstate; STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*2 + i*2; uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
iICODE last_current_insn = (++Icode.rbegin()).base(); Project::get()->addCommand(func,new FollowControlFlow(StCopy));
FollowCtrl (pcallGraph, &StCopy); Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
++last_current_insn;
last_current_insn->ll()->caseEntry = i;
last_current_insn->ll()->setFlags(CASE);
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
} }
return true; return true;
} }
bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph) static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
// mov cx,NUM_CASES // mov cx,NUM_CASES
@ -476,9 +479,9 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
// jmp word ptr [bx+2*NUM_CASES] // jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP}; static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(Icode.size()<12) if(func->Icode.size()<12)
return false; return false;
if(&Icode.back() != &pIcode) // not the last insn in the list skip it if(&func->Icode.back() != &pIcode) // not the last insn in the list skip it
return false; return false;
if(pIcode.ll()->src().regi != INDEX_BX) { if(pIcode.ll()->src().regi != INDEX_BX) {
return false; return false;
@ -486,7 +489,7 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
// find address-wise predecessors of the icode // find address-wise predecessors of the icode
std::deque<ICODE *> matched; std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap; QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : Icode) { for(ICODE & ic : func->Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic; addrmap[ic.ll()->GetLlLabel()] = &ic;
} }
auto iter = addrmap.find(pIcode.ll()->GetLlLabel()); auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -532,41 +535,19 @@ bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pc
STATE StCopy = *pstate; STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*4 + i*2; uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
iICODE last_current_insn = (++Icode.rbegin()).base(); Project::get()->addCommand(func,new FollowControlFlow(StCopy));
FollowCtrl (pcallGraph, &StCopy); Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
++last_current_insn;
last_current_insn->ll()->caseEntry = i;
last_current_insn->ll()->setFlags(CASE);
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
} }
return true; return true;
} }
bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph) /* Look for switch() stmt. idiom of the form
{ * JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *pstate) {
const static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
uint32_t seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
ICODE _Icode;
uint32_t cs, offTable, endTable;
uint32_t i, k, seg, target;
if (pIcode.ll()->testFlags(I))
{
if (pIcode.ll()->getOpcode() == iJMPF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
pstate->IP = pIcode.ll()->src().getImm2();
int64_t i = pIcode.ll()->src().getImm2();
if (i < 0)
{
exit(1);
}
/* Return true if jump target is already parsed */
return Icode.alreadyDecoded(i);
}
/* We've got an indirect JMP - look for switch() stmt. idiom of the form
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
/* Ensure we have a uint16_t offset & valid seg */ /* Ensure we have a uint16_t offset & valid seg */
if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and
@ -576,8 +557,9 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
pIcode.ll()->src().regi == INDEX_BX)) pIcode.ll()->src().regi == INDEX_BX))
{ {
offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off; uint32_t offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
uint32_t endTable;
uint32_t i;
/* Firstly look for a leading range check of the form:- /* Firstly look for a leading range check of the form:-
* CMP {BX | SI | DI}, immed * CMP {BX | SI | DI}, immed
* JA | JAE | JB | JBE * JA | JAE | JB | JBE
@ -598,10 +580,10 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
/* Now do some heuristic pruning. Look for ptrs. into the table /* Now do some heuristic pruning. Look for ptrs. into the table
* and for addresses that don't appear to point to valid code. * and for addresses that don't appear to point to valid code.
*/ */
cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4; uint32_t cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
for (i = offTable; i < endTable; i += 2) for (i = offTable; i < endTable; i += 2)
{ {
target = cs + LH(&prog.image()[i]); uint32_t target = cs + LH(&prog.image()[i]);
if (target < endTable and target >= offTable) if (target < endTable and target >= offTable)
endTable = target; endTable = target;
else if (target >= (uint32_t)prog.cbImage) else if (target >= (uint32_t)prog.cbImage)
@ -610,10 +592,10 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
for (i = offTable; i < endTable; i += 2) for (i = offTable; i < endTable; i += 2)
{ {
target = cs + LH(&prog.image()[i]); uint32_t target = cs + LH(&prog.image()[i]);
/* Be wary of 00 00 as code - it's probably data */ /* Be wary of 00 00 as code - it's probably data */
if (not (prog.image()[target] or prog.image()[target+1]) or ICODE _Icode;
scan(target, _Icode)) if (not (prog.image()[target] or prog.image()[target+1]) or scan(target, _Icode)!=NO_ERR)
endTable = i; endTable = i;
} }
@ -629,37 +611,56 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
setBits(BM_DATA, offTable, endTable - offTable); setBits(BM_DATA, offTable, endTable - offTable);
pIcode.ll()->setFlags(SWITCH); pIcode.ll()->setFlags(SWITCH);
//pIcode.ll()->caseTbl2.numEntries = (endTable - offTable) / 2;
uint32_t k;
for (i = offTable, k = 0; i < endTable; i += 2) for (i = offTable, k = 0; i < endTable; i += 2)
{ {
StCopy = *pstate; StCopy = *pstate;
StCopy.IP = cs + LH(&prog.image()[i]); StCopy.IP = cs + LH(&prog.image()[i]);
iICODE last_current_insn = (++Icode.rbegin()).base(); Project::get()->addCommand(func,new FollowControlFlow(StCopy));
//ip = Icode.size(); Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,k++));
FollowCtrl (pcallGraph, &StCopy);
++last_current_insn;
last_current_insn->ll()->caseEntry = k++;
last_current_insn->ll()->setFlags(CASE);
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
} }
return true; return true;
} }
} }
if(decodeIndirectJMP(pIcode,pstate,pcallGraph)) { return false;
}
/* process_JMP - Handles JMPs, returns true if we should end recursion */
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
{
PROG &prog(Project::get()->prog);
if (pIcode.ll()->srcIsImmed())
{
if (pIcode.ll()->getOpcode() == iJMPF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
pstate->IP = pIcode.ll()->src().getImm2();
int64_t i = pIcode.ll()->src().getImm2();
if (i < 0)
{
exit(1);
}
/* Return true if jump target is already parsed */
return func->Icode.alreadyDecoded(i);
}
/* We've got an indirect JMP */
if(decodeIndirectJMP0(func,pIcode,pstate)) {
return true; return true;
} }
if(decodeIndirectJMP2(pIcode,pstate,pcallGraph)) { if(decodeIndirectJMP(func,pIcode,pstate)) {
return true;
}
if(decodeIndirectJMP2(func,pIcode,pstate)) {
return true; return true;
} }
/* Can't do anything with this jump */ /* Can't do anything with this jump */
flg |= PROC_IJMP; func->flg |= PROC_IJMP;
flg &= ~TERMINATES; func->flg &= ~TERMINATES;
interactDis(this, this->Icode.size()-1); // TODO: consider adding a new user-interactive command ResolveControlFlowFailure ?
interactDis(func, func->Icode.size()-1);
return true; return true;
} }
@ -673,16 +674,16 @@ bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGra
* programmer expected it to come back - otherwise surely a JMP would * programmer expected it to come back - otherwise surely a JMP would
* have been used. */ * have been used. */
bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate) bool process_CALL(const PtrFunction &func,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(func->Icode.back());
STATE localState; /* Local copy of the machine state */
uint32_t off; uint32_t off;
/* For Indirect Calls, find the function address */ /* For Indirect Calls, find the function address */
bool indirect = false; bool indirect = false;
//pIcode.ll()->immed.proc.proc=fakeproc; //pIcode.ll()->immed.proc.proc=fakeproc;
if ( not pIcode.ll()->testFlags(I) ) if ( not pIcode.ll()->srcIsImmed() )
{ {
/* Not immediate, i.e. indirect call */ /* Not immediate, i.e. indirect call */
@ -727,30 +728,30 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
if (pIcode.ll()->getOpcode() == iCALLF) if (pIcode.ll()->getOpcode() == iCALLF)
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4); tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4);
else else
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)state.r[rCS] << 4); tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)pstate->r[rCS] << 4);
pIcode.ll()->replaceSrc(LLOperand::CreateImm2( tgtAddr ) ); pIcode.ll()->replaceSrc(LLOperand::CreateImm2( tgtAddr ) );
pIcode.ll()->setFlags(I); pIcode.ll()->setFlags(I);
indirect = true; indirect = true;
} }
/* Process CALL. Function address is located in pIcode.ll()->immed.op */ /* Process CALL. Function address is located in pIcode.ll()->immed.op */
if (pIcode.ll()->testFlags(I)) if (pIcode.ll()->srcIsImmed())
{ {
/* Search procedure list for one with appropriate entry point */ /* Search procedure list for one with appropriate entry point */
ilFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2()); PtrFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
/* Create a new procedure node and save copy of the state */ /* Create a new procedure node and save copy of the state */
if ( not Project::get()->valid(iter) ) if ( iter == nullptr )
{ {
iter = Project::get()->createFunction(0,""); iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()});
Function &x(*iter); Function &x(*iter);
x.procEntry = pIcode.ll()->src().getImm2(); if(project.m_pattern_locator)
LibCheck(x); project.m_pattern_locator->LibCheck(x);
if (x.flg & PROC_ISLIB) if (x.flg & PROC_ISLIB)
{ {
/* A library function. No need to do any more to it */ /* A library function. No need to do any more to it */
pcallGraph->insertCallGraph (this, iter); pcallGraph->insertCallGraph (func, iter);
//iter = (++pProcList.rbegin()).base(); //iter = (++pProcList.rbegin()).base();
last_insn.ll()->src().proc.proc = &x; last_insn.ll()->src().proc.proc = &x;
return false; return false;
@ -766,35 +767,27 @@ bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *psta
x.depth = x.depth + 1; x.depth = x.depth + 1;
x.flg |= TERMINATES; x.flg |= TERMINATES;
/* Save machine state in localState, load up IP and CS.*/
localState = *pstate;
pstate->IP = pIcode.ll()->src().getImm2(); pstate->IP = pIcode.ll()->src().getImm2();
if (pIcode.ll()->getOpcode() == iCALLF) if (pIcode.ll()->getOpcode() == iCALLF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3)); pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
x.state = *pstate; x.state = *pstate;
/* Insert new procedure in call graph */ /* Insert new procedure in call graph */
pcallGraph->insertCallGraph (this, iter); pcallGraph->insertCallGraph (func, iter);
/* Process new procedure */ /* Process new procedure */
x.FollowCtrl (pcallGraph, pstate); Project::get()->addCommand(iter,new FollowControlFlow(*pstate));
/* Restore segment registers & IP from localState */
pstate->IP = localState.IP;
pstate->setState( rCS, localState.r[rCS]);
pstate->setState( rDS, localState.r[rDS]);
pstate->setState( rES, localState.r[rES]);
pstate->setState( rSS, localState.r[rSS]);
} }
else else
Project::get()->callGraph->insertCallGraph (this, iter); Project::get()->callGraph->insertCallGraph (func, iter);
last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc
/* return ((p->flg & TERMINATES) != 0); */ /* return ((p->flg & TERMINATES) != 0); */
} }
return false; // Cristina, please check!! return false; // Cristina, please check!!
} }
@ -807,7 +800,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
uint8_t srcReg = ll.src().regi; uint8_t srcReg = ll.src().regi;
if (dstReg > 0 and dstReg < INDEX_BX_SI) if (dstReg > 0 and dstReg < INDEX_BX_SI)
{ {
if (ll.testFlags(I)) if (ll.srcIsImmed())
pstate->setState( dstReg, (int16_t)ll.src().getImm2()); pstate->setState( dstReg, (int16_t)ll.src().getImm2());
else if (srcReg == 0) /* direct memory offset */ else if (srcReg == 0) /* direct memory offset */
{ {
@ -864,7 +857,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]); pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]);
if(psym->size>1) if(psym->size>1)
{ {
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]>>8); pstate->setMemoryByte(psym->label,uint8_t(pstate->r[srcReg]>>8));
//prog.image()[psym->label+1] = (uint8_t)(pstate->r[srcReg] >> 8); //prog.image()[psym->label+1] = (uint8_t)(pstate->r[srcReg] >> 8);
} }
psym->duVal.setFlags(eDuVal::DEF); psym->duVal.setFlags(eDuVal::DEF);
@ -912,8 +905,8 @@ void STKFRAME::updateFrameOff ( int16_t off, int _size, uint16_t duFlag)
} }
/* Save maximum argument offset */ /* Save maximum argument offset */
if ((uint32_t)this->maxOff < (off + (uint32_t)_size)) if ((uint32_t)this->m_maxOff < (off + (uint32_t)_size))
this->maxOff = off + (int16_t)_size; this->m_maxOff = off + (int16_t)_size;
} }
@ -1012,7 +1005,7 @@ static void setBits(int16_t type, uint32_t start, uint32_t len)
for (i = start + len - 1; i >= start; i--) for (i = start + len - 1; i >= start; i--)
{ {
prog.map[i >> 2] |= type << ((i & 3) << 1); prog.map[i >> 2] |= type << ((i & 3) << 1);
if (i == 0) break; // Fixes inf loop! if (i == 0) break; // Fixes inf loop!
} }
} }
} }
@ -1034,8 +1027,9 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
{ {
if (pm->regi == INDEX_BP) /* indexed on bp */ if (pm->regi == INDEX_BP) /* indexed on bp */
{ {
if (pm->off >= 2) if (pm->off >= 2) {
pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE); pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE);
}
else if (pm->off < 0) else if (pm->off < 0)
pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0); pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
} }
@ -1068,7 +1062,7 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
} }
/* Use of register */ /* Use of register */
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I)))) else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
pIcode.du.use.addReg(pm->regi); pIcode.du.use.addReg(pm->regi);
} }
@ -1117,7 +1111,7 @@ static void def (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
} }
} }
/* Definition of register */ /* Definition of register */
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I)))) else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
{ {
assert(not pIcode.ll()->match(iPUSH)); assert(not pIcode.ll()->match(iPUSH));
pIcode.du1.addDef(pm->regi); pIcode.du1.addDef(pm->regi);
@ -1154,7 +1148,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
int sseg = (ll_ins.src().seg)? ll_ins.src().seg: rDS; int sseg = (ll_ins.src().seg)? ll_ins.src().seg: rDS;
int cb = pIcode.ll()->testFlags(B) ? 1: 2; int cb = pIcode.ll()->testFlags(B) ? 1: 2;
//x86_op_t *im= pIcode.insn.x86_get_imm(); //x86_op_t *im= pIcode.insn.x86_get_imm();
bool Imm = (pIcode.ll()->testFlags(I)); bool Imm = (pIcode.ll()->srcIsImmed());
switch (pIcode.ll()->getOpcode()) { switch (pIcode.ll()->getOpcode()) {
case iAND: case iOR: case iXOR: case iAND: case iOR: case iXOR:
@ -1172,8 +1166,8 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
case iXCHG: case iXCHG:
/* This instruction is replaced by 3 instructions, only need /* This instruction is replaced by 3 instructions, only need
* to define the src operand and use the destination operand * to define the src operand and use the destination operand
* in the mean time. */ * in the mean time.*/
use(SRC, pIcode, this, pstate, cb); use(SRC, pIcode, this, pstate, cb);
def(DST, pIcode, this, pstate, cb); def(DST, pIcode, this, pstate, cb);
break; break;
@ -1271,7 +1265,9 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
use(SRC, pIcode, this, pstate, cb); use(SRC, pIcode, this, pstate, cb);
break; break;
case iLOOP: case iLOOPE: case iLOOPNE: case iLOOP:
case iLOOPE:
case iLOOPNE:
pIcode.du.def.addReg(rCX); pIcode.du.def.addReg(rCX);
pIcode.du1.addDef(rCX); pIcode.du1.addDef(rCX);
case iJCXZ: case iJCXZ:
@ -1326,7 +1322,8 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
pIcode.du.use.addReg(rDX).addReg(sseg); pIcode.du.use.addReg(rDX).addReg(sseg);
break; break;
case iIN: case iOUT: case iIN:
case iOUT:
def(DST, pIcode, this, pstate, cb); def(DST, pIcode, this, pstate, cb);
if (not Imm) if (not Imm)
{ {

7
src/parser.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef PARSER_H
#define PARSER_H
class Function;
struct CALL_GRAPH;
struct STATE;
void FollowCtrl(Function & func, CALL_GRAPH * pcallGraph, STATE *pstate);
#endif // PARSER_H

View File

@ -14,7 +14,6 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
extern Project g_proj;
/* Static indentation buffer */ /* Static indentation buffer */
static constexpr int indSize=81; /* size of indentation buffer; max 20 */ static constexpr int indSize=81; /* size of indentation buffer; max 20 */
static char indentBuf[indSize] = static char indentBuf[indSize] =
@ -28,7 +27,7 @@ const char *indentStr(int indLevel) // Indentation according to the depth of the
/* Inserts an outEdge at the current callGraph pointer if the newProc does /* Inserts an outEdge at the current callGraph pointer if the newProc does
* not exist. */ * not exist. */
void CALL_GRAPH::insertArc (ilFunction newProc) void CALL_GRAPH::insertArc (PtrFunction newProc)
{ {
@ -44,23 +43,23 @@ void CALL_GRAPH::insertArc (ilFunction newProc)
/* Inserts a (caller, callee) arc in the call graph tree. */ /* Inserts a (caller, callee) arc in the call graph tree. */
bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee) bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee)
{ {
if (proc == caller) if (proc == caller)
{ {
insertArc (callee); insertArc (callee);
return true; return true;
} }
for (CALL_GRAPH *edg : outEdges) for (CALL_GRAPH *edg : outEdges)
if (edg->insertCallGraph (caller, callee)) if (edg->insertCallGraph (caller, callee))
return true; return true;
return false; return false;
} }
bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee) //bool CALL_GRAPH::insertCallGraph(PtrFunction &caller, PtrFunction &callee)
{ //{
return insertCallGraph(Project::get()->funcIter(caller),callee); // return insertCallGraph(caller,callee);
} //}
/* Displays the current node of the call graph, and invokes recursively on /* Displays the current node of the call graph, and invokes recursively on
@ -98,7 +97,7 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
condId type; condId type;
Function * tproc; Function * tproc;
eReg regL = rUNDEF; eReg regL = rUNDEF;
eReg regH; /* Registers involved in arguments */ eReg regH; /* Registers involved in arguments */
/* Flag ticode as having register arguments */ /* Flag ticode as having register arguments */
tproc = ticode->hl()->call.proc; tproc = ticode->hl()->call.proc;
@ -188,7 +187,7 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
/* Do ps (actual arguments) */ /* Do ps (actual arguments) */
STKSYM newsym; STKSYM newsym;
newsym.setArgName(call_args_stackframe->size()); newsym.setArgName(call_args_stackframe->size());
newsym.actual = picode->hl()->asgn.rhs; newsym.actual = picode->hl()->asgn.m_rhs;
newsym.regs = lhs; newsym.regs = lhs;
/* Mask off high and low register(s) in picode */ /* Mask off high and low register(s) in picode */
switch (type) { switch (type) {
@ -246,7 +245,7 @@ bool CallType::newStkArg(Expr *exp, llIcode opcode, Function * pproc)
/* Places the actual argument exp in the position given by pos in the /* Places the actual argument exp in the position given by pos in the
* argument list of picode. */ * argument list of picode. */
void CallType::placeStkArg (Expr *exp, int pos) void CallType::placeStkArg (Expr *exp, int pos)
{ {
(*args)[pos].actual = exp; (*args)[pos].actual = exp;
@ -290,7 +289,7 @@ Expr *Function::adjustActArgType (Expr *_exp, hlType forType)
case TYPE_STR: case TYPE_STR:
switch (actType) { switch (actType) {
case TYPE_CONST: case TYPE_CONST:
/* It's an offset into image where a string is found. Point to the string. */ /* It's an offset into image where a string is found. Point to the string. */
{ {
Constant *c=dynamic_cast<Constant *>(expr); Constant *c=dynamic_cast<Constant *>(expr);
assert(c); assert(c);

View File

@ -1,28 +1,37 @@
#include <QtCore/QString>
#include <QtCore/QDir>
#include <utility>
#include "dcc.h" #include "dcc.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "project.h" #include "project.h"
#include "Procedure.h" #include "Procedure.h"
#include <QtCore/QString>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <utility>
using namespace std; using namespace std;
//Project g_proj;
QString asm1_name, asm2_name; /* Assembler output filenames */ QString asm1_name, asm2_name; /* Assembler output filenames */
SYMTAB symtab; /* Global symbol table */ SYMTAB symtab; /* Global symbol table */
STATS stats; /* cfg statistics */ 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);
connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool)));
} }
void Project::initialize() void Project::initialize()
{ {
resetCommandsAndErrorState();
delete callGraph; delete callGraph;
callGraph = nullptr; callGraph = nullptr;
} }
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;
@ -40,23 +49,49 @@ bool Project::valid(ilFunction iter)
ilFunction Project::funcIter(Function *to_find) ilFunction Project::funcIter(Function *to_find)
{ {
auto iter=std::find_if(pProcList.begin(),pProcList.end(), auto iter=std::find_if(pProcList.begin(),pProcList.end(),
[to_find](const Function &f)->bool {return to_find==&f;}); [to_find](const PtrFunction &f)->bool {return to_find->shared_from_this()==f;});
assert(iter!=pProcList.end()); assert(iter!=pProcList.end());
return iter; return iter;
} }
ilFunction Project::findByEntry(uint32_t entry) PtrFunction Project::findByEntry(uint32_t entry)
{ {
/* Search procedure list for one with appropriate entry point */ /* Search procedure list for one with appropriate entry point */
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(), ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
[entry](const Function &f) { return f.procEntry==entry; }); [entry](const PtrFunction &f) { return f->procEntry==entry; });
return iter; if(iter==pProcList.end())
return nullptr;
return *iter;
} }
ilFunction Project::createFunction(FunctionType *f,const QString &name) /**
* \brief Search procedure list for one with given name
*/
PtrFunction Project::findByName(const QString &name)
{ {
pProcList.push_back(*Function::Create(f,0,name,0)); ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
return (++pProcList.rbegin()).base(); [name](const PtrFunction &f) { return f->name==name; });
if(iter==pProcList.end())
return nullptr;
return *iter;
}
PtrFunction Project::createFunction(FunctionType *f,const QString &name,SegOffAddr addr)
{
PtrFunction func(Function::Create(f,0,name,0));
pProcList.push_back(func);
// FIXME: use provided segment addr !
func->procEntry = addr.addr;
if(!callGraph) {
/* Set up call graph initial node */
callGraph = new CALL_GRAPH;
callGraph->proc = func;
/* The entry state info is for the first procedure */
func->state = m_entry_state;
}
emit newFunctionCreated(func);
return func;
} }
int Project::getSymIdxByAdd(uint32_t adr) int Project::getSymIdxByAdd(uint32_t adr)
@ -105,3 +140,99 @@ SourceMachine *Project::machine()
return nullptr; return nullptr;
} }
bool Project::addCommand(Command *cmd) {
bool res = m_project_command_stream.add(cmd);
emit commandListChanged();
return res;
}
bool Project::addCommand(PtrFunction f, Command *cmd)
{
bool res = m_function_streams[f].add(cmd);
emit commandListChanged();
return res;
}
bool Project::hasCommands(const PtrFunction & f)
{
auto iter = m_function_streams.find(f);
if(iter!=m_function_streams.end()) {
return not iter->second.isEmpty();
}
return false;
}
CommandStream *Project::functionCommands(const PtrFunction & f)
{
if(f==nullptr)
return nullptr;
auto iter = m_function_streams.find(f);
if(iter!=m_function_streams.end()) {
return &iter->second;
}
return nullptr;
}
void Project::onCommandStreamFinished(bool state)
{
if(false==state) {
m_error_state = true;
}
}
void Project::dumpAllErrors() {
for(QPair<Command *,QString> v : m_command_ctx.m_failures) {
qDebug() << QString("%1 command failed with : %2").arg(v.first->name()).arg(v.second);
}
}
void Project::setLoader(DosLoader * ldr)
{
m_selected_loader = ldr;
emit loaderSelected();
}
bool Project::addLoadCommands(QString fname)
{
if(!addCommand(new LoaderSelection(fname)))
return false;
if(!addCommand(new LoaderApplication(fname))) {
return false;
}
return true;
}
void Project::processAllCommands()
{
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::processFunctionCommands(const PtrFunction &func,int count) {
m_command_ctx.m_project = this;
m_command_ctx.m_func = func;
CommandStream *cs = functionCommands(func);
if(nullptr==cs)
return;
while(count--) {
if(false==cs->processOne(&m_command_ctx)) {
break;
}
}
emit commandListChanged();
emit functionUpdate(func);
}
void Project::resetCommandsAndErrorState()
{
m_error_state = false;
m_command_ctx.reset();
m_command_ctx.m_project = this;
m_project_command_stream.clear();
}

View File

@ -1,5 +1,5 @@
/***************************************************************************** /**
* dcc project scanner module * dcc project scanner module
* Implements a simple state driven scanner to convert 8086 machine code into * Implements a simple state driven scanner to convert 8086 machine code into
* I-code * I-code
* (C) Cristina Cifuentes, Jeff Ledermann * (C) Cristina Cifuentes, Jeff Ledermann
@ -51,8 +51,8 @@ static void none1(int i);
static void none2(int i); static void none2(int i);
static void checkInt(int i); static void checkInt(int i);
#define iZERO (llIcode)0 // For neatness #define iZERO (llIcode)0 // For neatness
#define IC llIcode #define IC llIcode
static struct { static struct {
void (*state1)(int); void (*state1)(int);
@ -60,267 +60,267 @@ static struct {
uint32_t flg; uint32_t flg;
llIcode opcode; llIcode opcode;
} stateTable[] = { } stateTable[] = {
{ modrm, none2, B , iADD }, /* 00 */ { modrm, none2, B , iADD }, /* 00 */
{ modrm, none2, 0 , iADD }, /* 01 */ { modrm, none2, 0 , iADD }, /* 01 */
{ modrm, none2, TO_REG | B , iADD }, /* 02 */ { modrm, none2, TO_REG | B , iADD }, /* 02 */
{ modrm, none2, TO_REG , iADD }, /* 03 */ { modrm, none2, TO_REG , iADD }, /* 03 */
{ data1, axImp, B , iADD }, /* 04 */ { data1, axImp, B , iADD }, /* 04 */
{ data2, axImp, 0 , iADD }, /* 05 */ { data2, axImp, 0 , iADD }, /* 05 */
{ segop, none2, NO_SRC , iPUSH }, /* 06 */ { segop, none2, NO_SRC , iPUSH }, /* 06 */
{ segop, none2, NO_SRC , iPOP }, /* 07 */ { segop, none2, NO_SRC , iPOP }, /* 07 */
{ modrm, none2, B , iOR }, /* 08 */ { modrm, none2, B , iOR }, /* 08 */
{ modrm, none2, NSP , iOR }, /* 09 */ { modrm, none2, NSP , iOR }, /* 09 */
{ modrm, none2, TO_REG | B , iOR }, /* 0A */ { modrm, none2, TO_REG | B , iOR }, /* 0A */
{ modrm, none2, TO_REG | NSP , iOR }, /* 0B */ { modrm, none2, TO_REG | NSP , iOR }, /* 0B */
{ data1, axImp, B , iOR }, /* 0C */ { data1, axImp, B , iOR }, /* 0C */
{ data2, axImp, 0 , iOR }, /* 0D */ { data2, axImp, 0 , iOR }, /* 0D */
{ segop, none2, NO_SRC , iPUSH }, /* 0E */ { segop, none2, NO_SRC , iPUSH }, /* 0E */
{ none1, none2, OP386 , iZERO }, /* 0F */ { none1, none2, OP386 , iZERO }, /* 0F */
{ modrm, none2, B , iADC }, /* 10 */ { modrm, none2, B , iADC }, /* 10 */
{ modrm, none2, NSP , iADC }, /* 11 */ { modrm, none2, NSP , iADC }, /* 11 */
{ modrm, none2, TO_REG | B , iADC }, /* 12 */ { modrm, none2, TO_REG | B , iADC }, /* 12 */
{ modrm, none2, TO_REG | NSP , iADC }, /* 13 */ { modrm, none2, TO_REG | NSP , iADC }, /* 13 */
{ data1, axImp, B , iADC }, /* 14 */ { data1, axImp, B , iADC }, /* 14 */
{ data2, axImp, 0 , iADC }, /* 15 */ { data2, axImp, 0 , iADC }, /* 15 */
{ segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */ { segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */
{ segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */ { segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */
{ modrm, none2, B , iSBB }, /* 18 */ { modrm, none2, B , iSBB }, /* 18 */
{ modrm, none2, NSP , iSBB }, /* 19 */ { modrm, none2, NSP , iSBB }, /* 19 */
{ modrm, none2, TO_REG | B , iSBB }, /* 1A */ { modrm, none2, TO_REG | B , iSBB }, /* 1A */
{ modrm, none2, TO_REG | NSP , iSBB }, /* 1B */ { modrm, none2, TO_REG | NSP , iSBB }, /* 1B */
{ data1, axImp, B , iSBB }, /* 1C */ { data1, axImp, B , iSBB }, /* 1C */
{ data2, axImp, 0 , iSBB }, /* 1D */ { data2, axImp, 0 , iSBB }, /* 1D */
{ segop, none2, NO_SRC , iPUSH }, /* 1E */ { segop, none2, NO_SRC , iPUSH }, /* 1E */
{ segop, none2, NO_SRC , iPOP }, /* 1F */ { segop, none2, NO_SRC , iPOP }, /* 1F */
{ modrm, none2, B , iAND }, /* 20 */ { modrm, none2, B , iAND }, /* 20 */
{ modrm, none2, NSP , iAND }, /* 21 */ { modrm, none2, NSP , iAND }, /* 21 */
{ modrm, none2, TO_REG | B , iAND }, /* 22 */ { modrm, none2, TO_REG | B , iAND }, /* 22 */
{ modrm, none2, TO_REG | NSP , iAND }, /* 23 */ { modrm, none2, TO_REG | NSP , iAND }, /* 23 */
{ data1, axImp, B , iAND }, /* 24 */ { data1, axImp, B , iAND }, /* 24 */
{ data2, axImp, 0 , iAND }, /* 25 */ { data2, axImp, 0 , iAND }, /* 25 */
{ prefix, none2, 0 , (IC)rES}, /* 26 */ { prefix, none2, 0 , (IC)rES}, /* 26 */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */ { none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */
{ modrm, none2, B , iSUB }, /* 28 */ { modrm, none2, B , iSUB }, /* 28 */
{ modrm, none2, 0 , iSUB }, /* 29 */ { modrm, none2, 0 , iSUB }, /* 29 */
{ modrm, none2, TO_REG | B , iSUB }, /* 2A */ { modrm, none2, TO_REG | B , iSUB }, /* 2A */
{ modrm, none2, TO_REG , iSUB }, /* 2B */ { modrm, none2, TO_REG , iSUB }, /* 2B */
{ data1, axImp, B , iSUB }, /* 2C */ { data1, axImp, B , iSUB }, /* 2C */
{ data2, axImp, 0 , iSUB }, /* 2D */ { data2, axImp, 0 , iSUB }, /* 2D */
{ prefix, none2, 0 , (IC)rCS}, /* 2E */ { prefix, none2, 0 , (IC)rCS}, /* 2E */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */ { none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */
{ modrm, none2, B , iXOR }, /* 30 */ { modrm, none2, B , iXOR }, /* 30 */
{ modrm, none2, NSP , iXOR }, /* 31 */ { modrm, none2, NSP , iXOR }, /* 31 */
{ modrm, none2, TO_REG | B , iXOR }, /* 32 */ { modrm, none2, TO_REG | B , iXOR }, /* 32 */
{ modrm, none2, TO_REG | NSP , iXOR }, /* 33 */ { modrm, none2, TO_REG | NSP , iXOR }, /* 33 */
{ data1, axImp, B , iXOR }, /* 34 */ { data1, axImp, B , iXOR }, /* 34 */
{ data2, axImp, 0 , iXOR }, /* 35 */ { data2, axImp, 0 , iXOR }, /* 35 */
{ prefix, none2, 0 , (IC)rSS}, /* 36 */ { prefix, none2, 0 , (IC)rSS}, /* 36 */
{ none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */ { none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */
{ modrm, none2, B , iCMP }, /* 38 */ { modrm, none2, B , iCMP }, /* 38 */
{ modrm, none2, NSP , iCMP }, /* 39 */ { modrm, none2, NSP , iCMP }, /* 39 */
{ modrm, none2, TO_REG | B , iCMP }, /* 3A */ { modrm, none2, TO_REG | B , iCMP }, /* 3A */
{ modrm, none2, TO_REG | NSP , iCMP }, /* 3B */ { modrm, none2, TO_REG | NSP , iCMP }, /* 3B */
{ data1, axImp, B , iCMP }, /* 3C */ { data1, axImp, B , iCMP }, /* 3C */
{ data2, axImp, 0 , iCMP }, /* 3D */ { data2, axImp, 0 , iCMP }, /* 3D */
{ prefix, none2, 0 , (IC)rDS}, /* 3E */ { prefix, none2, 0 , (IC)rDS}, /* 3E */
{ none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */ { none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */
{ regop, none2, 0 , iINC }, /* 40 */ { regop, none2, 0 , iINC }, /* 40 */
{ regop, none2, 0 , iINC }, /* 41 */ { regop, none2, 0 , iINC }, /* 41 */
{ regop, none2, 0 , iINC }, /* 42 */ { regop, none2, 0 , iINC }, /* 42 */
{ regop, none2, 0 , iINC }, /* 43 */ { regop, none2, 0 , iINC }, /* 43 */
{ regop, none2, NOT_HLL , iINC }, /* 44 */ { regop, none2, NOT_HLL , iINC }, /* 44 */
{ regop, none2, 0 , iINC }, /* 45 */ { regop, none2, 0 , iINC }, /* 45 */
{ regop, none2, 0 , iINC }, /* 46 */ { regop, none2, 0 , iINC }, /* 46 */
{ regop, none2, 0 , iINC }, /* 47 */ { regop, none2, 0 , iINC }, /* 47 */
{ regop, none2, 0 , iDEC }, /* 48 */ { regop, none2, 0 , iDEC }, /* 48 */
{ regop, none2, 0 , iDEC }, /* 49 */ { regop, none2, 0 , iDEC }, /* 49 */
{ regop, none2, 0 , iDEC }, /* 4A */ { regop, none2, 0 , iDEC }, /* 4A */
{ regop, none2, 0 , iDEC }, /* 4B */ { regop, none2, 0 , iDEC }, /* 4B */
{ regop, none2, NOT_HLL , iDEC }, /* 4C */ { regop, none2, NOT_HLL , iDEC }, /* 4C */
{ regop, none2, 0 , iDEC }, /* 4D */ { regop, none2, 0 , iDEC }, /* 4D */
{ regop, none2, 0 , iDEC }, /* 4E */ { regop, none2, 0 , iDEC }, /* 4E */
{ regop, none2, 0 , iDEC }, /* 4F */ { regop, none2, 0 , iDEC }, /* 4F */
{ regop, none2, NO_SRC , iPUSH }, /* 50 */ { regop, none2, NO_SRC , iPUSH }, /* 50 */
{ regop, none2, NO_SRC , iPUSH }, /* 51 */ { regop, none2, NO_SRC , iPUSH }, /* 51 */
{ regop, none2, NO_SRC , iPUSH }, /* 52 */ { regop, none2, NO_SRC , iPUSH }, /* 52 */
{ regop, none2, NO_SRC , iPUSH }, /* 53 */ { regop, none2, NO_SRC , iPUSH }, /* 53 */
{ regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */ { regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */
{ regop, none2, NO_SRC , iPUSH }, /* 55 */ { regop, none2, NO_SRC , iPUSH }, /* 55 */
{ regop, none2, NO_SRC , iPUSH }, /* 56 */ { regop, none2, NO_SRC , iPUSH }, /* 56 */
{ regop, none2, NO_SRC , iPUSH }, /* 57 */ { regop, none2, NO_SRC , iPUSH }, /* 57 */
{ regop, none2, NO_SRC , iPOP }, /* 58 */ { regop, none2, NO_SRC , iPOP }, /* 58 */
{ regop, none2, NO_SRC , iPOP }, /* 59 */ { regop, none2, NO_SRC , iPOP }, /* 59 */
{ regop, none2, NO_SRC , iPOP }, /* 5A */ { regop, none2, NO_SRC , iPOP }, /* 5A */
{ regop, none2, NO_SRC , iPOP }, /* 5B */ { regop, none2, NO_SRC , iPOP }, /* 5B */
{ regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */ { regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */
{ regop, none2, NO_SRC , iPOP }, /* 5D */ { regop, none2, NO_SRC , iPOP }, /* 5D */
{ regop, none2, NO_SRC , iPOP }, /* 5E */ { regop, none2, NO_SRC , iPOP }, /* 5E */
{ regop, none2, NO_SRC , iPOP }, /* 5F */ { regop, none2, NO_SRC , iPOP }, /* 5F */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */ { none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */
{ none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */ { none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */
{ memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */ { memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */
{ none1, none2, OP386 , iZERO }, /* 63 */ { none1, none2, OP386 , iZERO }, /* 63 */
{ none1, none2, OP386 , iZERO }, /* 64 */ { none1, none2, OP386 , iZERO }, /* 64 */
{ none1, none2, OP386 , iZERO }, /* 65 */ { none1, none2, OP386 , iZERO }, /* 65 */
{ none1, none2, OP386 , iZERO }, /* 66 */ { none1, none2, OP386 , iZERO }, /* 66 */
{ none1, none2, OP386 , iZERO }, /* 67 */ { none1, none2, OP386 , iZERO }, /* 67 */
{ data2, none2, NO_SRC , iPUSH }, /* 68 */ { data2, none2, NO_SRC , iPUSH }, /* 68 */
{ modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */ { modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */
{ data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */ { data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */
{ modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */ { modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */
{ strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */ { strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */
{ strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */ { strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */
{ strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */ { strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */
{ strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */ { strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */
{ dispS, none2, NOT_HLL , iJO }, /* 70 */ { dispS, none2, NOT_HLL , iJO }, /* 70 */
{ dispS, none2, NOT_HLL , iJNO }, /* 71 */ { dispS, none2, NOT_HLL , iJNO }, /* 71 */
{ dispS, none2, 0 , iJB }, /* 72 */ { dispS, none2, 0 , iJB }, /* 72 */
{ dispS, none2, 0 , iJAE }, /* 73 */ { dispS, none2, 0 , iJAE }, /* 73 */
{ dispS, none2, 0 , iJE }, /* 74 */ { dispS, none2, 0 , iJE }, /* 74 */
{ dispS, none2, 0 , iJNE }, /* 75 */ { dispS, none2, 0 , iJNE }, /* 75 */
{ dispS, none2, 0 , iJBE }, /* 76 */ { dispS, none2, 0 , iJBE }, /* 76 */
{ dispS, none2, 0 , iJA }, /* 77 */ { dispS, none2, 0 , iJA }, /* 77 */
{ dispS, none2, 0 , iJS }, /* 78 */ { dispS, none2, 0 , iJS }, /* 78 */
{ dispS, none2, 0 , iJNS }, /* 79 */ { dispS, none2, 0 , iJNS }, /* 79 */
{ dispS, none2, NOT_HLL , iJP }, /* 7A */ { dispS, none2, NOT_HLL , iJP }, /* 7A */
{ dispS, none2, NOT_HLL , iJNP }, /* 7B */ { dispS, none2, NOT_HLL , iJNP }, /* 7B */
{ dispS, none2, 0 , iJL }, /* 7C */ { dispS, none2, 0 , iJL }, /* 7C */
{ dispS, none2, 0 , iJGE }, /* 7D */ { dispS, none2, 0 , iJGE }, /* 7D */
{ dispS, none2, 0 , iJLE }, /* 7E */ { dispS, none2, 0 , iJLE }, /* 7E */
{ dispS, none2, 0 , iJG }, /* 7F */ { dispS, none2, 0 , iJG }, /* 7F */
{ immed, data1, B , iZERO }, /* 80 */ { immed, data1, B , iZERO }, /* 80 */
{ immed, data2, NSP , iZERO }, /* 81 */ { immed, data2, NSP , iZERO }, /* 81 */
{ immed, data1, B , iZERO }, /* 82 */ /* ?? */ { immed, data1, B , iZERO }, /* 82 */ /* ?? */
{ immed, data1, NSP | S_EXT , iZERO }, /* 83 */ { immed, data1, NSP | S_EXT , iZERO }, /* 83 */
{ modrm, none2, TO_REG | B , iTEST }, /* 84 */ { modrm, none2, TO_REG | B , iTEST }, /* 84 */
{ modrm, none2, TO_REG | NSP , iTEST }, /* 85 */ { modrm, none2, TO_REG | NSP , iTEST }, /* 85 */
{ modrm, none2, TO_REG | B , iXCHG }, /* 86 */ { modrm, none2, TO_REG | B , iXCHG }, /* 86 */
{ modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */ { modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */
{ modrm, none2, B , iMOV }, /* 88 */ { modrm, none2, B , iMOV }, /* 88 */
{ modrm, none2, 0 , iMOV }, /* 89 */ { modrm, none2, 0 , iMOV }, /* 89 */
{ modrm, none2, TO_REG | B , iMOV }, /* 8A */ { modrm, none2, TO_REG | B , iMOV }, /* 8A */
{ modrm, none2, TO_REG , iMOV }, /* 8B */ { modrm, none2, TO_REG , iMOV }, /* 8B */
{ segrm, none2, NSP , iMOV }, /* 8C */ { segrm, none2, NSP , iMOV }, /* 8C */
{ memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */ { memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */
{ segrm, none2, TO_REG | NSP , iMOV }, /* 8E */ { segrm, none2, TO_REG | NSP , iMOV }, /* 8E */
{ memReg0, none2, NO_SRC , iPOP }, /* 8F */ { memReg0, none2, NO_SRC , iPOP }, /* 8F */
{ none1, none2, NO_OPS , iNOP }, /* 90 */ { none1, none2, NO_OPS , iNOP }, /* 90 */
{ regop, axImp, 0 , iXCHG }, /* 91 */ { regop, axImp, 0 , iXCHG }, /* 91 */
{ regop, axImp, 0 , iXCHG }, /* 92 */ { regop, axImp, 0 , iXCHG }, /* 92 */
{ regop, axImp, 0 , iXCHG }, /* 93 */ { regop, axImp, 0 , iXCHG }, /* 93 */
{ regop, axImp, NOT_HLL , iXCHG }, /* 94 */ { regop, axImp, NOT_HLL , iXCHG }, /* 94 */
{ regop, axImp, 0 , iXCHG }, /* 95 */ { regop, axImp, 0 , iXCHG }, /* 95 */
{ regop, axImp, 0 , iXCHG }, /* 96 */ { regop, axImp, 0 , iXCHG }, /* 96 */
{ regop, axImp, 0 , iXCHG }, /* 97 */ { regop, axImp, 0 , iXCHG }, /* 97 */
{ alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */ { alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */
{axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */ {axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */
{ dispF, none2, TO_REG , iCALLF }, /* 9A */ // TO_REG set to use SRC when processing setAddress { dispF, none2, TO_REG , iCALLF }, /* 9A */ // TO_REG set to use SRC when processing setAddress
{ none1, none2, FLOAT_OP| NO_OPS , iWAIT }, /* 9B */ { none1, none2, FLOAT_OP| NO_OPS , iWAIT }, /* 9B */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */ { none1, none2, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */
{ none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */ { none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */
{ none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */ { none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */
{ none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */ { none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */
{ dispM, axImp, B , iMOV }, /* A0 */ { dispM, axImp, B , iMOV }, /* A0 */
{ dispM, axImp, 0 , iMOV }, /* A1 */ { dispM, axImp, 0 , iMOV }, /* A1 */
{ dispM, axImp, TO_REG | B , iMOV }, /* A2 */ { dispM, axImp, TO_REG | B , iMOV }, /* A2 */
{ dispM, axImp, TO_REG , iMOV }, /* A3 */ { dispM, axImp, TO_REG , iMOV }, /* A3 */
{ strop, memImp, B | IM_OPS , iMOVS }, /* A4 */ { strop, memImp, B | IM_OPS , iMOVS }, /* A4 */
{ strop, memImp, IM_OPS , iMOVS }, /* A5 */ { strop, memImp, IM_OPS , iMOVS }, /* A5 */
{ strop, memImp, B | IM_OPS , iCMPS }, /* A6 */ { strop, memImp, B | IM_OPS , iCMPS }, /* A6 */
{ strop, memImp, IM_OPS , iCMPS }, /* A7 */ { strop, memImp, IM_OPS , iCMPS }, /* A7 */
{ data1, axImp, B , iTEST }, /* A8 */ { data1, axImp, B , iTEST }, /* A8 */
{ data2, axImp, 0 , iTEST }, /* A9 */ { data2, axImp, 0 , iTEST }, /* A9 */
{ strop, memImp, B | IM_OPS , iSTOS }, /* AA */ { strop, memImp, B | IM_OPS , iSTOS }, /* AA */
{ strop, memImp, IM_OPS , iSTOS }, /* AB */ { strop, memImp, IM_OPS , iSTOS }, /* AB */
{ strop, memImp, B | IM_OPS , iLODS }, /* AC */ { strop, memImp, B | IM_OPS , iLODS }, /* AC */
{ strop, memImp, IM_OPS , iLODS }, /* AD */ { strop, memImp, IM_OPS , iLODS }, /* AD */
{ strop, memImp, B | IM_OPS , iSCAS }, /* AE */ { strop, memImp, B | IM_OPS , iSCAS }, /* AE */
{ strop, memImp, IM_OPS , iSCAS }, /* AF */ { strop, memImp, IM_OPS , iSCAS }, /* AF */
{ regop, data1, B , iMOV }, /* B0 */ { regop, data1, B , iMOV }, /* B0 */
{ regop, data1, B , iMOV }, /* B1 */ { regop, data1, B , iMOV }, /* B1 */
{ regop, data1, B , iMOV }, /* B2 */ { regop, data1, B , iMOV }, /* B2 */
{ regop, data1, B , iMOV }, /* B3 */ { regop, data1, B , iMOV }, /* B3 */
{ regop, data1, B , iMOV }, /* B4 */ { regop, data1, B , iMOV }, /* B4 */
{ regop, data1, B , iMOV }, /* B5 */ { regop, data1, B , iMOV }, /* B5 */
{ regop, data1, B , iMOV }, /* B6 */ { regop, data1, B , iMOV }, /* B6 */
{ regop, data1, B , iMOV }, /* B7 */ { regop, data1, B , iMOV }, /* B7 */
{ regop, data2, 0 , iMOV }, /* B8 */ { regop, data2, 0 , iMOV }, /* B8 */
{ regop, data2, 0 , iMOV }, /* B9 */ { regop, data2, 0 , iMOV }, /* B9 */
{ regop, data2, 0 , iMOV }, /* BA */ { regop, data2, 0 , iMOV }, /* BA */
{ regop, data2, 0 , iMOV }, /* BB */ { regop, data2, 0 , iMOV }, /* BB */
{ regop, data2, NOT_HLL , iMOV }, /* BC */ { regop, data2, NOT_HLL , iMOV }, /* BC */
{ regop, data2, 0 , iMOV }, /* BD */ { regop, data2, 0 , iMOV }, /* BD */
{ regop, data2, 0 , iMOV }, /* BE */ { regop, data2, 0 , iMOV }, /* BE */
{ regop, data2, 0 , iMOV }, /* BF */ { regop, data2, 0 , iMOV }, /* BF */
{ shift, data1, B , iZERO }, /* C0 */ { shift, data1, B , iZERO }, /* C0 */
{ shift, data1, NSP | SRC_B , iZERO }, /* C1 */ { shift, data1, NSP | SRC_B , iZERO }, /* C1 */
{ data2, none2, 0 , iRET }, /* C2 */ { data2, none2, 0 , iRET }, /* C2 */
{ none1, none2, NO_OPS , iRET }, /* C3 */ { none1, none2, NO_OPS , iRET }, /* C3 */
{ memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */ { memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */
{ memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */ { memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */
{ memReg0, data1, B , iMOV }, /* C6 */ { memReg0, data1, B , iMOV }, /* C6 */
{ memReg0, data2, 0 , iMOV }, /* C7 */ { memReg0, data2, 0 , iMOV }, /* C7 */
{ data2, data1, 0 , iENTER}, /* C8 */ { data2, data1, 0 , iENTER}, /* C8 */
{ none1, none2, NO_OPS , iLEAVE}, /* C9 */ { none1, none2, NO_OPS , iLEAVE}, /* C9 */
{ data2, none2, 0 , iRETF }, /* CA */ { data2, none2, 0 , iRETF }, /* CA */
{ none1, none2, NO_OPS , iRETF }, /* CB */ { none1, none2, NO_OPS , iRETF }, /* CB */
{ const3, none2, NOT_HLL , iINT }, /* CC */ { const3, none2, NOT_HLL , iINT }, /* CC */
{ data1,checkInt, NOT_HLL , iINT }, /* CD */ { data1,checkInt, NOT_HLL , iINT }, /* CD */
{ none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */ { none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */
{ none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */ { none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */
{ shift, const1, B , iZERO }, /* D0 */ { shift, const1, B , iZERO }, /* D0 */
{ shift, const1, SRC_B , iZERO }, /* D1 */ { shift, const1, SRC_B , iZERO }, /* D1 */
{ shift, none1, B , iZERO }, /* D2 */ { shift, none1, B , iZERO }, /* D2 */
{ shift, none1, SRC_B , iZERO }, /* D3 */ { shift, none1, SRC_B , iZERO }, /* D3 */
{ data1, axImp, NOT_HLL , iAAM }, /* D4 */ { data1, axImp, NOT_HLL , iAAM }, /* D4 */
{ data1, axImp, NOT_HLL , iAAD }, /* D5 */ { data1, axImp, NOT_HLL , iAAD }, /* D5 */
{ none1, none2, 0 , iZERO }, /* D6 */ { none1, none2, 0 , iZERO }, /* D6 */
{ memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */ { memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */
{ escop, none2, FLOAT_OP , iESC }, /* D8 */ { escop, none2, FLOAT_OP , iESC }, /* D8 */
{ escop, none2, FLOAT_OP , iESC }, /* D9 */ { escop, none2, FLOAT_OP , iESC }, /* D9 */
{ escop, none2, FLOAT_OP , iESC }, /* DA */ { escop, none2, FLOAT_OP , iESC }, /* DA */
{ escop, none2, FLOAT_OP , iESC }, /* DB */ { escop, none2, FLOAT_OP , iESC }, /* DB */
{ escop, none2, FLOAT_OP , iESC }, /* DC */ { escop, none2, FLOAT_OP , iESC }, /* DC */
{ escop, none2, FLOAT_OP , iESC }, /* DD */ { escop, none2, FLOAT_OP , iESC }, /* DD */
{ escop, none2, FLOAT_OP , iESC }, /* DE */ { escop, none2, FLOAT_OP , iESC }, /* DE */
{ escop, none2, FLOAT_OP , iESC }, /* Df */ { escop, none2, FLOAT_OP , iESC }, /* Df */
{ dispS, none2, 0 , iLOOPNE}, /* E0 */ { dispS, none2, 0 , iLOOPNE}, /* E0 */
{ dispS, none2, 0 , iLOOPE}, /* E1 */ { dispS, none2, 0 , iLOOPE}, /* E1 */
{ dispS, none2, 0 , iLOOP }, /* E2 */ { dispS, none2, 0 , iLOOP }, /* E2 */
{ dispS, none2, 0 , iJCXZ }, /* E3 */ { dispS, none2, 0 , iJCXZ }, /* E3 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */ { data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */
{ data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */ { data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */ { data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */
{ data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */ { data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */
{ dispN, none2, 0 , iCALL }, /* E8 */ { dispN, none2, 0 , iCALL }, /* E8 */
{ dispN, none2, 0 , iJMP }, /* E9 */ { dispN, none2, 0 , iJMP }, /* E9 */
{ dispF, none2, 0 , iJMPF }, /* EA */ { dispF, none2, 0 , iJMPF }, /* EA */
{ dispS, none2, 0 , iJMP }, /* EB */ { dispS, none2, 0 , iJMP }, /* EB */
{ none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */ { none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */
{ none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */ { none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */ { none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */
{ none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */ { none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */
{ none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */ { none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */
{ none1, none2, 0 , iZERO }, /* F1 */ { none1, none2, 0 , iZERO }, /* F1 */
{ prefix, none2, 0 , iREPNE}, /* F2 */ { prefix, none2, 0 , iREPNE}, /* F2 */
{ prefix, none2, 0 , iREPE }, /* F3 */ { prefix, none2, 0 , iREPE }, /* F3 */
{ none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */ { none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */
{ none1, none2, NO_OPS , iCMC }, /* F5 */ { none1, none2, NO_OPS , iCMC }, /* F5 */
{ arith, none1, B , iZERO }, /* F6 */ { arith, none1, B , iZERO }, /* F6 */
{ arith, none1, NSP , iZERO }, /* F7 */ { arith, none1, NSP , iZERO }, /* F7 */
{ none1, none2, NO_OPS , iCLC }, /* F8 */ { none1, none2, NO_OPS , iCLC }, /* F8 */
{ none1, none2, NO_OPS , iSTC }, /* F9 */ { none1, none2, NO_OPS , iSTC }, /* F9 */
{ none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */ { none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */
{ none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */ { none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */
{ none1, none2, NO_OPS , iCLD }, /* FC */ { none1, none2, NO_OPS , iCLD }, /* FC */
{ none1, none2, NO_OPS , iSTD }, /* FD */ { none1, none2, NO_OPS , iSTD }, /* FD */
{ trans, none1, B , iZERO }, /* FE */ { trans, none1, B , iZERO }, /* FE */
{ trans, none1, NSP , iZERO } /* FF */ { trans, none1, NSP , iZERO } /* FF */
} ; } ;
static uint16_t SegPrefix, RepPrefix; static uint16_t SegPrefix, RepPrefix;
static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */ static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */
static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */ static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */
static void decodeBranchTgt(x86_insn_t &insn) static void decodeBranchTgt(x86_insn_t &insn)
@ -338,7 +338,7 @@ static void decodeBranchTgt(x86_insn_t &insn)
pIcode->ll()->replaceSrc((uint32_t)addr); pIcode->ll()->replaceSrc((uint32_t)addr);
pIcode->ll()->setFlags(I); pIcode->ll()->setFlags(I);
// PROG &prog(Project::get()->prog); // PROG &prog(Project::get()->prog);
// long off = (short)getWord(); /* Signed displacement */ // long off = (short)getWord(); /* Signed displacement */
// assert(addr==(uint32_t)(off + (unsigned)(pInst - prog.image()))); // assert(addr==(uint32_t)(off + (unsigned)(pInst - prog.image())));
} }
@ -538,7 +538,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
int op; int op;
p = ICODE(); p = ICODE();
p.type = LOW_LEVEL_ICODE; p.type = LOW_LEVEL_ICODE;
p.ll()->label = ip; /* ip is absolute offset into image*/ p.ll()->label = ip; /* ip is absolute offset into image*/
if (ip >= (uint32_t)prog.cbImage) if (ip >= (uint32_t)prog.cbImage)
{ {
return (IP_OUT_OF_RANGE); return (IP_OUT_OF_RANGE);
@ -557,13 +557,13 @@ eErrorId scan(uint32_t ip, ICODE &p)
do do
{ {
op = *pInst++; /* First state - trivial */ op = *pInst++; /* First state - trivial */
/* Convert to Icode.opcode */ /* Convert to Icode.opcode */
p.ll()->set(stateTable[op].opcode,stateTable[op].flg & ICODEMASK); p.ll()->set(stateTable[op].opcode,stateTable[op].flg & ICODEMASK);
(*stateTable[op].state1)(op); /* Second state */ (*stateTable[op].state1)(op); /* Second state */
(*stateTable[op].state2)(op); /* Third state */ (*stateTable[op].state2)(op); /* Third state */
} while (stateTable[op].state1 == prefix); /* Loop if prefix */ } while (stateTable[op].state1 == prefix); /* Loop if prefix */
if(p.insn.group == x86_insn_t::insn_controlflow) if(p.insn.group == x86_insn_t::insn_controlflow)
{ {
if(p.insn.x86_get_branch_target()) if(p.insn.x86_get_branch_target())
@ -591,10 +591,9 @@ eErrorId scan(uint32_t ip, ICODE &p)
static bool relocItem(const uint8_t *p) static bool relocItem(const uint8_t *p)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
int i; uint32_t off = p - prog.image();
uint32_t off = p - prog.image();
for (i = 0; i < prog.cReloc; i++) for (int i = 0; i < prog.cReloc; i++)
if (prog.relocTable[i] == off) if (prog.relocTable[i] == off)
return true; return true;
return false; return false;
@ -621,33 +620,33 @@ static int signex(uint8_t b)
return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s); return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s);
} }
/**************************************************************************** /**
* setAddress - Updates the source or destination field for the current * \brief Updates the source or destination field for the current
* icode, based on fdst and the TO_REG flag. * icode, based on fdst and the TO_REG flag.
* Note: fdst == true is for the r/m part of the field (dest, unless TO_REG) * \note fdst == true is for the r/m part of the field (dest, unless TO_REG)
* fdst == false is for reg part of the field * fdst == false is for reg part of the field
***************************************************************************/ ***************************************************************************/
static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off) static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off)
{ {
/* If not to register (i.e. to r/m), and talking about r/m, then this is dest */ /* If not to register (i.e. to r/m), and talking about r/m, then this is dest */
LLOperand *pm = (! (stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src(); LLOperand *pm = (! bool(stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src();
/* Set segment. A later procedure (lookupAddr in proclist.c) will /* Set segment. A later procedure (lookupAddr in proclist.c) will
* provide the value of this segment in the field segValue. * provide the value of this segment in the field segValue.
*/ */
if (seg) /* segment override */ if (seg) /* segment override */
{ {
pm->seg = pm->segOver = (eReg)seg; pm->seg = pm->segOver = (eReg)seg;
} }
else else
{ /* no override, check indexed register */ { /* no override, check indexed register */
if ((reg >= INDEX_BX_SI) and (reg == INDEX_BP_SI or reg == INDEX_BP_DI or reg == INDEX_BP)) if ((reg >= INDEX_BX_SI) and (reg == INDEX_BP_SI or reg == INDEX_BP_DI or reg == INDEX_BP))
{ {
pm->seg = rSS; /* indexed on bp */ pm->seg = rSS; /* indexed on bp */
} }
else else
{ {
pm->seg = rDS; /* any other indexed reg */ pm->seg = rDS; /* any other indexed reg */
} }
} }
@ -658,7 +657,7 @@ static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off
pm->regi = Machine_X86::subRegL(pm->regi); pm->regi = Machine_X86::subRegL(pm->regi);
} }
if (seg) /* So we can catch invalid use of segment overrides */ if (seg) /* So we can catch invalid use of segment overrides */
{ {
SegPrefix = 0; SegPrefix = 0;
} }
@ -674,7 +673,7 @@ static void rm(int i)
uint8_t rm = *pInst++ & 7; uint8_t rm = *pInst++ & 7;
switch (mod) { switch (mod) {
case 0: /* No disp unless rm == 6 */ case 0: /* No disp unless rm == 6 */
if (rm == 6) { if (rm == 6) {
setAddress(i, true, SegPrefix, 0, getWord()); setAddress(i, true, SegPrefix, 0, getWord());
pIcode->ll()->setFlags(WORD_OFF); pIcode->ll()->setFlags(WORD_OFF);
@ -683,16 +682,16 @@ static void rm(int i)
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, 0); setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, 0);
break; break;
case 1: /* 1 uint8_t disp */ case 1: /* 1 uint8_t disp */
setAddress(i, true, SegPrefix, rm+INDEX_BX_SI, (uint16_t)signex(*pInst++)); setAddress(i, true, SegPrefix, rm+INDEX_BX_SI, (uint16_t)signex(*pInst++));
break; break;
case 2: /* 2 uint8_t disp */ case 2: /* 2 uint8_t disp */
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, getWord()); setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, getWord());
pIcode->ll()->setFlags(WORD_OFF); pIcode->ll()->setFlags(WORD_OFF);
break; break;
case 3: /* reg */ case 3: /* reg */
setAddress(i, true, 0, rm + rAX, 0); setAddress(i, true, 0, rm + rAX, 0);
break; break;
} }
@ -718,7 +717,7 @@ static void modrm(int i)
****************************************************************************/ ****************************************************************************/
static void segrm(int i) static void segrm(int i)
{ {
int reg = REG(*pInst) + rES; int reg = REG(*pInst) + rES;
if (reg > rDS or (reg == rCS and (stateTable[i].flg & TO_REG))) if (reg > rDS or (reg == rCS and (stateTable[i].flg & TO_REG)))
pIcode->ll()->setOpcode((llIcode)0); // setCBW because it has that index pIcode->ll()->setOpcode((llIcode)0); // setCBW because it has that index
@ -814,7 +813,7 @@ static void immed(int i)
rm(i); rm(i);
if (pIcode->ll()->getOpcode() == iADD or pIcode->ll()->getOpcode() == iSUB) if (pIcode->ll()->getOpcode() == iADD or pIcode->ll()->getOpcode() == iSUB)
pIcode->ll()->clrFlags(NOT_HLL); /* Allow ADD/SUB SP, immed */ pIcode->ll()->clrFlags(NOT_HLL); /* Allow ADD/SUB SP, immed */
} }
@ -826,7 +825,7 @@ static void shift(int i)
static llIcode shiftTable[8] = static llIcode shiftTable[8] =
{ {
(llIcode)iROL, (llIcode)iROR, (llIcode)iRCL, (llIcode)iRCR, (llIcode)iROL, (llIcode)iROR, (llIcode)iRCL, (llIcode)iRCR,
(llIcode)iSHL, (llIcode)iSHR, (llIcode)0, (llIcode)iSAR}; (llIcode)iSHL, (llIcode)iSHR, (llIcode)0, (llIcode)iSAR};
pIcode->ll()->setOpcode(shiftTable[REG(*pInst)]); pIcode->ll()->setOpcode(shiftTable[REG(*pInst)]);
rm(i); rm(i);
@ -884,7 +883,7 @@ static void arith(int i)
else if (not (opcode == iNOT or opcode == iNEG)) else if (not (opcode == iNOT or opcode == iNEG))
{ {
pIcode->ll()->replaceSrc( pIcode->ll()->m_dst ); pIcode->ll()->replaceSrc( pIcode->ll()->m_dst );
setAddress(i, true, 0, rAX, 0); /* dst = AX */ setAddress(i, true, 0, rAX, 0); /* dst = AX */
} }
else if (opcode == iNEG or opcode == iNOT) else if (opcode == iNEG or opcode == iNOT)
pIcode->ll()->setFlags(NO_SRC); pIcode->ll()->setFlags(NO_SRC);
@ -919,7 +918,7 @@ static void data2(int )
* but this field is being used as the number of bytes to allocate * but this field is being used as the number of bytes to allocate
* on the stack. The procedure level is stored in the immediate * on the stack. The procedure level is stored in the immediate
* field. There is no source operand; therefore, the flag flg is * field. There is no source operand; therefore, the flag flg is
* set to NO_OPS. */ * set to NO_OPS. */
if (pIcode->ll()->getOpcode() == iENTER) if (pIcode->ll()->getOpcode() == iENTER)
{ {
pIcode->ll()->m_dst.off = getWord(); pIcode->ll()->m_dst.off = getWord();
@ -946,7 +945,7 @@ static void dispN(int )
{ {
//PROG &prog(Project::get()->prog); //PROG &prog(Project::get()->prog);
/*long off = (short)*/getWord(); /* Signed displacement */ /*long off = (short)*/getWord(); /* Signed displacement */
/* Note: the result of the subtraction could be between 32k and 64k, and /* Note: the result of the subtraction could be between 32k and 64k, and
still be positive; it is an offset from prog.Image. So this must be still be positive; it is an offset from prog.Image. So this must be
@ -960,7 +959,7 @@ static void dispN(int )
***************************************************************************/ ***************************************************************************/
static void dispS(int ) static void dispS(int )
{ {
/*long off =*/ signex(*pInst++); /* Signed displacement */ /*long off =*/ signex(*pInst++); /* Signed displacement */
// decodeBranchTgt(); // decodeBranchTgt();
} }
@ -994,7 +993,7 @@ static void prefix(int )
inline void BumpOpcode(LLInst &ll) inline void BumpOpcode(LLInst &ll)
{ {
llIcode ic((llIcode)ll.getOpcode()); llIcode ic((llIcode)ll.getOpcode());
ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type
ll.setOpcode(ic); ll.setOpcode(ic);
} }
@ -1069,7 +1068,7 @@ static void none1(int )
****************************************************************************/ ****************************************************************************/
static void none2(int ) static void none2(int )
{ {
if ( pIcode->ll()->testFlags(I) ) if ( pIcode->ll()->srcIsImmed() )
pIcode->ll()->setFlags(NO_OPS); pIcode->ll()->setFlags(NO_OPS);
} }

24
src/tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
set(TESTS
ProjectTests
LoaderTests
MemoryChunkTests
MemorySegmentCoordinatorTests
)
include(DCC_Macros)
set(target_INCLUDE_DIR
..
)
include_directories(${target_INCLUDE_DIR}
../../frontend/sparc
../../frontend/pentium
)
set(test_LIBRARIES
dcc_lib dcc_hash disasm_s
)
foreach(t ${TESTS})
ADD_QTEST(${t})
endforeach()

15
src/tests/LoaderTests.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "LoaderTests.h"
#include "project.h"
#include "loader.h"
#include <QTextStream>
#include <QStringList>
#include <QDir>
#include <QProcessEnvironment>
#include <QDebug>
void LoaderTest::testDummy() {
QVERIFY2(false,"No tests written for loader");
}
QTEST_MAIN(LoaderTest)

7
src/tests/LoaderTests.h Normal file
View File

@ -0,0 +1,7 @@
#include <QtTest/QTest>
class LoaderTest : public QObject {
Q_OBJECT
private slots:
void testDummy();
};

View File

@ -0,0 +1,22 @@
#include "MemoryChunkTests.h"
#include "MemoryChunk.h"
#include "project.h"
#include "loader.h"
#include <QTextStream>
#include <QStringList>
#include <QDir>
#include <QProcessEnvironment>
#include <QDebug>
void MemoryChunkTest::testIfConstructionWorksProperly() {
MemoryChunk mc(0,10);
QCOMPARE(mc.size(),size_t(10));
QVERIFY(mc.contains(1));
QVERIFY(not mc.contains(10));
QVERIFY(not mc.contains(-1));
QVERIFY(not mc.contains(100));
}
QTEST_MAIN(MemoryChunkTest)

View File

@ -0,0 +1,7 @@
#include <QtTest/QTest>
class MemoryChunkTest : public QObject {
Q_OBJECT
private slots:
void testIfConstructionWorksProperly();
};

View File

@ -0,0 +1,55 @@
#include "MemorySegmentCoordinatorTests.h"
#include "MemorySegmentCoordinator.h"
#include "project.h"
#include "loader.h"
#include <QTextStream>
#include <QStringList>
#include <QDir>
#include <QProcessEnvironment>
#include <QDebug>
void MemorySegmentCoordinatorTest::testSimpleQueries()
{
MemorySegmentCoordinator segmenter;
segmenter.addSegment(
LinearAddress(0x10),
LinearAddress(0x13),LinearAddress(0x20),
".text",4);
MemorySegment * seg;
QCOMPARE(segmenter.getSegment(LinearAddress(0x9)),(MemorySegment *)nullptr);
seg = segmenter.getSegment(0x14);
QVERIFY(seg!=nullptr);
if(seg) {
QCOMPARE(seg->getName(),QString(".text"));
}
}
void MemorySegmentCoordinatorTest::testAddingSegments()
{
MemorySegmentCoordinator segmenter;
QVERIFY(segmenter.addSegment(
LinearAddress(0x10),
LinearAddress(0x13),LinearAddress(0x20),
".text",4));
QCOMPARE(segmenter.size(),uint32_t(1));
QVERIFY(segmenter.addSegment(
LinearAddress(0x20),
LinearAddress(0x22),LinearAddress(0x33),
".text",4));
QVERIFY2(not segmenter.addSegment(
LinearAddress(0x20),
LinearAddress(0x40),LinearAddress(0x20),
".text",4),"Adding segment with start>fin should fail");
QVERIFY2(not segmenter.addSegment(
LinearAddress(0x20),
LinearAddress(0x10),LinearAddress(0x20),
".text",4),"Segment start should be >= base");
QCOMPARE(segmenter.size(),uint32_t(2));
}
void MemorySegmentCoordinatorTest::testAddingIntersectingSegments()
{
}
QTEST_MAIN(MemorySegmentCoordinatorTest)

View File

@ -0,0 +1,9 @@
#include <QtTest/QTest>
class MemorySegmentCoordinatorTest : public QObject {
Q_OBJECT
private slots:
void testAddingSegments();
void testAddingIntersectingSegments();
void testSimpleQueries();
};

View File

@ -0,0 +1,53 @@
#include "ProjectTests.h"
#include "project.h"
#include <QTextStream>
#include <QStringList>
#include <QDir>
#include <QProcessEnvironment>
#include <QDebug>
static bool logset = false;
static QString TEST_BASE;
static QDir baseDir;
void ProjectTest::initTestCase() {
if (!logset) {
TEST_BASE = QProcessEnvironment::systemEnvironment().value("DCC_TEST_BASE", "");
baseDir = QDir(TEST_BASE);
if (TEST_BASE.isEmpty()) {
qWarning() << "DCC_TEST_BASE environment variable not set, will assume '..', many test may fail";
TEST_BASE = "..";
baseDir = QDir("..");
}
logset = true;
// Boomerang::get()->setProgPath(TEST_BASE);
// Boomerang::get()->setPluginPath(TEST_BASE + "/out");
// Boomerang::get()->setLogger(new NullLogger());
}
}
void ProjectTest::testNewProjectIsInitalized() {
Project p;
QCOMPARE((CALL_GRAPH *)nullptr,p.callGraph);
QVERIFY(p.pProcList.empty());
QVERIFY(p.binary_path().isEmpty());
QVERIFY(p.project_name().isEmpty());
QVERIFY(p.symtab.empty());
}
void ProjectTest::testCreatedProjectHasValidNames() {
Project p;
QStringList strs = {"./Project1.EXE","/home/Project2.EXE","/home/Pro\\ ject3"};
QStringList expected = {"Project1","Project2","Pro\\ ject3"};
for(size_t i=0; i<strs.size(); i++)
{
p.create(strs[i]);
QCOMPARE((CALL_GRAPH *)nullptr,p.callGraph);
QVERIFY(p.pProcList.empty());
QCOMPARE(expected[i],p.project_name());
QCOMPARE(strs[i],p.binary_path());
QVERIFY(p.symtab.empty());
}
}
QTEST_MAIN(ProjectTest)

10
src/tests/ProjectTests.h Normal file
View File

@ -0,0 +1,10 @@
#include <QtTest/QTest>
class ProjectTest : public QObject {
Q_OBJECT
private slots:
void testNewProjectIsInitalized();
void testCreatedProjectHasValidNames();
void initTestCase();
};

View File

@ -1,14 +0,0 @@
#include "project.h"
#include "loader.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
TEST(Loader, NewProjectIsInitalized) {
Project p;
EXPECT_EQ(nullptr,p.callGraph);
ASSERT_TRUE(p.pProcList.empty());
ASSERT_TRUE(p.binary_path().empty());
ASSERT_TRUE(p.project_name().empty());
ASSERT_TRUE(p.symtab.empty());
}

View File

@ -1,27 +0,0 @@
#include "project.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
TEST(Project, NewProjectIsInitalized) {
Project p;
EXPECT_EQ(nullptr,p.callGraph);
ASSERT_TRUE(p.pProcList.empty());
ASSERT_TRUE(p.binary_path().empty());
ASSERT_TRUE(p.project_name().empty());
ASSERT_TRUE(p.symtab.empty());
}
TEST(Project, CreatedProjectHasValidNames) {
Project p;
std::vector<std::string> strs = {"./Project1.EXE","/home/Project2.EXE","/home/Pro\\ ject3"};
std::vector<std::string> expected = {"Project1","Project2","Pro\\ ject3"};
for(size_t i=0; i<strs.size(); i++)
{
p.create(strs[i]);
EXPECT_EQ(nullptr,p.callGraph);
ASSERT_TRUE(p.pProcList.empty());
EXPECT_EQ(expected[i],p.project_name());
EXPECT_EQ(strs[i],p.binary_path());
ASSERT_TRUE(p.symtab.empty());
}
}

View File

@ -13,7 +13,6 @@
#include <cassert> #include <cassert>
#include <stdio.h> #include <stdio.h>
#include <CallGraph.h> #include <CallGraph.h>
extern Project g_proj;
//static void displayCFG(Function * pProc); //static void displayCFG(Function * pProc);
//static void displayDfs(BB * pBB); //static void displayDfs(BB * pBB);
@ -32,7 +31,7 @@ void Function::buildCFG(Disassembler &ds)
if (option.asm2) if (option.asm2)
{ {
ds.disassem(this); // Print 2nd pass assembler listing ds.disassem(this->shared_from_this()); // Print 2nd pass assembler listing
return; return;
} }
@ -46,10 +45,9 @@ void Function::controlFlowAnalysis()
{ {
if (flg & PROC_ISLIB) if (flg & PROC_ISLIB)
return; /* Ignore library functions */ return; /* Ignore library functions */
derSeq *derivedG=nullptr;
/* Make cfg reducible and build derived sequences */ /* Make cfg reducible and build derived sequences */
derivedG=checkReducibility(); derSeq *derivedG = checkReducibility();
if (option.VeryVerbose) if (option.VeryVerbose)
derivedG->display(); derivedG->display();
@ -80,13 +78,13 @@ void udm(void)
Disassembler ds(2); Disassembler ds(2);
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter) for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
{ {
Function &f(*iter); Function &f(**iter);
if(option.CustomEntryPoint) { if(option.CustomEntryPoint) {
if(f.procEntry!=option.CustomEntryPoint) { if(f.procEntry!=option.CustomEntryPoint) {
continue; continue;
} }
} }
iter->buildCFG(ds); f.buildCFG(ds);
} }
if (option.asm2) if (option.asm2)
return; return;
@ -97,8 +95,8 @@ void udm(void)
* substitution algorithm */ * substitution algorithm */
LivenessSet live_regs; LivenessSet live_regs;
if(option.CustomEntryPoint) { if(option.CustomEntryPoint) {
ilFunction iter = proj->findByEntry(option.CustomEntryPoint); PtrFunction iter = proj->findByEntry(option.CustomEntryPoint);
if(iter==proj->pProcList.end()) { if(iter==nullptr) {
qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16); qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16);
return; return;
} }
@ -109,12 +107,12 @@ void udm(void)
proj->callGraph->proc = iter; proj->callGraph->proc = iter;
return; return;
} }
proj->pProcList.front().dataFlow (live_regs); proj->pProcList.front()->dataFlow (live_regs);
/* Control flow analysis - structuring algorithm */ /* Control flow analysis - structuring algorithm */
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter) for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
{ {
iter->controlFlowAnalysis(); (*iter)->controlFlowAnalysis();
} }
} }

View File

@ -0,0 +1,71 @@
#include "CommandQueueView.h"
#include "project.h"
#include "../AutomatedPlanner.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();
CommandStream * func_stream = project.functionCommands(m_current_function);
if(func_stream) {
for(const Command * cmd : func_stream->m_commands) {
ui->lstQueuedCommands->addItem(cmd->instanceDescription());
}
}
const CommandStream& project_commands(project.m_project_command_stream);
for(const Command * cmd : project_commands.m_commands) {
ui->lstQueuedCommands->addItem(cmd->instanceDescription());
}
}
void CommandQueueView::onCurrentFunctionChanged(PtrFunction func)
{
m_current_function=func;
onCommandListChanged();
}
void CommandQueueView::on_btnStep_clicked()
{
Project &project(*Project::get());
if(nullptr!=m_current_function and project.hasCommands(m_current_function))
project.processFunctionCommands(m_current_function,1);
else
project.processCommands(1);
}
void CommandQueueView::on_btnPlan_clicked()
{
AutomatedPlanner planner;
if(m_current_function!=nullptr) {
planner.planFor(*m_current_function);
}
else
planner.planFor(*Project::get());
}

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

@ -0,0 +1,37 @@
#ifndef COMMANDQUEUEVIEW_H
#define COMMANDQUEUEVIEW_H
#include <QtWidgets/QDockWidget>
#include "Procedure.h"
namespace Ui {
class CommandQueueView;
}
class CommandQueueView : public QDockWidget
{
Q_OBJECT
public:
explicit CommandQueueView(QWidget *parent = 0);
~CommandQueueView();
public slots:
void onCommandListChanged();
void onCurrentFunctionChanged(PtrFunction func);
protected:
void changeEvent(QEvent *e);
private slots:
void on_btnStep_clicked();
void on_btnPlan_clicked();
private:
Ui::CommandQueueView *ui;
PtrFunction m_current_function;
};
#endif // COMMANDQUEUEVIEW_H

View File

@ -0,0 +1,57 @@
<?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="QLabel" name="label">
<property name="text">
<string>Planned actions:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="lstQueuedCommands"/>
</item>
<item>
<widget class="QPushButton" name="btnPlan">
<property name="text">
<string>Plan</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnStep">
<property name="text">
<string>Execute</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Completed actions:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="lstCompletedCommands"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

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

@ -0,0 +1,147 @@
#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_IDCC = 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_IDCC = IDcc::get();
m_last_display = nullptr;
m_command_queue = new CommandQueueView(this);
m_functionlist_widget = new FunctionListDockWidget(this);
m_functionlist_widget->setWindowTitle(QApplication::tr("Function list"));
connect(m_functionlist_widget,SIGNAL(selectFunction(PtrFunction)),SLOT(onFunctionSelected(PtrFunction)));
connect(m_functionlist_widget,SIGNAL(displayRequested()), SLOT(displayCurrentFunction()));
// we are beeing signalled when display is requested
connect(this,SIGNAL(functionListChanged()), m_functionlist_widget->model(),SLOT(updateFunctionList()));
connect(Project::get(),SIGNAL(newFunctionCreated(PtrFunction)),SLOT(onNewFunction(PtrFunction)));
connect(Project::get(),SIGNAL(functionUpdate(const PtrFunction &)),SLOT(onFunctionUpdated(const PtrFunction &)));
this->addDockWidget(Qt::RightDockWidgetArea,m_functionlist_widget);
this->addDockWidget(Qt::LeftDockWidgetArea,m_command_queue);
connect(m_functionlist_widget,&FunctionListDockWidget::selectFunction,
m_command_queue, &CommandQueueView::onCurrentFunctionChanged);
}
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::onFunctionSelected(PtrFunction func) {
m_selected_func = func;
}
// TODO: consider increasing granularity of change events to reduce redraw/refresh spam
void DccMainWindow::onFunctionUpdated(const PtrFunction &f) {
// some function was updated refresh the list and the view if open
auto iter = m_map_function_to_view.find(f);
if(iter!=m_map_function_to_view.end()) {
iter->second->renderCurrent();
}
emit functionListChanged();
}
void DccMainWindow::onNewFunction(PtrFunction f) {
emit functionListChanged();
}
void DccMainWindow::onOptim()
{
Project::get()->processCommands();
emit functionListChanged();
if(m_last_display==m_selected_func)
{
displayCurrentFunction();
}
}
void DccMainWindow::onOptim10()
{
Project::get()->processCommands(10);
emit functionListChanged();
if(m_last_display==m_selected_func)
{
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_IDCC->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::functionViewClosed() {
FunctionViewWidget *sndr = qobject_cast<FunctionViewWidget *>(sender());
for(auto iter = m_mdi_function_views.begin(); iter!=m_mdi_function_views.end(); ++iter) {
if(*iter==sndr) {
m_map_function_to_view.erase(sndr->viewedFunction());
m_mdi_function_views.erase(iter);
break;
}
}
ui->mdiArea->removeSubWindow(sndr);
sndr->deleteLater();
}
void DccMainWindow::displayCurrentFunction()
{
if(m_last_display!=m_selected_func) {
m_last_display=m_selected_func;
// Check if function's view is already open, if it is, acivate it
auto iter = m_map_function_to_view.find(m_selected_func);
if(iter!=m_map_function_to_view.end()) {
ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(iter->second->parent()));
return;
}
FunctionViewWidget *view = new FunctionViewWidget(m_selected_func,this);
view->setWindowTitle(QString(tr("Listing for %1")).arg(m_selected_func->name));
connect(view,SIGNAL(close()),SLOT(functionViewClosed()));
ui->mdiArea->addSubWindow(view);
view->show();
m_mdi_function_views.push_back(view);
m_map_function_to_view[m_selected_func] = view;
}
}
void DccMainWindow::prt_log(const char *v)
{
qDebug()<<v;
}
void DccMainWindow::on_actionExit_triggered()
{
qApp->exit(0);
}

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

@ -0,0 +1,53 @@
#ifndef EXE2C_MAINWINDOW_H
#define EXE2C_MAINWINDOW_H
#include "Procedure.h"
#include "DccFrontend.h"
#include <QMainWindow>
#include <QAbstractTableModel>
#include <QVariant>
#include <vector>
#include <unordered_map>
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();
void onNewFunction(PtrFunction f);
void onFunctionSelected(PtrFunction func);
void functionViewClosed();
void onFunctionUpdated(const PtrFunction & f);
private:
std::vector<FunctionViewWidget *> m_mdi_function_views;
std::unordered_map<PtrFunction,FunctionViewWidget *> m_map_function_to_view;
// FunctionViewWidget *m_internal_view;
CommandQueueView *m_command_queue;
FunctionListDockWidget *m_functionlist_widget;
Ui::DccMainWindow *ui;
PtrFunction m_last_display;
PtrFunction m_selected_func;
};
#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,124 @@
#include "FunctionListDockWidget.h"
#include "ui_FunctionListDockWidget.h"
#include "dcc.h"
#include "dcc_interface.h"
#include "Procedure.h"
#include "project.h"
#include <QtCore>
//#include "exe2c.h"
extern IDcc *g_IDCC;
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::onFunctionSelected(const QModelIndex &idx)
{
QVariant v=m_list_model.data(m_list_model.index(idx.row(),0),Qt::DisplayRole);
qDebug()<<"changed function to "<<v;
PtrFunction p(Project::get()->findByName(v.toString()));
emit selectFunction(p);
}
// signalled by m_func_list_view accepted signal
void FunctionListDockWidget::onDisplayRequested(const QModelIndex &)
{
// argument ignored since functionSelected must've been called before us
emit displayRequested();
}
void FunctionListModel::updateFunctionList()
{
rebuildFunctionList();
}
void FunctionListModel::add_function(const QString & name, DecompilationStep 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 FunctionListModel::rebuildFunctionList()
{
Project &project(*Project::get());
const lFunction &funcs(project.functions());
clear();
beginInsertRows(QModelIndex(),0,funcs.size());
for(const PtrFunction &info : funcs)
{
//g_EXE2C->GetFuncInfo(iter, &info);
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
switch(inf.m_decoding_step) {
case eNotDecoded:
return "Undecoded";
case eDisassemblyInProgress:
return "Disassembly in progress";
case eDissassembled:
return "Disassembled";
default:
return "UNKNOWN STATE";
}
}
case 2: // start offset
{
QString in_base_16=QString("%1").arg(inf.m_start_off,0,16);
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,65 @@
#ifndef FUNCTIONLISTDOCKWIDGET_H
#define FUNCTIONLISTDOCKWIDGET_H
#include <QAbstractTableModel>
#include <QDockWidget>
#include "Procedure.h"
enum DecompilationStep : uint32_t;
class FunctionListModel : public QAbstractTableModel
{
Q_OBJECT
struct function_info
{
QString m_name;
DecompilationStep 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,DecompilationStep step,int start_off,int end_off,int stack_purge);
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 onDisplayRequested(const QModelIndex &idx);
void onFunctionSelected(const QModelIndex &idx);
signals:
void displayRequested();
void selectFunction(PtrFunction p);
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>Doc&amp;kWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" 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>onDisplayRequested(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>267</x>
<y>97</y>
</hint>
<hint type="destinationlabel">
<x>573</x>
<y>154</y>
</hint>
</hints>
</connection>
<connection>
<sender>m_func_list_view</sender>
<signal>clicked(QModelIndex)</signal>
<receiver>FunctionListDockWidget</receiver>
<slot>onFunctionSelected(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
<x>283</x>
<y>211</y>
</hint>
<hint type="destinationlabel">
<x>508</x>
<y>253</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<signal>displayRequested()</signal>
<slot>onDisplayRequested(QModelIndex)</slot>
<slot>onFunctionSelected(QModelIndex)</slot>
</slots>
</ui>

View File

@ -0,0 +1,121 @@
#include "FunctionViewWidget.h"
#include "ui_FunctionViewWidget.h"
#include "RenderTags.h"
#include "Procedure.h"
#include <QDebug>
#include <QtCore>
#include "dcc_interface.h"
extern IDcc* g_IDCC;
//#include "XMLTYPE.h"
FunctionViewWidget::FunctionViewWidget(PtrFunction func, QWidget *parent) :
QWidget(parent),
ui(new Ui::FunctionViewWidget),
m_viewed_function(func)
{
ui->setupUi(this);
m_assembly_rendering = new QTextDocument(ui->textEdit);
m_doc_cursor = new QTextCursor(m_assembly_rendering);
ui->textEdit->setTextBackgroundColor(Qt::black);
m_current_format = m_doc_cursor->blockFormat();
m_current_format.setNonBreakableLines(true); // each block is single line
m_current_format.setBackground(Qt::black);
m_chars_format.setBackground(Qt::black);
m_chars_format.setForeground(Qt::white);
//ui->label->setTextFormat(Qt::RichText);
}
FunctionViewWidget::~FunctionViewWidget()
{
delete ui;
}
void FunctionViewWidget::renderCurrent()
{
m_viewed_function->toStructuredText(this,0);
}
void FunctionViewWidget::prtt(const char *s)
{
m_doc_cursor->insertText(s);
collected_text+=s;
//collected_text+="<br>";
}
void FunctionViewWidget::prtt(const QString &s)
{
m_doc_cursor->insertText(s);
collected_text+=s;
//collected_text+="<br>";
}
void FunctionViewWidget::delChars(int v) {
assert(v>0);
collected_text = collected_text.remove(collected_text.size()-v,v);
while(v--)
m_doc_cursor->deletePreviousChar();
}
void FunctionViewWidget::addEOL()
{
m_doc_cursor->insertBlock(m_current_format);
m_doc_cursor->setBlockFormat(m_current_format);
}
void FunctionViewWidget::TAGbegin(TAG_TYPE tag_type, void *p)
{
QColor col= RenderTag_2_Color(tag_type);
switch(tag_type)
{
case XT_Function:
m_assembly_rendering->clear();
m_chars_format.setForeground(Qt::white);
m_doc_cursor->setBlockFormat(m_current_format);
m_doc_cursor->setCharFormat(m_chars_format);
break;
case XT_FuncName:
case XT_Symbol:
case XT_Keyword:
case XT_DataType:
case XT_Number:
case XT_AsmOffset:
case XT_AsmLabel:
m_chars_format.setForeground(col);
m_doc_cursor->setCharFormat(m_chars_format);
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?
QFile res("result.html");
res.open(QFile::WriteOnly);
res.write(m_assembly_rendering->toHtml().toUtf8());
res.close();
ui->textEdit->setDocument(m_assembly_rendering);
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:
m_chars_format.setForeground(Qt::white);
m_doc_cursor->setCharFormat(m_chars_format);
m_doc_cursor->setBlockFormat(m_current_format);
break;
default:
qDebug()<<"Tag end:"<<tag_type;
}
}
void FunctionViewWidget::on_tabWidget_currentChanged(int index)
{
renderCurrent();
}

Some files were not shown because too many files have changed in this diff Show More