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,11 +19,11 @@ 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
@ -30,15 +32,11 @@ enum PROC_FLAGS
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 */
// CALL_C =0x00004000, /* Proc uses C calling convention */
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
PROC_NEAR =0x00010000, /* Proc exits with near return */ PROC_NEAR =0x00010000, /* Proc exits with near return */
PROC_FAR =0x00020000, /* Proc exits with far return */ PROC_FAR =0x00020000, /* Proc exits with far return */
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */ GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
SI_REGVAR =0x00200000, /* SI is used as a stack variable */ SI_REGVAR =0x00200000, /* SI is used as a stack variable */
DI_REGVAR =0x00400000, /* DI is used as a stack variable */ DI_REGVAR =0x00400000, /* DI is used as a stack variable */
PROC_IS_FUNC=0x00800000, /* Proc is a function */
REG_ARGS =0x01000000, /* Proc has registers as arguments */ REG_ARGS =0x01000000, /* Proc has registers as arguments */
// PROC_VARARG =0x02000000, /* Proc has variable arguments */ // PROC_VARARG =0x02000000, /* Proc has variable arguments */
PROC_OUTPUT =0x04000000, /* C for this proc has been output */ PROC_OUTPUT =0x04000000, /* C for this proc has been output */
@ -49,10 +47,43 @@ enum PROC_FLAGS
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */ //#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,16 +137,18 @@ 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 = ty;
if(!ty) // No type was provided, create it
type = new FunctionType; 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 */
@ -114,7 +157,6 @@ public:
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 */
@ -134,20 +176,25 @@ public:
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);
@ -215,11 +259,7 @@ protected:
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;

View File

@ -82,12 +82,11 @@ 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,11 +30,10 @@ 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) */

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

View File

@ -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;
@ -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);
@ -253,7 +253,7 @@ struct LLOperand
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 */
@ -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
@ -334,43 +334,42 @@ public:
} }
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);
{
if(getOpcode()==iMOD)
{
assert(false);
}
flg &= ~flag;
}
uint32_t getFlag() const {return flg;} uint32_t getFlag() const {return flg;}
uint32_t GetLlLabel() const { return label;} 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) bool match(llIcode op)
{ {
return (getOpcode()==op); return (getOpcode()==op);
} }
bool matchWithRegDst(llIcode op) bool matchWithRegDst(llIcode op)
{ {
return (getOpcode()==op) and m_dst.isReg(); return match(op) and m_dst.isReg();
} }
bool match(llIcode op,eReg dest) bool match(llIcode op,eReg dest)
{ {
return (getOpcode()==op)&&m_dst.regi==dest; return match(op) and match(dest);
} }
bool match(llIcode op,eReg dest,uint32_t flgs) bool match(llIcode op,eReg dest,uint32_t flgs)
{ {
return (getOpcode()==op) and (m_dst.regi==dest) and testFlags(flgs); return match(op) and match(dest) and testFlags(flgs);
} }
bool match(llIcode op,eReg dest,eReg src_reg) bool match(llIcode op,eReg dest,eReg src_reg)
{ {
return (getOpcode()==op) and (m_dst.regi==dest) and (m_src.regi==src_reg); return match(op) and match(dest) and (m_src.regi==src_reg);
} }
bool match(eReg dest,eReg src_reg) bool match(eReg dest,eReg src_reg)
{ {
return (m_dst.regi==dest) and (m_src.regi==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) bool match(eReg dest)
{ {
@ -378,7 +377,7 @@ public:
} }
bool match(llIcode op,uint32_t flgs) bool match(llIcode op,uint32_t flgs)
{ {
return (getOpcode()==op) and testFlags(flgs); return match(op) and testFlags(flgs);
} }
void set(llIcode op,uint32_t flags) void set(llIcode op,uint32_t flags)
{ {
@ -402,7 +401,6 @@ public:
void findJumpTargets(CIcodeRec &_pc); void findJumpTargets(CIcodeRec &_pc);
void writeIntComment(QTextStream & s); void writeIntComment(QTextStream & s);
void dis1Line(int loc_ip, int pass); void dis1Line(int loc_ip, int pass);
QTextStream & strSrc(QTextStream & os, bool skip_comma=false);
void flops(QTextStream & out); void flops(QTextStream & out);
bool isJmpInst(); bool isJmpInst();
@ -411,33 +409,30 @@ public:
{ {
setOpcode(0); setOpcode(0);
} }
const LLOperand & dst() const { return m_dst; }
LLOperand & dst() { return m_dst; }
const LLOperand & src() const { return m_src; } const LLOperand & src() const { return m_src; }
LLOperand & src() { return m_src; } LLOperand & src() { return m_src; }
void replaceSrc(const LLOperand &with) void replaceSrc(const LLOperand &with) { m_src = with; }
{ void replaceSrc(eReg r) { m_src = LLOperand::CreateReg2(r); }
m_src = with; void replaceSrc(int64_t r) { m_src = LLOperand::CreateImm2(r); }
} void replaceDst(const LLOperand &with) { m_dst = with; }
void replaceSrc(eReg r) bool srcIsImmed() const { return (flg & I)!=0; }
{
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; 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; }
@ -613,7 +646,7 @@ 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

@ -104,10 +104,7 @@ 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) */

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;
typedef FunctionListType lFunction;
typedef FunctionListType::iterator ilFunction;
SYMTAB symtab; /* Global symbol table */
FunctionListType pProcList;
CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */
PROG prog; /* Loaded program image parameters */ PROG prog; /* Loaded program image parameters */
// no copies CommandStream m_project_command_stream;
std::unordered_map<PtrFunction,CommandStream> m_function_streams;
bool m_error_state;
struct PatternLocator *m_pattern_locator;
public:
// prevent Project instance copying
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,15 +3,16 @@
* (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 */

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;
@ -46,6 +50,7 @@ struct STKSYM : public SymbolCommon
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

@ -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);
/**************************************************************************** /****************************************************************************
@ -65,16 +24,16 @@ 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);
@ -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);
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
SynthLab = SYNTHESIZED_MIN;
/* Check for special settings of initial state, based on idioms of the bool MachineStateInitialization::execute(CommandContext *ctx)
startup code */
state.checkStartup();
ilFunction start_proc;
/* Make a struct for the initial procedure */
if (prog.offMain != -1)
{ {
start_proc = proj.createFunction(0,"main"); assert(ctx && ctx->m_project);
start_proc->retVal.loc = REG_FRAME; Project &proj(*ctx->m_project);
start_proc->retVal.type = TYPE_WORD_SIGN; const PROG &prog(proj.prog);
start_proc->retVal.id.regi = rAX; proj.m_entry_state.setState(rES, 0); /* PSP segment */
/* We know where main() is. Start the flow of control from there */ proj.m_entry_state.setState(rDS, 0);
start_proc->procEntry = prog.offMain; proj.m_entry_state.setState(rCS, prog.initCS);
proj.m_entry_state.setState(rSS, prog.initSS);
proj.m_entry_state.setState(rSP, prog.initSP);
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
proj.SynthLab = SYNTHESIZED_MIN;
return true;
}
bool FindMain::execute(CommandContext *ctx) {
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction start_func = proj.findByName("start");
if(ctx->m_project->m_entry_state.IP==0) {
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
return false;
}
/* Check for special settings of initial state, based on idioms of the startup code */
if(checkStartup(ctx->m_project->m_entry_state)) {
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);
main_type->setCallingConvention(CConv::C);
proj.addCommand(new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type));
proj.addCommand(new LoadPatternLibrary());
} else {
start_func->state = proj.m_entry_state; // just in case we fail to find main, initialize 'state' for start func
}
return true;
}
QString CreateFunction::instanceDescription() const {
return QString("%1 \"%2\" @ 0x%3").arg(name()).arg(m_name).arg(m_addr.addr,0,16,QChar('0'));
}
bool CreateFunction::execute(CommandContext *ctx) {
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction func = proj.createFunction(m_type,m_name,m_addr);
if(m_name=="main") {
/* In medium and large models, the segment of main may (will?) not be /* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */ the same as the initial CS segment (of the startup code) */
state.setState(rCS, prog.segMain); proj.m_entry_state.setState(rCS, prog.segMain);
state.IP = prog.offMain; proj.m_entry_state.IP = prog.offMain;
func->state = proj.m_entry_state;
} }
else if(m_name=="start") {
{ proj.addCommand(new MachineStateInitialization);
start_proc = proj.createFunction(0,"start"); proj.addCommand(new FindMain);
/* Create initial procedure at program start address */
start_proc->procEntry = (uint32_t)state.IP;
} }
/* The state info is for the first procedure */ // proj.addCommand(new ProcessFunction);
start_proc->state = state; //proj.addCommand(new FollowControl());
/* Set up call graph initial node */
proj.callGraph = new CALL_GRAPH;
proj.callGraph->proc = start_proc;
/* 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 */
prog.bSigs = SetupLibCheck();
//BUG: proj and g_proj are 'live' at this point !
/* Recursively build entire procedure list */ /* Recursively build entire procedure list */
start_proc->FollowCtrl(proj.callGraph, &state); //proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
return true;
/* This proc needs to be called to clean things up from SetupLibCheck() */
CleanupLibCheck();
} }

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

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

@ -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+" (";
@ -282,7 +282,7 @@ void Function::codeGen (QIODevice &fs)
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 */
{ {

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

@ -239,9 +239,9 @@ 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:
@ -250,8 +250,11 @@ void Function::writeProcComments(QTextStream &ostr)
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;
case TYPE_UNKNOWN:
// void return type
break;
default: default:
fprintf(stderr,"Unknown retval type %d",this->retVal.type); fprintf(stderr,"Unknown retval type %d",getReturnType());
break; break;
} /* eos */ } /* eos */
} }

View File

@ -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);
@ -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;
@ -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();
@ -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());
@ -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);
} }
@ -879,14 +877,14 @@ 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);
@ -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
@ -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);
@ -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,7 +1094,7 @@ 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()));
@ -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);
} }
} }
} }

View File

@ -14,10 +14,10 @@
#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 */
@ -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
@ -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
{ {
@ -112,7 +113,7 @@ static vector<POSSTACK_ENTRY> posStack; /* position stack */
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());
@ -138,7 +139,7 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
* 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)
@ -768,5 +412,230 @@ void LLInst::flops(QTextStream &out)
} }
} }
} }
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

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

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

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

@ -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
@ -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

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

View File

@ -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

@ -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

@ -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;
@ -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);
@ -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,7 +204,7 @@ 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_)
{ {
@ -453,7 +453,8 @@ eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
} }
/* 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. */

View File

@ -2,10 +2,14 @@
* 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>
@ -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 bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph);
static bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate);
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag); static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
void interactDis(Function * initProc, int ic); //void interactDis(Function * initProc, int ic);
extern uint32_t SynthLab;
/* 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,8 +249,8 @@ 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;
@ -190,39 +258,40 @@ void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
/* 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;
@ -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
{
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] */ * JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS; 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);
/* 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,29 +767,21 @@ 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
@ -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;
} }
@ -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:
@ -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,7 +43,7 @@ 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)
{ {
@ -57,10 +56,10 @@ bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
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
@ -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) {

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,4 +1,4 @@
/***************************************************************************** /**
* 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
@ -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,16 +620,16 @@ 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.
@ -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();
}

View File

@ -0,0 +1,49 @@
#ifndef FUNCTIONVIEWWIDGET_H
#define FUNCTIONVIEWWIDGET_H
#include "StructuredTextTarget.h"
#include "RenderTags.h"
#include <memory>
#include <QWidget>
#include <QTextDocument>
#include <QTextBlockFormat>
class Function;
typedef std::shared_ptr<Function> PtrFunction;
namespace Ui {
class FunctionViewWidget;
}
//TODO: convert 'controllers' of each hex/asm/high-level areas into standalone classes
class FunctionViewWidget : public QWidget,public IStructuredTextTarget
{
Q_OBJECT
PtrFunction m_viewed_function; // 'model' this view is bound to
QTextDocument *m_assembly_rendering;
QTextCursor* m_doc_cursor;
QTextBlockFormat m_current_format;
QTextCharFormat m_chars_format;
public:
explicit FunctionViewWidget(PtrFunction func,QWidget *parent = 0);
~FunctionViewWidget();
const PtrFunction &viewedFunction() const { return m_viewed_function; }
void renderCurrent();
// IStructuredTextTarget interface
void prtt(const char * s);
void prtt(const QString &s);
void addEOL() override;
void TAGbegin(enum TAG_TYPE tag_type, void * p);
void TAGend(enum TAG_TYPE tag_type);
void delChars(int v);
private slots:
void on_tabWidget_currentChanged(int index);
private:
Ui::FunctionViewWidget *ui;
QString collected_text;
};
#endif // FUNCTIONVIEWWIDGET_H

View File

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FunctionViewWidget</class>
<widget class="QWidget" name="FunctionViewWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>708</width>
<height>582</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="binaryTab">
<attribute name="title">
<string>Binary</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTextEdit" name="edtBinary">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Corbel'; font-size:10pt; font-weight:400; font-style:normal;&quot; bgcolor=&quot;#000000&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="assemblyTab">
<attribute name="title">
<string>Assembly</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTextEdit" name="textEdit">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Corbel'; font-size:10pt; font-weight:400; font-style:normal;&quot; bgcolor=&quot;#000000&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="highLevelTab">
<attribute name="title">
<string>High level</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="edtHighLevel">
<property name="undoRedoEnabled">
<bool>false</bool>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Corbel'; font-size:10pt; font-weight:400; font-style:normal;&quot; bgcolor=&quot;#000000&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

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

@ -0,0 +1,23 @@
#include "RenderTags.h"
QColor RenderTag_2_Color(TAG_TYPE tag_type)
{
switch (tag_type)
{
case XT_invalid : return QColor(255,255,255);
case XT_blank : return QColor(255,255,255);
case XT_Symbol : return QColor(57,109,165);
case XT_Function : return QColor(255,255,255);
case XT_Keyword : return QColor(255,255,0);
case XT_Class : return QColor(255,255,0);
case XT_K1 : return QColor(163,70,255);
case XT_Comment : return QColor(0,245,255);
case XT_DataType : return QColor(100,222,192);
case XT_Number : return QColor(0,255,0);
case XT_AsmStack : return QColor(0,70,255);
case XT_AsmOffset: return QColor(70,180,70);
case XT_AsmLabel : return QColor(255,180,70);
case XT_FuncName : return QColor(255,0,255);
}
return QColor(255,255,255);
}

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

@ -0,0 +1,28 @@
#pragma once
#include <QtGui/QColor>
enum TAG_TYPE
{
XT_invalid = 0,
XT_blank,
XT_Symbol,
XT_Function,
XT_Keyword, //Keywords, such as struct, union, for, while
XT_Class, //For comound types (struct/class/union)
XT_K1, //Braces {} []
XT_Comment, //Comments
XT_DataType, //
XT_Number, //
XT_AsmStack, //stack values
XT_AsmOffset, //seg:offset
XT_AsmLabel, //label name
XT_FuncName,
};
struct tColorPair
{
QColor color1;
QColor color2;
};
extern tColorPair tbl_color[];
QColor RenderTag_2_Color(TAG_TYPE tag_type);

View File

@ -0,0 +1,26 @@
#pragma once
#include "src/ui/RenderTags.h"
class IStructuredTextTarget {
public:
virtual void TAGbegin(TAG_TYPE t,void *data)=0;
virtual void TAGend(TAG_TYPE t)=0;
virtual void prtt(const QString &v)=0;
virtual void delChars(int v) = 0;
virtual void addEOL() = 0; // some targets might want to disable newlines
void addSpace(int n=1) {
while(n--)
prtt(" ");
}
void addTaggedString(TAG_TYPE t, QString v) {
this->TAGbegin(t,nullptr);
this->prtt(v);
this->TAGend(t);
}
void addTaggedString(TAG_TYPE t, QString str, void *value) {
this->TAGbegin(t,value);
this->prtt(str);
this->TAGend(t);
}
};

View File

@ -58,7 +58,7 @@ boolT phDoCB(int id, char *data) {
return true; return true;
} }
void phError(char *errmsg) { void phError(const char *errmsg) {
char msg[200]; char msg[200];
sprintf(msg, "PH *ERROR*\nFile: %s L=%d C=%d O=%lu\n%s", fileName, line, col, sprintf(msg, "PH *ERROR*\nFile: %s L=%d C=%d O=%lu\n%s", fileName, line, col,
@ -66,7 +66,7 @@ void phError(char *errmsg) {
printf(msg); printf(msg);
} }
void phWarning(char *errmsg) { void phWarning(const char *errmsg) {
char msg[200]; char msg[200];
sprintf(msg, "PH -warning-\nFile: %s L=%d C=%d O=%lu\n%s\n", fileName, line, sprintf(msg, "PH -warning-\nFile: %s L=%d C=%d O=%lu\n%s\n", fileName, line,
@ -406,8 +406,9 @@ void phChar(char ch) {
/* Take a lump of data from a header file, and churn the state machine /* Take a lump of data from a header file, and churn the state machine
through each char */ through each char */
boolT phData(char *buff, int ndata) { boolT phData(char *buff, int ndata) {
int i, j; int i;
#ifdef DEBUG #ifdef DEBUG
int j=0;
char cLine[81]; char cLine[81];
char cfLine[90]; char cfLine[90];
#endif #endif
@ -415,7 +416,6 @@ boolT phData(char *buff, int ndata) {
if (ndata < 1) { if (ndata < 1) {
ndata = strlen(buff); ndata = strlen(buff);
} }
j = 0;
for (i = 0; i < ndata; i++) { for (i = 0; i < ndata; i++) {
phChar(buff[i]); phChar(buff[i]);
@ -835,7 +835,6 @@ boolT isAttrib(void) {
return false; return false;
return true; return true;
} }
boolT isCdecl(void) { boolT isCdecl(void) {
return ((strcmp(token, "__cdecl") == 0) || (strcmp(token, "_Cdecl") == 0) || return ((strcmp(token, "__cdecl") == 0) || (strcmp(token, "_Cdecl") == 0) ||
(strcmp(token, "cdecl") == 0)); (strcmp(token, "cdecl") == 0));

View File

@ -20,8 +20,8 @@ typedef unsigned char boolT; /* 8 bits */
#define ERRF stdout #define ERRF stdout
void phError(char *errmsg); void phError(const char * errmsg);
void phWarning(char *errmsg); void phWarning(const char * errmsg);
#define ERR(msg) phError(msg) #define ERR(msg) phError(msg)
#ifdef DEBUG #ifdef DEBUG