Compare commits

..

11 Commits

Author SHA1 Message Date
Godzil
b58f315c98 cleanup things, stop trying with CS 2018-09-19 17:59:25 +01:00
Godzil
7687c2b7d2 Trying to make parser to correctly handle CS 2018-09-18 18:50:13 +01:00
Artur K
0abbce6f4e
Merge pull request #32 from nemerle/add-license-1
Create LICENSE
2018-03-23 19:59:48 +01:00
Artur K
8ffdf657ec
Create LICENSE
Original code was using GPL.
2018-03-23 19:59:34 +01:00
nemerle
2232a76033 Disregard signed/unsigned difference in AstIdent::idID 2017-02-13 16:14:38 +01:00
nemerle
d6af9c1555 Add iInvalid enum value for invalid instructions
Various cleanups.
2017-02-13 13:24:54 +01:00
nemerle
d7acc8cd4d rename otherLongRegi to getPairedRegisterAt, make it a method of
LOCAL_ID struct.
2017-02-13 12:31:30 +01:00
nemerle
a5f1d17e83 Various code cleanups. 2017-02-13 12:11:29 +01:00
nemerle
29efcd5be1 Remove references to malloc.h closes #28 2017-02-07 12:09:58 +01:00
Artur K
4656db9484 Merge pull request #25 from gitter-badger/gitter-badge
Add a Gitter chat badge to Readme.md
2016-05-23 13:30:14 +02:00
The Gitter Badger
b33d7239e5 Add Gitter badge 2016-05-23 11:28:47 +00:00
115 changed files with 4024 additions and 6137 deletions

View File

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

View File

@ -1,6 +1,10 @@
PROJECT(dcc_original)
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})
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")
@ -14,25 +18,15 @@ ENDIF()
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH})
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
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)
include(cotire)
FIND_PACKAGE(Boost)
IF(dcc_build_tests)
enable_testing()
find_package(Qt5Test)
#FIND_PACKAGE(GMock)
enable_testing()
FIND_PACKAGE(GMock)
ENDIF()
INCLUDE_DIRECTORIES(
${PROJECT_SOURCE_DIR}
3rd_party/libdisasm
include
include/idioms
@ -40,7 +34,109 @@ INCLUDE_DIRECTORIES(
${Boost_INCLUDE_DIRS}
)
ADD_SUBDIRECTORY(3rd_party)
ADD_SUBDIRECTORY(common)
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)
endif()

View File

@ -1,21 +0,0 @@
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()

339
LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -6,6 +6,8 @@ To reflect those fixes, I've edited the original readme a bit.
dcc Distribution
================
[![Join the chat at https://gitter.im/nemerle/dcc](https://badges.gitter.im/nemerle/dcc.svg)](https://gitter.im/nemerle/dcc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
The code provided in this distribution is (C) by their authors:
- Cristina Cifuentes (most of dcc code)
- Mike van Emmerik (signatures and prototype code)

View File

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

View File

@ -1,4 +1,4 @@
#!/bin/bash
mkdir -p tests/outputs
makedir -p tests/outputs
./test_use_all.sh
./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 "icode.h"
/* Basic block (BB) node definition */
class Function;
struct Function;
class CIcodeRec;
struct BB;
struct LOCAL_ID;
@ -27,7 +27,7 @@ struct TYPEADR_TYPE
};
struct BB
{
friend class Function;
friend struct Function;
private:
BB(const BB&);
BB() : nodeType(0),traversed(DFS_NONE),

View File

@ -3,9 +3,9 @@
#include <vector>
struct PROG /* Loaded program image parameters */
{
int16_t initCS=0;
int16_t initIP=0; /* These are initial load values */
int16_t initSS=0; /* Probably not of great interest */
uint16_t initCS=0;
uint16_t initIP=0; /* These are initial load values */
uint16_t initSS=0; /* Probably not of great interest */
uint16_t initSP=0;
bool fCOM=false; /* Flag set if COM program (else EXE)*/
int cReloc=0; /* No. of relocation table entries */
@ -14,8 +14,10 @@ struct PROG /* Loaded program image parameters */
int cProcs=0; /* Number of procedures so far */
int offMain=0; /* The offset 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 */
uint8_t * Imagez=nullptr; /* Allocated by loader to hold entire program image */
int addressingMode=0;
public:
const uint8_t *image() const {return Imagez;}
void displayLoadInfo();

View File

@ -1,41 +1,33 @@
#pragma once
#include "ast.h"
#ifdef PASCAL
#undef PASCAL
#endif
class QTextStream;
struct CConv {
enum CC_Type {
UNKNOWN=0,
C,
PASCAL
enum Type {
eUnknown=0,
eCdecl,
ePascal
};
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;
static CConv * create(CC_Type v);
static CConv * create(Type v);
protected:
};
struct C_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &);
private:
int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs);
};
struct Pascal_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
virtual void writeComments(QTextStream &) override;
void calculateStackLayout(Function *func) override;
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &);
};
struct Unknown_CallingConvention : public CConv {
void processHLI(Function *func, Expr *_exp, iICODE picode) override {}
void calculateStackLayout(Function *func) override;
virtual void writeComments(QTextStream &) override;
void processHLI(Function *func, Expr *_exp, iICODE picode) {}
virtual void writeComments(QTextStream &);
};

View File

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

View File

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

View File

@ -99,7 +99,7 @@ enum icodeType
/* LOW_LEVEL icode opcodes */
enum llIcode
{
//iINVALID,
iINVALID=-1,
iCBW, /* 0 */
iAAA,
iAAD,
@ -263,8 +263,7 @@ enum hlType
TYPE_STR, /* string */
TYPE_CONST, /* constant (any type) */
TYPE_FLOAT, /* floating point */
TYPE_DOUBLE, /* double precision float */
TYPE_FUNC
TYPE_DOUBLE /* double precision float */
};
/* Operand is defined, used or both flag */

View File

@ -6,8 +6,6 @@
#include "StackFrame.h"
#include "CallConvention.h"
#include <memory>
#include <stdint.h>
#include <QtCore/QString>
#include <bitset>
#include <map>
@ -19,24 +17,28 @@ class QTextStream;
struct CALL_GRAPH;
struct Expr;
struct Disassembler;
class Function;
struct Function;
struct CALL_GRAPH;
struct PROG;
struct IStructuredTextTarget;
struct Function;
/* Procedure FLAGS */
enum PROC_FLAGS
{
PROC_BADINST=0x00000100, /* Proc contains invalid or 386 instruction */
PROC_IJMP =0x00000200, /* Proc incomplete due to indirect jmp */
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
// CALL_C =0x00004000, /* Proc uses C calling convention */
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
PROC_NEAR =0x00010000, /* Proc exits with near return */
PROC_FAR =0x00020000, /* Proc exits with far return */
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
PROC_IS_FUNC=0x00800000, /* Proc is a function */
REG_ARGS =0x01000000, /* Proc has registers as arguments */
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
@ -47,43 +49,10 @@ enum PROC_FLAGS
//#define CALL_MASK 0xFFFF9FFF /* Masks off CALL_C and CALL_PASCAL */
};
struct Type {
hlType dcc_type;
};
struct FunctionType : public Type
struct FunctionType
{
CConv * m_call_conv;
std::vector<Type> ContainedTys;
ID retVal; /* Return value - identifier */
bool m_vararg=false;
unsigned getNumParams() const { return ContainedTys.size(); }
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
{
@ -119,17 +88,7 @@ public:
}
void push_back(BB *v) { m_listBB.push_back(v);}
};
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>
struct Function
{
typedef std::list<BB *> BasicBlockListType;
// BasicBlock iterators...
@ -137,18 +96,16 @@ class Function : public std::enable_shared_from_this<Function>
typedef BasicBlockListType::const_iterator const_iterator;
protected:
BasicBlockListType BasicBlocks; ///< The basic blocks
Function(FunctionType *ty) : nStep(eNotDecoded),procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
hasCase(false),liveAnal(0)
{
type = ty;
if(!ty) // No type was provided, create it
type = new FunctionType;
callingConv(CConv::UNKNOWN);
callingConv(CConv::eUnknown);
}
public:
DecompilationStep nStep; // decompilation step number for this function
FunctionType * type;
CConv * m_call_conv;
uint32_t procEntry; /* label number */
QString name; /* Meaningful name for this proc */
STATE state; /* Entry state */
@ -157,6 +114,7 @@ public:
int16_t cbParam; /* Probable no. of bytes of parameters */
STKFRAME args; /* Array of arguments */
LOCAL_ID localId; /* Local identifiers */
ID retVal; /* Return value - identifier */
/* Icodes and control flow graph */
CIcodeRec Icode; /* Object with ICODE records */
@ -176,25 +134,20 @@ public:
delete type;
}
public:
static PtrFunction Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
{
PtrFunction r(new Function(ty));
Function *r=new Function(ty);
r->name = nm;
return r;
}
hlType getReturnType() const {
return getFunctionType()->getReturnType();
}
FunctionType *getFunctionType() const {
return type;
}
CConv *callingConv() const { return type->m_call_conv;}
void callingConv(CConv::CC_Type v);
CConv *callingConv() const { return m_call_conv;}
void callingConv(CConv::Type v);
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=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;}
void compoundCond();
void writeProcComments();
@ -208,7 +161,10 @@ public:
void createCFG();
void markImpure();
void findImmedDom();
void FollowCtrl(CALL_GRAPH *pcallGraph, 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 codeGen(QIODevice & fs);
void mergeFallThrough(BB *pBB);
@ -218,7 +174,6 @@ public:
void controlFlowAnalysis();
void newRegArg(iICODE picode, iICODE ticode);
void writeProcComments(QTextStream & ostr);
void toStructuredText(IStructuredTextTarget *out,int level);
void displayCFG();
void displayStats();
@ -228,10 +183,11 @@ public:
Expr * adjustActArgType(Expr *_exp, hlType forType);
QString writeCall(Function *tproc, STKFRAME &args, int *numLoc);
void processDosInt(STATE *pstate, PROG &prog, bool done);
void switchState(DecompilationStep s);
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode);
protected:
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 Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
@ -258,8 +214,12 @@ protected:
void genLiveKtes();
bool findDerivedSeq(derSeq &derivedGi);
bool nextOrderGraph(derSeq &derivedGi);
void addOutEdgesForConditionalJump(BB *pBB, int next_ip, LLInst *ll);
void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll);
private:
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
};
typedef std::list<PtrFunction> FunctionListType;
typedef std::list<Function> FunctionListType;
typedef FunctionListType lFunction;
typedef lFunction::iterator ilFunction;

View File

@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon<STKSYM>
//std::vector<STKSYM> sym;
//STKSYM * sym; /* Symbols */
int16_t m_minOff; /* Initial offset in stack frame*/
int16_t m_maxOff; /* Maximum offset in stack frame*/
int16_t maxOff; /* Maximum offset in stack frame*/
int cb; /* Number of bytes in arguments */
int numArgs; /* No. of arguments in the table*/
void adjustForArgType(size_t numArg_, hlType actType_);
STKFRAME() : m_minOff(0),m_maxOff(0),cb(0),numArgs(0)
STKFRAME() : m_minOff(0),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,
LESS_EQUAL, GREATER, GREATER_EQUAL, LESS};
struct AstIdent;
class Function;
struct Function;
struct STKFRAME;
struct LOCAL_ID;
struct ICODE;
@ -221,9 +221,6 @@ struct AstIdent : public UnaryOperator
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);
virtual Expr *insertSubTreeLongReg(Expr *_expr, int longIdx);
virtual bool xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locId);
protected:
eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl);
};
struct GlobalVariable : public AstIdent
{
@ -272,7 +269,7 @@ struct Constant : public AstIdent
}
QString walkCondExpr(Function *pProc, int *numLoc) const;
int hlTypeSize(Function *pproc) const;
hlType expType(Function *pproc) const;
hlType expType(Function *pproc) const { return TYPE_CONST; }
};
struct FuncNode : public AstIdent
{

View File

@ -28,25 +28,25 @@ extern bundle cCode; /* Output C procedure's declaration and code */
extern QString asm1_name, asm2_name; /* Assembler output filenames */
typedef struct { /* Command line option flags */
unsigned verbose : 1;
unsigned VeryVerbose : 1;
unsigned asm1 : 1; /* Early disassembly listing */
unsigned asm2 : 1; /* Disassembly listing after restruct */
unsigned Map : 1;
unsigned Stats : 1;
unsigned Interact : 1; /* Interactive mode */
unsigned Calls : 1; /* Follow register indirect calls */
/** Command line option flags */
struct OPTION
{
bool verbose;
bool VeryVerbose;
bool asm1; /* Early disassembly listing */
bool asm2; /* Disassembly listing after restruct */
bool Map;
bool Stats;
bool Interact; /* Interactive mode */
bool Calls; /* Follow register indirect calls */
QString filename; /* The input filename */
uint32_t CustomEntryPoint;
} OPTION;
};
extern OPTION option; /* Command line options */
#include "BinaryImage.h"
/* Memory map states */
enum eAreaType
{
@ -82,11 +82,12 @@ eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */
void parse (CALL_GRAPH * *); /* parser.c */
extern int strSize (const uint8_t *, char); /* parser.c */
void interactDis(const PtrFunction &, int initIC); /* disassem.c */
//void disassem(int pass, Function * pProc); /* disassem.c */
void interactDis(Function *, int initIC); /* disassem.c */
bool JmpInst(llIcode opcode); /* idioms.c */
queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */
bool SetupLibCheck(QString pattern_file_id); /* chklib.c */
bool SetupLibCheck(void); /* chklib.c */
void CleanupLibCheck(void); /* chklib.c */
bool LibCheck(Function &p); /* chklib.c */
@ -99,7 +100,5 @@ QString writeJcondInv(HLTYPE, Function *, int *);
/* Exported funcions from locident.c */
bool checkLongEq(LONG_STKID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &atOffset);
bool checkLongRegEq(LONGID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &);
eReg otherLongRegi(eReg, int, LOCAL_ID *);
extern const char *indentStr(int level);

View File

@ -4,11 +4,21 @@
#include <QtCore/QObject>
#include <QtCore/QDir>
class IStructuredTextTarget;
class IXmlTarget;
struct IDcc {
static IDcc *get();
virtual bool load(QString name)=0; // load and preprocess -> find entry point
virtual void BaseInit()=0;
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 dataDir(QString kind)=0;
};

View File

@ -7,22 +7,19 @@
#pragma once
#include "bundle.h"
#include <memory>
#include <fstream>
#include <vector>
#include <QString>
#include <QTextStream>
struct LLInst;
class Function;
typedef std::shared_ptr<Function> PtrFunction;
struct Function;
struct Disassembler
{
protected:
int pass=0;
int g_lab=0;
QIODevice *m_disassembly_target=nullptr;
int pass;
int g_lab;
//bundle &cCode;
QIODevice *m_disassembly_target;
QTextStream m_fp;
std::vector<std::string> m_decls;
std::vector<std::string> m_code;
@ -30,10 +27,11 @@ protected:
public:
Disassembler(int _p) : pass(_p)
{
g_lab=0;
}
void disassem(PtrFunction ppProc);
void disassem(PtrFunction ppProc, int i);
public:
void disassem(Function *ppProc);
void disassem(Function *ppProc, int i);
void dis1Line(LLInst &inst, int loc_ip, int pass);
};
/* Definitions for extended keys (first key is zero) */

View File

@ -8,7 +8,7 @@
#include <stdint.h>
#include <list>
class Function;
struct Function;
/* Types of basic block nodes */
/* Real basic blocks: type defined according to their out-edges */
enum eBBKind

View File

@ -25,7 +25,7 @@
struct LOCAL_ID;
struct BB;
class Function;
struct Function;
struct STKFRAME;
class CIcodeRec;
struct ICODE;
@ -165,8 +165,8 @@ struct AssignType : public HlTypeSupport
/* for HLI_ASSIGN */
protected:
public:
Expr *m_lhs;
Expr *m_rhs;
Expr * m_lhs;
Expr * m_rhs;
AssignType() {}
Expr *lhs() const {return m_lhs;}
void lhs(Expr *l);
@ -176,8 +176,8 @@ public:
struct ExpType : public HlTypeSupport
{
/* for HLI_JCOND, HLI_RET, HLI_PUSH, HLI_POP*/
Expr *v;
ExpType() : v(0) {}
Expr * v;
ExpType() : v(nullptr) {}
bool removeRegFromLong(eReg regi, LOCAL_ID *locId)
{
v=performLongRemoval(regi,locId,v);
@ -253,7 +253,7 @@ struct LLOperand
bool is_offset; // set by jumps
bool is_compound;
size_t width;
/* Source operand if (flg & I) */
//union {/* Source operand if (flg & I) */
struct { /* Call & # actual arg bytes */
Function *proc; /* pointer to target proc (for CALL(F))*/
int cb; /* # actual arg bytes */
@ -300,11 +300,11 @@ struct LLOperand
Op.regi = (eReg)Val;
return Op;
}
bool isSet() const
bool isSet()
{
return not (*this == LLOperand());
}
void addProcInformation(int param_count, CConv::CC_Type call_conv);
void addProcInformation(int param_count, CConv::Type call_conv);
bool isImmediate() const { return immed;}
void setImmediate(bool x) { immed=x;}
bool compound() const {return is_compound;} // dx:ax pair
@ -313,7 +313,7 @@ struct LLOperand
struct LLInst
{
protected:
uint32_t m_opcode; // Low level opcode identifier
llIcode m_opcode; // Low level opcode identifier
uint32_t flg; /* icode flags */
LLOperand m_src; /* source operand */
public:
@ -326,50 +326,51 @@ public:
std::vector<uint32_t> caseTbl2;
int hllLabNum; /* label # for hll codegen */
uint32_t getOpcode() const { return m_opcode;}
void setOpcode(uint32_t op) { m_opcode=op; }
llIcode getOpcode() const { return m_opcode;}
void setOpcode(uint32_t op) { m_opcode=(llIcode)op; }
bool conditionalJump()
{
return (getOpcode() >= iJB) and (getOpcode() < iJCXZ);
}
bool testFlags(uint32_t x) const { return (flg & x)!=0;}
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 GetLlLabel() const { return label;}
void SetImmediateOp(uint32_t dw) {m_src.SetImmediateOp(dw);}
bool match(llIcode op)
{
return (getOpcode()==op);
}
bool matchWithRegDst(llIcode op)
{
return match(op) and m_dst.isReg();
return (getOpcode()==op) and m_dst.isReg();
}
bool match(llIcode op,eReg dest)
{
return match(op) and match(dest);
return (getOpcode()==op)&&m_dst.regi==dest;
}
bool match(llIcode op,eReg dest,uint32_t flgs)
{
return match(op) and match(dest) and testFlags(flgs);
return (getOpcode()==op) and (m_dst.regi==dest) and testFlags(flgs);
}
bool match(llIcode op,eReg dest,eReg src_reg)
{
return match(op) and match(dest) and (m_src.regi==src_reg);
return (getOpcode()==op) and (m_dst.regi==dest) and (m_src.regi==src_reg);
}
bool match(eReg dest,eReg src_reg)
{
return match(dest) and (m_src.regi==src_reg);
}
bool matchAny(std::initializer_list<llIcode> ops) {
for(llIcode op : ops) {
if(match(op))
return true;
}
return false;
return (m_dst.regi==dest) and (m_src.regi==src_reg);
}
bool match(eReg dest)
{
@ -377,7 +378,7 @@ public:
}
bool match(llIcode op,uint32_t flgs)
{
return match(op) and testFlags(flgs);
return (getOpcode()==op) and testFlags(flgs);
}
void set(llIcode op,uint32_t flags)
{
@ -401,6 +402,7 @@ public:
void findJumpTargets(CIcodeRec &_pc);
void writeIntComment(QTextStream & s);
void dis1Line(int loc_ip, int pass);
QTextStream & strSrc(QTextStream & os, bool skip_comma=false);
void flops(QTextStream & out);
bool isJmpInst();
@ -409,30 +411,33 @@ public:
{
setOpcode(0);
}
const LLOperand & dst() const { return m_dst; }
LLOperand & dst() { return m_dst; }
const LLOperand & src() const { return m_src; }
LLOperand & src() { return m_src; }
void replaceSrc(const LLOperand &with) { m_src = with; }
void replaceSrc(eReg r) { m_src = LLOperand::CreateReg2(r); }
void replaceSrc(int64_t r) { m_src = LLOperand::CreateImm2(r); }
void replaceDst(const LLOperand &with) { m_dst = with; }
bool srcIsImmed() const { return (flg & I)!=0; }
const LLOperand &src() const {return m_src;}
LLOperand &src() {return m_src;}
void replaceSrc(const LLOperand &with)
{
m_src = with;
}
void replaceSrc(eReg r)
{
m_src = LLOperand::CreateReg2(r);
}
void replaceSrc(int64_t r)
{
m_src = LLOperand::CreateImm2(r);
}
void replaceDst(const LLOperand &with)
{
m_dst = with;
}
// void replaceDst(eReg r)
// {
// dst = LLOperand::CreateReg2(r);
// }
ICODE *m_link;
condId idType(opLoc sd) const;
const LLOperand * get(opLoc sd) const { return (sd == SRC) ? &src() : &m_dst; }
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 */
struct ICODE
@ -440,7 +445,7 @@ struct ICODE
// use llvm names at least
typedef BB MachineBasicBlock;
protected:
LLInst *m_ll;
LLInst m_ll;
HLTYPE m_hl;
MachineBasicBlock * Parent; /* BB to which this icode belongs */
bool invalid; /* Has no HIGH_LEVEL equivalent */
@ -543,8 +548,8 @@ public:
DU1 du1; /* du chain 1 */
int loc_ip; // used by CICodeRec to number ICODEs
LLInst * ll() { return m_ll;}
const LLInst * ll() const { return m_ll;}
LLInst * ll() { return &m_ll;}
const LLInst * ll() const { return &m_ll;}
HLTYPE * hlU() {
// assert(type==HIGH_LEVEL);
@ -584,46 +589,8 @@ public:
{
return hlU()->call.newStkArg(exp,opcode,pproc);
}
ICODE() :Parent(0),invalid(false),type(NOT_SCANNED_ICODE),loc_ip(0)
ICODE() : m_ll(this),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:
const MachineBasicBlock* getParent() const { return Parent; }
@ -646,7 +613,7 @@ class CIcodeRec : public std::list<ICODE>
public:
CIcodeRec(); // Constructor
ICODE * addIcode(const ICODE * pIcode);
ICODE * addIcode(ICODE *pIcode);
void SetInBB(rCODE &rang, BB* pnewBB);
bool labelSrch(uint32_t target, uint32_t &pIndex);
iterator labelSrch(uint32_t target);

View File

@ -28,7 +28,7 @@ struct LLInst;
typedef std::list<ICODE>::iterator iICODE;
struct IDX_ARRAY : public std::vector<iICODE>
{
bool inList(iICODE idx)
bool inList(iICODE idx) const
{
return std::find(begin(),end(),idx)!=end();
}
@ -96,15 +96,17 @@ protected:
LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */
public:
hlType type; /* Probable type */
bool illegal; /* Boolean: not a valid field any more */
//std::vector<iICODE> idx;
IDX_ARRAY idx; /* Index into icode array (REG_FRAME only) */
frameType loc; /* Frame location */
bool illegal; /* Boolean: not a valid field any more */
bool hasMacro; /* Identifier requires a macro */
char macro[10]; /* Macro for this identifier */
QString name; /* Identifier's name */
union ID_UNION { /* Different types of identifiers */
friend struct ID;
protected:
LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */
public:
eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */
uint8_t regOff; /* register offset (if any) */
@ -140,6 +142,8 @@ public:
sprintf (buf, "loc%d", i);
name=buf;
}
bool isLongRegisterPair() const { return (loc == REG_FRAME) and isLong();}
eReg getPairedRegister(eReg first) const;
};
struct LOCAL_ID
@ -167,10 +171,11 @@ public:
void flagByteWordId(int off);
void propLongId(uint8_t regL, uint8_t regH, const QString & name);
size_t csym() const {return id_arr.size();}
void newRegArg(iICODE picode, iICODE ticode) const;
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong) const;
void forwardSubs(Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode, int &numHlIcodes) const;
void newRegArg(ICODE & picode, ICODE & ticode) const;
void processTargetIcode(ICODE & picode, int &numHlIcodes, ICODE & ticode, bool isLong) const;
void forwardSubs(Expr *lhs, Expr *rhs, ICODE & picode, ICODE & ticode, int &numHlIcodes) const;
AstIdent *createId(const ID *retVal, iICODE ix_);
eReg getPairedRegisterAt(int idx,eReg first) const;
};

View File

@ -1,174 +1,74 @@
#pragma once
#include "symtab.h"
#include "BinaryImage.h"
#include "Procedure.h"
#include "state.h"
#include "src/Command.h"
#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 <QtCore/QString>
#include <list>
#include <unordered_set>
#include <unordered_map>
#include <string>
#include <stdint.h>
#include <assert.h>
#include <QtCore/QString>
#include "symtab.h"
#include "BinaryImage.h"
#include "Procedure.h"
class QString;
class SourceMachine;
struct CALL_GRAPH;
struct DosLoader;
struct SegOffAddr {
uint16_t seg;
uint32_t addr;
};
enum CompilerVendor {
eUnknownVendor=0,
eBorland,
eMicrosoft,
eLogitech,
};
enum CompilerLanguage {
eUnknownLanguage=0,
eAnsiCorCPP,
ePascal,
eModula2
};
enum CompilerMemoryModel {
eUnknownMemoryModel=0,
eTiny,
eSmall,
eCompact,
eMedium,
eLarge
};
struct LoaderMetadata {
CompilerVendor compiler_vendor;
CompilerLanguage compiler_language;
CompilerMemoryModel compiler_memory_model;
int compiler_version;
QString compilerId() const {
switch(compiler_vendor) {
case eBorland:
switch(compiler_language) {
case eUnknownLanguage:
return QString("bx") + codeModelChar();
case eAnsiCorCPP:
return QString("b%1%2").arg(compiler_version).arg(codeModelChar());
case ePascal:
return QString("tp%1").arg(compiler_version);
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
class IProject
{
Q_OBJECT
virtual PROG *binary()=0;
virtual const QString & project_name() const =0;
virtual const QString & binary_path() const =0;
};
class Project : public IProject
{
static Project *s_instance;
QString m_fname;
QString m_project_name;
QString m_output_path;
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 */
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
// no copies
Project(const Project&) = delete;
const Project & operator=(const Project & l) =delete;
// only moves
Project(); // default constructor,
public:
void create(const QString &a);
bool addLoadCommands(QString fname);
void processAllCommands();
void resetCommandsAndErrorState();
bool load();
const QString & output_path() const {return m_output_path;}
const QString & project_name() const {return m_project_name;}
const QString & binary_path() const {return m_fname;}
QString output_name(const char *ext);
ilFunction funcIter(Function *to_find);
PtrFunction findByEntry(uint32_t entry);
PtrFunction findByName(const QString &name);
PtrFunction createFunction(FunctionType *f, const QString & name, SegOffAddr addr);
ilFunction findByEntry(uint32_t entry);
ilFunction createFunction(FunctionType *f, const QString & name);
bool valid(ilFunction iter);
int getSymIdxByAdd(uint32_t adr);
int getSymIdxByAddr(uint32_t adr);
bool validSymIdx(size_t idx);
size_t symbolSize(size_t idx);
hlType symbolType(size_t idx);
const QString & symbolName(size_t idx);
const SYM & getSymByIdx(size_t idx) const;
LoaderMetadata &getLoaderMetadata() { assert(m_metadata_available); return m_loader_data; }
void setLoaderMetadata(LoaderMetadata d) { m_loader_data = d; m_metadata_available=true;}
static Project * get();
PROG * binary() {return &prog;}
SourceMachine *machine();
const FunctionListType &functions() const { 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:
void initialize();
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,16 +3,15 @@
* (C) Cristina Cifuentes, Mike van Emmerik
****************************************************************************/
#pragma once
#include "machine_x86.h"
#include <stdint.h>
#include <string.h>
#include <cstring>
#include "machine_x86.h"
/* STATE TABLE */
struct STATE
{
uint32_t IP; /* Offset into Image */
int16_t r[INDEX_BX_SI]; /* Register values */
uint16_t r[INDEX_BX_SI]; /* Value of segs and AX */
bool f[INDEX_BX_SI]; /* True if r[.] has a value */
struct
{ /* For case stmt indexed reg */

View File

@ -9,11 +9,7 @@
#include <QtCore/QString>
#include <string>
#include <vector>
#include <stdint.h>
class QTextStream;
struct Expr;
struct AstIdent;
struct TypeContainer;
@ -50,7 +46,6 @@ struct STKSYM : public SymbolCommon
bool hasMacro=false; /* This type needs a macro */
QString macro; /* Macro name */
bool invalid=false; /* Boolean: invalid entry in formal arg list*/
int arrayMembers=1; // for local variables if >1 marks this stack symbol as an array
void setArgName(int i)
{
char buf[32];
@ -86,7 +81,7 @@ public:
void updateSymType(uint32_t symbol, const TypeContainer &tc);
SYM *updateGlobSym(uint32_t operand, int size, uint16_t duFlag, bool &inserted_new);
};
class Function;
struct Function;
struct SYMTABLE
{
std::string pSymName; /* Ptr to symbolic name or comment */
@ -106,9 +101,9 @@ struct SYMTABLE
enum tableType /* The table types */
{
Label=0, /* The label table */
Comment, /* The comment table */
NUM_TABLE_TYPES /* Number of entries: must be last */
Comment /* The comment table */
};
constexpr int NUM_TABLE_TYPES = int(Comment)+1; /* Number of entries: must be last */
void createSymTables(void);
void destroySymTables(void);

View File

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

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -1,60 +0,0 @@
#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);
}

View File

@ -1,20 +0,0 @@
#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,131 +1,13 @@
set(dcc_LIB_SOURCES
CallConvention.cpp
ast.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
SET(dcc_test_SOURCES
tests/comwrite.cpp
tests/project.cpp
tests/loader.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)
SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
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()
target_link_libraries(tester dcc_lib disasm_s
${GMOCK_BOTH_LIBRARIES} ${REQ_LLVM_LIBRARIES})
add_test(dcc-tests tester)

View File

@ -1,89 +1,9 @@
#include "CallConvention.h"
#include "Procedure.h"
#include <QtCore/QTextStream>
#include <ostream>
#include <cassert>
static void calculateReturnLocations(Function *func) {
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;
}
#include "CallConvention.h"
#include <QtCore/QTextStream>
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)
CConv *CConv::create(Type v)
{
static C_CallingConvention *c_call = nullptr;
static Pascal_CallingConvention *p_call = nullptr;
@ -95,9 +15,9 @@ CConv *CConv::create(CC_Type v)
if(nullptr==u_call)
u_call = new Unknown_CallingConvention;
switch(v) {
case UNKNOWN: return u_call;
case C: return c_call;
case PASCAL: return p_call;
case eUnknown: return u_call;
case eCdecl: return c_call;
case ePascal: return p_call;
}
assert(false);
return nullptr;
@ -107,31 +27,11 @@ void C_CallingConvention::writeComments(QTextStream & ostr)
{
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)
{
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)
{
ostr << " * Unknown calling convention.\n";
}
void Unknown_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}

View File

@ -1,138 +0,0 @@
#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();
}

View File

@ -1,95 +0,0 @@
#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,19 +1,60 @@
#include "DccFrontend.h"
#include "Loaders.h"
#include "dcc.h"
#include "msvc_fixes.h"
#include "project.h"
#include "disassem.h"
#include "CallGraph.h"
#include "Command.h"
#include "chklib.h"
#include <QtCore/QFileInfo>
#include <QtCore/QDebug>
#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 displayMemMap(void);
/****************************************************************************
@ -24,16 +65,16 @@ void PROG::displayLoadInfo(void)
int i;
printf("File type is %s\n", (fCOM)?"COM":"EXE");
// if (not fCOM) {
// printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
// printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
// printf("File size / 512 = %04X pages\n", LH(&header.numPages));
// printf("# relocation items = %04X\n", LH(&header.numReloc));
// printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
// printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
// printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
// }
printf("Load image size = %08lX\n", cbImage); // - sizeof(PSP)
if (not fCOM) {
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
printf("File size / 512 = %04X pages\n", LH(&header.numPages));
printf("# relocation items = %04X\n", LH(&header.numReloc));
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
}
printf("Load image size = %08lX\n", cbImage - sizeof(PSP));
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
@ -125,106 +166,370 @@ bool DccFrontend::FrontEnd ()
/* Search through code looking for impure references and flag them */
Disassembler ds(1);
for(PtrFunction &f : Project::get()->pProcList)
for(Function &f : Project::get()->pProcList)
{
f->markImpure();
f.markImpure();
if (option.asm1)
{
ds.disassem(f);
ds.disassem(&f);
}
}
if (option.Interact)
{
interactDis(Project::get()->pProcList.front(), 0); /* Interactive disassembler */
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
}
/* Converts jump target addresses to icode offsets */
for(PtrFunction &f : Project::get()->pProcList)
for(Function &f : Project::get()->pProcList)
{
f->bindIcodeOff();
f.bindIcodeOff();
}
/* Print memory bitmap */
if (option.Map)
displayMemMap();
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;
}
};
#if 0
struct RomLoader {
bool canLoad(QFile &fp) {
fp.seek(0xFFF0);
uint8_t sig[1];
if(fp.read((char *)sig,1) == 1)
{
return (sig[0] == 0xEA);
}
return false;
}
bool load(PROG &prog,QFile &fp) {
printf("Loading ROM...\n");
fp.seek(0);
/* ROM file
* In this case the load module size is just the file length
*/
auto cb = fp.size();
fp.seek(cb - 0x10);
uint8_t buf[5];
printf("Going to get CS/IP...\n");
if(fp.read((char *)buf, 5) != 5)
{
return false;
}
fp.seek(0);
/* ROM File, Hard to say where it is suppose to start, so try to trust the
*/
prog.initIP = (buf[2] << 8) | buf[1];
//prog.initCS = 0;
prog.initCS = (buf[4] << 8) | buf[3];
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;
}
protected:
void prepareImage(PROG &prog, size_t sz, QFile &fp)
{
int32_t start = 0x100000 - sz;
/* Allocate a block of memory for the program. */
prog.cbImage = 1 * 1024 * 1024; /* Allocate the whole 1MB memory */
//prog.cbImage = 64 * 1024; /* Allocate the whole 1MB memory */
prog.Imagez = new uint8_t [prog.cbImage];
if (fp.read((char *)prog.Imagez + start, sz) != sz)
//if (fp.read((char *)prog.Imagez, sz) != sz)
{
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
}
}
};
#else
struct RomLoader {
bool canLoad(QFile &fp) {
fp.seek(0xFFF0);
uint8_t sig[1];
if(fp.read((char *)sig,1) == 1)
{
return (sig[0] == 0xEA);
}
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 = 0x000;
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;
}
protected:
void prepareImage(PROG &prog, size_t sz, QFile &fp)
{
/* Allocate a block of memory for the program. */
prog.cbImage = sz;
prog.Imagez = new uint8_t[prog.cbImage];
if (sz != fp.read((char *)prog.Imagez, sz))
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
}
};
#endif
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
****************************************************************************/
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);
}
RomLoader rom_loader;
ComLoader com_loader;
ExeLoader exe_loader;
if(rom_loader.canLoad(finfo)) {
/* We have no relacation and code should be on 64K only,
* So let's consider it as a COM file
*/
prog.fCOM = true;
return rom_loader.load(prog,finfo);
}
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
* procedures found */
void DccFrontend::parse(Project &proj)
{
PROG &prog(proj.prog);
STATE state;
/* Set initial state */
proj.addCommand(new MachineStateInitialization);
proj.addCommand(new FindMain);
}
state.setState(rES, 0); /* PSP segment */
state.setState(rDS, 0);
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;
bool MachineStateInitialization::execute(CommandContext *ctx)
{
assert(ctx && ctx->m_project);
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
proj.m_entry_state.setState(rES, 0); /* PSP segment */
proj.m_entry_state.setState(rDS, 0);
proj.m_entry_state.setState(rCS, prog.initCS);
proj.m_entry_state.setState(rSS, prog.initSS);
proj.m_entry_state.setState(rSP, prog.initSP);
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
proj.SynthLab = SYNTHESIZED_MIN;
return true;
}
bool FindMain::execute(CommandContext *ctx) {
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction start_func = proj.findByName("start");
if(ctx->m_project->m_entry_state.IP==0) {
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
return false;
}
/* Check for special settings of initial state, based on idioms of the startup code */
if(checkStartup(ctx->m_project->m_entry_state)) {
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") {
/* Check for special settings of initial state, based on idioms of the
startup code */
state.checkStartup();
ilFunction start_proc;
/* Make a struct for the initial procedure */
if (prog.offMain != -1)
{
start_proc = proj.createFunction(0,"main");
start_proc->retVal.loc = REG_FRAME;
start_proc->retVal.type = TYPE_WORD_SIGN;
start_proc->retVal.id.regi = rAX;
/* We know where main() is. Start the flow of control from there */
start_proc->procEntry = prog.offMain;
/* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */
proj.m_entry_state.setState(rCS, prog.segMain);
proj.m_entry_state.IP = prog.offMain;
func->state = proj.m_entry_state;
state.setState(rCS, prog.segMain);
state.IP = prog.offMain;
}
if(m_name=="start") {
proj.addCommand(new MachineStateInitialization);
proj.addCommand(new FindMain);
else
{
start_proc = proj.createFunction(0,"start");
/* Create initial procedure at program start address */
start_proc->procEntry = (uint32_t)state.IP;
}
// proj.addCommand(new ProcessFunction);
//proj.addCommand(new FollowControl());
/* The state info is for the first procedure */
start_proc->state = state;
/* 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 */
//proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
return true;
start_proc->FollowCtrl(proj.callGraph, &state);
/* This proc needs to be called to clean things up from SetupLibCheck() */
CleanupLibCheck();
}

View File

@ -1,49 +0,0 @@
#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;
}

View File

@ -1,39 +0,0 @@
#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

View File

@ -1,177 +0,0 @@
#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;
}

View File

@ -1,31 +0,0 @@
#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

View File

@ -1,22 +0,0 @@
#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;
}

View File

@ -1,24 +0,0 @@
#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

View File

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

View File

@ -1,19 +0,0 @@
#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

@ -1,54 +0,0 @@
#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

@ -1,34 +0,0 @@
#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,9 +3,6 @@
#include "msvc_fixes.h"
#include "project.h"
#include "scanner.h"
#include "ui/StructuredTextTarget.h"
#include <QtCore/QDebug>
//FunctionType *Function::getFunctionType() const
//{
@ -38,100 +35,6 @@ void JumpTable::pruneEntries(uint16_t cs)
}
void Function::callingConv(CConv::CC_Type v) {
type->setCallingConvention(v);
getFunctionType()->m_call_conv->calculateStackLayout(this);
}
static QString sizeToPtrName(int size)
{
switch(size)
{
case 1:
return "BYTE ptr" ;
case 2:
return "WORD ptr";
case 4:
return "DWORD ptr";
}
return "UNKOWN ptr";
}
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;
void Function::callingConv(CConv::Type v) {
m_call_conv=CConv::create(v);
}

View File

@ -13,6 +13,7 @@
#include "project.h"
#include <QtCore/QTextStream>
#include <QtCore/QDebug>
#include <boost/range.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm.hpp>
@ -29,12 +30,15 @@ using namespace boost::adaptors;
extern int strSize (const uint8_t *, char);
extern char *cChar(uint8_t c);
namespace
{
// Conditional operator symbols in C. Index by condOp enumeration type
static const char * const condOpSym[] = { " <= ", " < ", " == ", " != ", " > ", " >= ",
constexpr const char * condOpSym[] = { " <= ", " < ", " == ", " != ", " > ", " >= ",
" & ", " | ", " ^ ", " ~ ",
" + ", " - ", " * ", " / ",
" >> ", " << ", " % ", " && ", " || " };
/* Size of hl types */
constexpr const int hlSize[] = {2, 1, 1, 2, 2, 4, 4, 4, 2, 2, 1, 4, 4};
/* Local expression stack */
//typedef struct _EXP_STK {
@ -43,13 +47,13 @@ static const char * const condOpSym[] = { " <= ", " < ", " == ", " != ", " > ",
//} EXP_STK; - for local expression stack
/* Returns the integer i in C hexadecimal format */
static const char *hexStr (uint16_t i)
const char *hexStr (uint16_t i)
{
static char buf[10];
sprintf (buf, "%s%x", (i > 9) ? "0x" : "", i);
return (buf);
return buf;
}
}
/* Sets the du record for registers according to the du flag */
void ICODE::setRegDU (eReg regi, operDu du_in)
@ -124,7 +128,7 @@ GlobalVariable::GlobalVariable(int16_t segValue, int16_t off)
valid = true;
ident.idType = GLOB_VAR;
adr = opAdr(segValue, off);
auto i=Project::get()->getSymIdxByAdd(adr);
auto i=Project::get()->getSymIdxByAddr(adr);
if ( not Project::get()->validSymIdx(i) )
{
printf ("Error, glob var not found in symtab\n");
@ -136,7 +140,7 @@ GlobalVariable::GlobalVariable(int16_t segValue, int16_t off)
QString GlobalVariable::walkCondExpr(Function *, int *) const
{
if(valid)
return Project::get()->symtab[globIdx].name;
return Project::get()->symbolName(globIdx);
return "INVALID GlobalVariable";
}
@ -222,7 +226,7 @@ AstIdent *AstIdent::Long(LOCAL_ID *localId, opLoc sd, iICODE pIcode, hlFirst f,
{
AstIdent *newExp;
/* Check for long constant and save it as a constant expression */
if ((sd == SRC) and pIcode->ll()->srcIsImmed()) /* constant */
if ((sd == SRC) and pIcode->ll()->testFlags(I)) /* constant */
{
int value;
if (f == HIGH_FIRST)
@ -259,18 +263,18 @@ AstIdent *AstIdent::Other(eReg seg, eReg regi, int16_t off)
* TYPE_WORD_SIGN */
AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_)
{
int idx;
AstIdent *newExp=nullptr;
switch(retVal->type)
{
case TYPE_LONG_SIGN:
{
newExp = new AstIdent();
idx = locsym->newLongReg (TYPE_LONG_SIGN, retVal->longId(), ix_);
int idx = locsym->newLongReg (TYPE_LONG_SIGN, retVal->longId(), ix_);
newExp->ident.idType = LONG_VAR;
newExp->ident.idNode.longIdx = idx;
break;
}
case TYPE_WORD_UNSIGN:
case TYPE_WORD_SIGN:
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),WORD_REG,locsym);
break;
@ -313,7 +317,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
duIcode.setRegDU(rTMP, (operDu)eUSE);
}
else if ((sd == SRC) and ll_insn.srcIsImmed()) /* constant */
else if ((sd == SRC) and ll_insn.testFlags(I)) /* constant */
newExp = new Constant(ll_insn.src().getImm2(), 2);
else if (pm.regi == rUNDEF) /* global variable */
newExp = new GlobalVariable(pm.segValue, pm.off);
@ -345,7 +349,6 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
newExp = AstIdent::Other (pm.seg, pm.regi, pm.off);
/**** check long ops, indexed global var *****/
}
else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */
{
if ((pm.seg == rDS) and (pm.regi > INDEX_BP_DI)) /* dereference */
@ -368,7 +371,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
else
newExp = AstIdent::Other (pm.seg, pm.regi, 0);
}
return (newExp);
return newExp;
}
@ -377,32 +380,29 @@ condId LLInst::idType(opLoc sd) const
{
const LLOperand &pm((sd == SRC) ? src() : m_dst);
if ((sd == SRC) and srcIsImmed())
return (CONSTANT);
if ((sd == SRC) and testFlags(I))
return CONSTANT;
else if (pm.regi == 0)
return (GLOB_VAR);
return GLOB_VAR;
else if ( pm.isReg() )
return (REGISTER);
else if ((pm.seg == rSS) and (pm.regi == INDEX_BP))
return REGISTER;
else if ((pm.seg == rSS) and (pm.regi == INDEX_BP)) // TODO: this assumes BP-based function frames !
{
//TODO: which pm.seg/pm.regi pairs should produce PARAM/LOCAL_VAR ?
if (pm.off >= 0)
return (PARAM);
else
return (LOCAL_VAR);
return PARAM;
return LOCAL_VAR;
}
else
return (OTHER);
return OTHER;
}
/* Size of hl types */
int hlSize[] = {2, 1, 1, 2, 2, 4, 4, 4, 2, 2, 1, 4, 4};
int Expr::hlTypeSize(Function * pproc) const
{
if (this == nullptr)
return (2); /* for TYPE_UNKNOWN */
return 2; /* for TYPE_UNKNOWN */
fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type);
return 2; // CC: is this correct?
}
@ -437,11 +437,11 @@ int AstIdent::hlTypeSize(Function *pproc) const
case PARAM:
return (hlSize[pproc->args[ident.idNode.paramIdx].type]);
case STRING:
return (2);
return 2;
case LONG_VAR:
return (4);
return 4;
case OTHER:
return (2);
return 2;
default:
assert(false);
return -1;
@ -594,6 +594,10 @@ QString AstIdent::walkCondExpr(Function *pProc, int *numLoc) const
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"]";
else if (id->id.longGlb.regi == rBX)
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"][bx]";
else {
qCritical() << "AstIdent::walkCondExpr unhandled LONG_VAR in GLB_FRAME";
assert(false);
}
}
break;
case OTHER:
@ -666,9 +670,6 @@ QString UnaryOperator::walkCondExpr(Function *pProc, int *numLoc) const
/* Walks the conditional expression tree and returns the result on a string */
/* Changes the boolean conditional operator at the root of this expression */
void BinaryOperator::changeBoolOp (condOp newOp)
{
@ -799,9 +800,8 @@ Expr *BinaryOperator::insertSubTreeLongReg(Expr *_expr, int longIdx)
Expr *AstIdent::insertSubTreeLongReg(Expr *_expr, int longIdx)
{
if (ident.idNode.longIdx == longIdx)
{
return _expr;
}
return nullptr;
}
@ -817,7 +817,7 @@ Expr *BinaryOperator::clone() const
Expr *BinaryOperator::inverse() const
{
static condOp invCondOp[] = {GREATER, GREATER_EQUAL, NOT_EQUAL, EQUAL,
constexpr static condOp invCondOp[] = {GREATER, GREATER_EQUAL, NOT_EQUAL, EQUAL,
LESS_EQUAL, LESS, DUMMY,DUMMY,DUMMY,DUMMY,
DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY,
DUMMY, DBL_OR, DBL_AND};
@ -849,34 +849,18 @@ Expr *AstIdent::performLongRemoval(eReg regi, LOCAL_ID *locId)
{
eReg otherRegi; /* high or low part of long register */
if (ident.idType == LONG_VAR)
{
otherRegi = otherLongRegi (regi, ident.idNode.longIdx, locId);
delete this;
return new RegisterNode(locId->newByteWordReg(TYPE_WORD_SIGN,otherRegi),WORD_REG,locId);
}
if (ident.idType != LONG_VAR)
return this;
otherRegi = locId->getPairedRegisterAt(ident.idNode.longIdx,regi);
bool long_was_signed = locId->id_arr[ident.idNode.longIdx].isSigned();
delete this;
return new RegisterNode(locId->newByteWordReg(long_was_signed ? TYPE_WORD_SIGN : TYPE_WORD_UNSIGN,otherRegi),WORD_REG,locId);
}
eReg AstIdent::otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
{
ID *id = &locTbl->id_arr[idx];
if ((id->loc == REG_FRAME) and ((id->type == TYPE_LONG_SIGN) or
(id->type == TYPE_LONG_UNSIGN)))
{
if (id->longId().h() == regi)
return (id->longId().l());
else if (id->longId().l() == regi)
return (id->longId().h());
}
return rUNDEF; // Cristina: please check this!
}
QString Constant::walkCondExpr(Function *, int *) const
{
if (kte.kte < 1000)
return QString::number(kte.kte);
else
return "0x" + QString::number(kte.kte,16);
}
@ -885,11 +869,6 @@ int Constant::hlTypeSize(Function *) const
return kte.size;
}
hlType Constant::expType(Function *pproc) const
{
return TYPE_CONST;
}
QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
{
return pProc->writeCall(call.proc,*call.args, numLoc);
@ -897,10 +876,10 @@ QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
int FuncNode::hlTypeSize(Function *) const
{
return hlSize[call.proc->getReturnType()];
return hlSize[call.proc->retVal.type];
}
hlType FuncNode::expType(Function *) const
{
return call.proc->getReturnType();
return call.proc->retVal.type;
}

View File

@ -158,9 +158,9 @@ void Project::writeGlobSymTable()
else { /* first defined */
switch (sym.size) {
case 1: ostr<<"uint8_t\t"; break;
case 2: ostr<<"int\t"; break;
case 2: ostr<<"int16_t\t"; break;
case 4: if (sym.type == TYPE_PTR)
ostr<<"int\t*";
ostr<<"int32_t\t*";
else
ostr<<"char\t*";
break;
@ -226,8 +226,8 @@ void Function::codeGen (QIODevice &fs)
/* Write procedure/function header */
cCode.init();
if (getReturnType() != TYPE_UNKNOWN) /* Function */
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name);
if (flg & PROC_IS_FUNC) /* Function */
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(retVal.type)).arg(name);
else /* Procedure */
ostr << "\nvoid "+name+" (";
@ -282,7 +282,7 @@ void Function::codeGen (QIODevice &fs)
if (flg & PROC_ASM) /* generate assembler */
{
Disassembler ds(3);
ds.disassem(this->shared_from_this());
ds.disassem(this);
}
else /* generate C */
{

File diff suppressed because it is too large Load Diff

View File

@ -1,51 +0,0 @@
#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)
{
ostr << " * Untranslatable routine. Assembler provided.\n";
switch (getReturnType()) { // TODO: Functions return value in various regs
case TYPE_BYTE_SIGN:
case TYPE_BYTE_UNSIGN:
if (this->flg & PROC_IS_FUNC)
switch (this->retVal.type) { // TODO: Functions return value in various regs
case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN:
ostr << " * Return value in register al.\n";
break;
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
@ -250,11 +250,8 @@ void Function::writeProcComments(QTextStream &ostr)
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
ostr << " * Return value in registers dx:ax.\n";
break;
case TYPE_UNKNOWN:
// void return type
break;
default:
fprintf(stderr,"Unknown retval type %d",getReturnType());
fprintf(stderr,"Unknown retval type %d",this->retVal.type);
break;
} /* eos */
}

View File

@ -7,27 +7,29 @@
#include "msvc_fixes.h"
#include <boost/range/algorithm.hpp>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <list>
#include <cassert>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
namespace {
typedef std::list<int> nodeList; /* dfsLast index to the node */
#define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum))
/* there is a path on the DFST from a to b if the a was first visited in a
* dfs, and a was later visited than b when doing the last visit of each
* node. */
bool inline ancestor(BB *a,BB *b)
{
return (a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum);
}
/* Checks if the edge (p,s) is a back edge. If node s was visited first
/** Checks if the edge (p,s) is a back edge. If node s was visited first
* during the dfs traversal (ie. s has a smaller dfsFirst number) or s == p,
* then it is a backedge.
* Also incrementes the number of backedges entries to the header node. */
static bool isBackEdge (BB * p,BB * s)
bool isBackEdge (BB * p,BB * s)
{
if (p->dfsFirstNum >= s->dfsFirstNum)
{
@ -38,9 +40,9 @@ static bool isBackEdge (BB * p,BB * s)
}
/* Finds the common dominator of the current immediate dominator
/** Finds the common dominator of the current immediate dominator
* currImmDom and its predecessor's immediate dominator predImmDom */
static int commonDom (int currImmDom, int predImmDom, Function * pProc)
int commonDom (int currImmDom, int predImmDom, Function * pProc)
{
if (currImmDom == NO_DOM)
return (predImmDom);
@ -57,67 +59,44 @@ static int commonDom (int currImmDom, int predImmDom, Function * pProc)
}
return (currImmDom);
}
/* Finds the immediate dominator of each node in the graph pProc->cfg.
* Adapted version of the dominators algorithm by Hecht and Ullman; finds
* immediate dominators only.
* Note: graph should be reducible */
void Function::findImmedDom ()
{
BB * currNode;
for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
{
currNode = m_dfsLast[currIdx];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue;
for (BB * inedge : currNode->inEdges)
{
size_t predIdx = inedge->dfsLastNum;
if (predIdx < currIdx)
currNode->immedDom = commonDom (currNode->immedDom, predIdx, this);
}
}
}
/* Inserts the node n to the list l. */
static void insertList (nodeList &l, int n)
{
l.push_back(n);
}
/* Returns whether or not the node n (dfsLast numbering of a basic block)
* is on the list l. */
static bool inList (const nodeList &l, int n)
bool inList (const nodeList &l, int n)
{
return std::find(l.begin(),l.end(),n)!=l.end();
}
/* Frees space allocated by the list l. */
static void freeList (nodeList &l)
{
l.clear();
}
/* Returns whether the node n belongs to the queue list q. */
static bool inInt(BB * n, queue &q)
bool inInt(BB * n, queue &q)
{
return std::find(q.begin(),q.end(),n)!=q.end();
}
/** Recursive procedure to find nodes that belong to the interval (ie. nodes
* from G1). */
void findNodesInInt (queue &intNodes, int level, interval *Ii)
{
if (level == 1)
{
for(BB *en : Ii->nodes)
{
appendQueue(intNodes,en);
}
}
else
{
for(BB *en : Ii->nodes)
{
findNodesInInt(intNodes,level-1,en->correspInt);
}
}
}
/* Finds the follow of the endless loop headed at node head (if any).
* The follow node is the closest node to the loop. */
static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
{
head->loopFollow = MAX;
for( int loop_node : loopNodes)
{
for (TYPEADR_TYPE &typeaddr: pProc->m_dfsLast[loop_node]->edges)
for (const TYPEADR_TYPE &typeaddr: pProc->m_dfsLast[loop_node]->edges)
{
int succ = typeaddr.BBptr->dfsLastNum;
if ((not inList(loopNodes, succ)) and (succ < head->loopFollow))
@ -130,7 +109,7 @@ static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
//static void findNodesInLoop(BB * latchNode,BB * head,PPROC pProc,queue *intNodes)
/* Flags nodes that belong to the loop determined by (latchNode, head) and
* determines the type of loop. */
static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &intNodes)
void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &intNodes)
{
int i, headDfsNum, intNodeType;
nodeList loopNodes;
@ -141,7 +120,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
/* Flag nodes in loop headed by head (except header node) */
headDfsNum = head->dfsLastNum;
head->loopHead = headDfsNum;
insertList (loopNodes, headDfsNum);
loopNodes.push_back(headDfsNum);
for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++)
{
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
@ -150,14 +129,14 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
immedDom = pProc->m_dfsLast[i]->immedDom;
if (inList (loopNodes, immedDom) and inInt(pProc->m_dfsLast[i], intNodes))
{
insertList (loopNodes, i);
loopNodes.push_back(i);
if (pProc->m_dfsLast[i]->loopHead == NO_NODE)/*not in other loop*/
pProc->m_dfsLast[i]->loopHead = headDfsNum;
}
}
latchNode->loopHead = headDfsNum;
if (latchNode != head)
insertList (loopNodes, latchNode->dfsLastNum);
loopNodes.push_back(latchNode->dfsLastNum);
/* Determine type of loop and follow node */
intNodeType = head->nodeType;
@ -237,32 +216,79 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
findEndlessFollow (pProc, loopNodes, head);
}
freeList(loopNodes);
loopNodes.clear();
}
//static void findNodesInInt (queue **intNodes, int level, interval *Ii)
/* Recursive procedure to find nodes that belong to the interval (ie. nodes
* from G1). */
static void findNodesInInt (queue &intNodes, int level, interval *Ii)
/** \returns whether the BB indexed by s is a successor of the BB indexed by \arg h
* \note that h is a case node.
*/
bool successor (int s, int h, Function * pProc)
{
if (level == 1)
BB * header = pProc->m_dfsLast[h];
auto iter = std::find_if(header->edges.begin(),
header->edges.end(),
[s](const TYPEADR_TYPE &te)->bool{ return te.BBptr->dfsLastNum == s;});
return iter!=header->edges.end();
}
/** Recursive procedure to tag nodes that belong to the case described by
* the list l, head and tail (dfsLast index to first and exit node of the
* case). */
void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
{
int current; /* index to current node */
pBB->traversed = DFS_CASE;
current = pBB->dfsLastNum;
if ((current != tail) and (pBB->nodeType != MULTI_BRANCH) and (inList (l, pBB->immedDom)))
{
for(BB *en : Ii->nodes)
l.push_back(current);
pBB->caseHead = head;
for(TYPEADR_TYPE &edge : pBB->edges)
{
appendQueue(intNodes,en);
if (edge.BBptr->traversed != DFS_CASE)
tagNodesInCase (edge.BBptr, l, head, tail);
}
}
else
}
/** Flags all nodes in the list l as having follow node f, and deletes all
* nodes from the list. */
void flagNodes (nodeList &l, int f, Function * pProc)
{
for(int idx : l)
{
for(BB *en : Ii->nodes)
pProc->m_dfsLast[idx]->ifFollow = f;
}
l.clear();
}
} // end of anonymouse namespace
/** Finds the immediate dominator of each node in the graph pProc->cfg.
* Adapted version of the dominators algorithm by Hecht and Ullman; finds
* immediate dominators only.
* Note: graph should be reducible */
void Function::findImmedDom ()
{
BB * currNode;
for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
{
findNodesInInt(intNodes,level-1,en->correspInt);
currNode = m_dfsLast[currIdx];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue;
for (BB * inedge : currNode->inEdges)
{
size_t predIdx = inedge->dfsLastNum;
if (predIdx < currIdx)
currNode->immedDom = commonDom (currNode->immedDom, predIdx, this);
}
}
}
/* Algorithm for structuring loops */
/** Algorithm for structuring loops */
void Function::structLoops(derSeq *derivedG)
{
interval *Ii;
@ -278,8 +304,7 @@ void Function::structLoops(derSeq *derivedG)
for(auto & elem : *derivedG)
{
level++;
Ii = elem.Ii;
while (Ii) /* for all intervals Ii of Gi */
for (Ii = elem.Ii; Ii!=nullptr; Ii = Ii->next) /* for all intervals Ii of Gi */
{
latchNode = nullptr;
intNodes.clear();
@ -321,45 +346,6 @@ void Function::structLoops(derSeq *derivedG)
latchNode->flg |= IS_LATCH_NODE;
}
}
/* Next interval */
Ii = Ii->next;
}
/* Next derived sequence */
}
}
/* Returns whether the BB indexed by s is a successor of the BB indexed by
* h. Note that h is a case node. */
static bool successor (int s, int h, Function * pProc)
{
BB * header = pProc->m_dfsLast[h];
auto iter = std::find_if(header->edges.begin(),
header->edges.end(),
[s](const TYPEADR_TYPE &te)->bool{ return te.BBptr->dfsLastNum == s;});
return iter!=header->edges.end();
}
/* Recursive procedure to tag nodes that belong to the case described by
* the list l, head and tail (dfsLast index to first and exit node of the
* case). */
static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
{
int current; /* index to current node */
pBB->traversed = DFS_CASE;
current = pBB->dfsLastNum;
if ((current != tail) and (pBB->nodeType != MULTI_BRANCH) and (inList (l, pBB->immedDom)))
{
insertList (l, current);
pBB->caseHead = head;
for(TYPEADR_TYPE &edge : pBB->edges)
{
if (edge.BBptr->traversed != DFS_CASE)
tagNodesInCase (edge.BBptr, l, head, tail);
}
}
}
@ -387,9 +373,7 @@ void Function::structCases()
if ((not successor(j, i, this)) and (m_dfsLast[j]->immedDom == i))
{
if (exitNode == NO_NODE)
{
exitNode = j;
}
else if (m_dfsLast[exitNode]->inEdges.size() < m_dfsLast[j]->inEdges.size())
exitNode = j;
}
@ -398,7 +382,7 @@ void Function::structCases()
/* Tag nodes that belong to the case by recording the
* header field with caseHeader. */
insertList (caseNodes, i);
caseNodes.push_back(i);
m_dfsLast[i]->caseHead = i;
for(TYPEADR_TYPE &pb : caseHeader->edges)
{
@ -411,20 +395,6 @@ void Function::structCases()
}
}
/* Flags all nodes in the list l as having follow node f, and deletes all
* nodes from the list. */
static void flagNodes (nodeList &l, int f, Function * pProc)
{
nodeList::iterator p;
for(int idx : l)
{
pProc->m_dfsLast[idx]->ifFollow = f;
}
l.clear();
}
/* Structures if statements */
void Function::structIfs ()
{
@ -455,7 +425,7 @@ void Function::structIfs ()
{
if (m_dfsLast[desc]->immedDom == curr)
{
insertList (domDesc, desc);
domDesc.push_back(desc);
pbb = m_dfsLast[desc];
if ((pbb->inEdges.size() - pbb->numBackEdges) >= followInEdges)
{
@ -474,9 +444,9 @@ void Function::structIfs ()
flagNodes (unresolved, follow, this);
}
else
insertList (unresolved, curr);
unresolved.push_back(curr);
}
freeList (domDesc);
domDesc.clear();
}
}
bool Function::removeInEdge_Flag_and_ProcessLatch(BB *pbb,BB *a,BB *b)
@ -653,8 +623,7 @@ void Function::compoundCond()
}
}
/* Structuring algorithm to find the structures of the graph pProc->cfg */
/** Structuring algorithm to find the structures of the graph pProc->cfg */
void Function::structure(derSeq *derivedG)
{
/* Find immediate dominators of the graph */

View File

@ -22,6 +22,9 @@
using namespace boost;
using namespace boost::adaptors;
using namespace std;
namespace
{
struct ExpStack
{
Function *func;
@ -49,6 +52,57 @@ struct ExpStack
}
};
ExpStack g_exp_stk;
/** Returns a string with the source operand of Icode */
Expr *srcIdent (const LLInst &ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
{
const LLOperand * src_op = ll_insn.get(SRC);
if (src_op->isImmediate()) /* immediate operand ll_insn.testFlags(I)*/
{
//if (ll_insn.testFlags(B))
return new Constant(src_op->getImm2(), src_op->byteWidth());
}
// otherwise
return AstIdent::id (ll_insn, SRC, pProc, i, duIcode, du);
}
/** Returns the destination operand */
Expr *dstIdent (const LLInst & ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
{
Expr *n;
n = AstIdent::id (ll_insn, DST, pProc, i, duIcode, du);
/** Is it needed? (pIcode->ll()->flg) & NO_SRC_B **/
return (n);
}
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the expression exp given */
void forwardSubsLong (int longIdx, Expr *_exp, ICODE &picode, ICODE &ticode, int *numHlIcodes)
{
bool res;
if (_exp == nullptr) /* In case expression popped is NULL */
return;
/* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeLongReg (_exp, ticode.hlU()->asgn.m_rhs, longIdx);
if (res)
{
picode.invalidate();
(*numHlIcodes)--;
}
else
{
/* Try to insert it on lhs of ticode*/
res = Expr::insertSubTreeLongReg (_exp, ticode.hlU()->asgn.m_lhs, longIdx);
if (res)
{
picode.invalidate();
(*numHlIcodes)--;
}
}
}
} // end of anonymous namespace
/***************************************************************************
* Expression stack functions
**************************************************************************/
@ -92,8 +146,6 @@ bool ExpStack::empty()
return expStk.empty();
}
using namespace std;
ExpStack g_exp_stk;
/* Returns the index of the local variable or parameter at offset off, if it
* is in the stack frame provided. */
@ -104,28 +156,6 @@ size_t STKFRAME::getLocVar(int off)
}
/* Returns a string with the source operand of Icode */
static Expr *srcIdent (const LLInst &ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
{
const LLOperand * src_op = ll_insn.get(SRC);
if (src_op->isImmediate()) /* immediate operand ll_insn.testFlags(I)*/
{
//if (ll_insn.testFlags(B))
return new Constant(src_op->getImm2(), src_op->byteWidth());
}
// otherwise
return AstIdent::id (ll_insn, SRC, pProc, i, duIcode, du);
}
/* Returns the destination operand */
static Expr *dstIdent (const LLInst & ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
{
Expr *n;
n = AstIdent::id (ll_insn, DST, pProc, i, duIcode, du);
/** Is it needed? (pIcode->ll()->flg) & NO_SRC_B **/
return (n);
}
/* Eliminates all condition codes and generates new hlIcode instructions */
void Function::elimCondCodes ()
{
@ -322,12 +352,12 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
pbb->liveOut = in_liveOut;
/* Get return expression of function */
if (getReturnType()!=TYPE_UNKNOWN)
if (flg & PROC_IS_FUNC)
{
auto picode = pbb->rbegin(); /* icode of function return */
if (picode->hl()->opcode == HLI_RET)
{
picode->hlU()->expr(AstIdent::idID(&type->retVal, &localId, (++pbb->rbegin()).base()));
picode->hlU()->expr(AstIdent::idID(&retVal, &localId, (++pbb->rbegin()).base()));
picode->du.use = in_liveOut;
}
}
@ -354,7 +384,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
}
else /* library routine */
{
if ( (pcallee->getReturnType()!=TYPE_UNKNOWN) and /* returns a value */
if ( (pcallee->flg & PROC_IS_FUNC) and /* returns a value */
(pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any()
)
pbb->liveOut = pcallee->liveOut;
@ -364,7 +394,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() ))
{
switch (pcallee->getReturnType()) {
switch (pcallee->retVal.type) {
case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN:
ticode.du1.setDef(rAX).addDef(rDX);
@ -462,7 +492,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
* on optimized code. */
void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
{
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->getReturnType()!=TYPE_UNKNOWN)))
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->flg & PROC_IS_FUNC)))
return;
BB *tbb = this->edges[0].BBptr;
@ -563,7 +593,7 @@ void Function::genDU1 ()
}
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the rhs of picode. */
void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode, int &numHlIcodes) const
void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, ICODE &picode, ICODE &ticode, int &numHlIcodes) const
{
bool res;
UnaryOperator *lhs_unary;
@ -579,16 +609,16 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
return;
/* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.m_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)
{
picode->invalidate();
picode.invalidate();
numHlIcodes--;
}
else
{
/* Try to insert it on lhs of ticode*/
RegisterNode *op = dynamic_cast<RegisterNode *>(ticode->hlU()->asgn.m_lhs);
RegisterNode *op = dynamic_cast<RegisterNode *>(ticode.hlU()->asgn.m_lhs);
if(op)
{
eReg inserted = id_arr[lhs_reg->regiIdx].id.regi;
@ -599,44 +629,17 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
return;
}
}
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.m_lhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
res = Expr::insertSubTreeReg (ticode.hlU()->asgn.m_lhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
if (res)
{
picode->invalidate();
picode.invalidate();
numHlIcodes--;
}
}
}
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the expression exp given */
static void forwardSubsLong (int longIdx, Expr *_exp, iICODE picode, iICODE ticode, int *numHlIcodes)
{
bool res;
if (_exp == nullptr) /* In case expression popped is NULL */
return;
/* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.m_rhs, longIdx);
if (res)
{
picode->invalidate();
(*numHlIcodes)--;
}
else
{
/* Try to insert it on lhs of ticode*/
res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.m_lhs, longIdx);
if (res)
{
picode->invalidate();
(*numHlIcodes)--;
}
}
}
/* Returns whether the elements of the expression rhs are all x-clear from
/** Returns whether the elements of the expression rhs are all x-clear from
* instruction f up to instruction t. */
bool UnaryOperator::xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locs)
{
@ -672,12 +675,14 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
Expr *_exp;
bool res;
int size_of_arg=0;
Project &proj(*Project::get());
PROG &prog(Project::get()->prog);
/* if (numArgs == 0)
return; */
assert(pProc==g_exp_stk.func);
_exp = g_exp_stk.pop();
if (callee->flg & PROC_ISLIB) /* library function */
if (callee->isLibrary() ) /* library function */
{
if (callee->args.numArgs > 0)
{
@ -692,7 +697,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
}
else {
if(numArgs<callee->args.size()) {
if(proj.getLoaderMetadata().compiler_memory_model==eLarge) {
if(prog.addressingMode=='l') {
if((callee->args[numArgs].type==TYPE_STR) or (callee->args[numArgs].type==TYPE_PTR)) {
RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top());
AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top());
@ -730,7 +735,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
callee->args.adjustForArgType (numArgs, _exp->expType (pProc));
}
}
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), pProc);
res = picode->newStkArg (_exp, picode->ll()->getOpcode(), pProc);
/* Do not update the size of k if the expression was a segment register
* in a near call */
if (res == false)
@ -745,11 +750,11 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
/** Eliminates extraneous intermediate icode instructions when finding
* expressions. Generates new hlIcodes in the form of expression trees.
* For HLI_CALL hlIcodes, places the arguments in the argument list. */
void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode,bool isLong) const
void LOCAL_ID::processTargetIcode(ICODE &picode, int &numHlIcodes, ICODE &ticode,bool isLong) const
{
bool res;
HLTYPE &p_hl(*picode->hlU());
HLTYPE &t_hl(*ticode->hlU());
HLTYPE &p_hl(*picode.hlU());
HLTYPE &t_hl(*ticode.hlU());
AstIdent *lhs_ident = dynamic_cast<AstIdent *>(p_hl.asgn.lhs());
switch (t_hl.opcode)
@ -787,14 +792,14 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
}
if (res)
{
picode->invalidate();
picode.invalidate();
numHlIcodes--;
}
break;
case HLI_CALL: /* register arguments */
newRegArg ( picode, ticode);
picode->invalidate();
picode.invalidate();
numHlIcodes--;
break;
default:
@ -841,11 +846,11 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
while(k<cb)
{
_exp = g_exp_stk.pop();
if (pp->flg & PROC_ISLIB) /* library function */
if (pp->isLibrary() ) /* library function */
{
if (pp->args.numArgs > 0)
_exp = func->adjustActArgType(_exp, pp->args[numArgs].type);
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), func);
res = picode->newStkArg (_exp, picode->ll()->getOpcode(), func);
}
else /* user function */
{
@ -855,9 +860,10 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
{
fprintf(stderr,"Would try to adjustForArgType with null _exp\n");
}
else
pp->args.adjustForArgType (numArgs,_exp->expType (func));
}
res = picode->newStkArg (_exp,(llIcode)picode->ll()->getOpcode(), func);
res = picode->newStkArg (_exp, picode->ll()->getOpcode(), func);
}
if (res == false)
k += _exp->hlTypeSize (func);
@ -877,30 +883,29 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
bool res;
ID *_retVal; // function return value
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL
//Expr *lhs; // exp ptr for return value of a HLI_CALL
iICODE ticode; // Target icode
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL */
iICODE ticode; // Target icode */
HLTYPE *ti_hl=nullptr;
uint8_t regi;
numHlIcodes = 0;
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>());
for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++)
{
ICODE &_ic(*picode);
HLTYPE &_icHl(*picode->hlU());
HLTYPE &_icHl(*_ic.hlU());
numHlIcodes++;
if (picode->du1.getNumRegsDef() == 1) /* uint8_t/uint16_t regs */
if (_ic.du1.getNumRegsDef() == 1) /* uint8_t/uint16_t regs */
{
/* Check for only one use of this register. If this is
* the last definition of the register in this BB, check
* that it is not liveOut from this basic block */
if (picode->du1.numUses(0)==1)
if (_ic.du1.numUses(0)==1)
{
/* Check that this register is not liveOut, if it
* is the last definition of the register */
regi = picode->du1.regi[0];
regi = _ic.du1.regi[0];
/* Check if we can forward substitute this register */
switch (_icHl.opcode)
@ -909,16 +914,16 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
/* Replace rhs of current icode into target
* icode expression */
ticode = picode->du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
ticode = _ic.du1.idx[0].uses.front();
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET)))
continue;
if (_icHl.asgn.m_rhs->xClear (make_iterator_range(picode.base(),picode->du1.idx[0].uses[0]),
if (_icHl.asgn.m_rhs->xClear (make_iterator_range(picode.base(),_ic.du1.idx[0].uses[0]),
end(), locals))
{
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,false);
locals.processTargetIcode(_ic, numHlIcodes, *ticode,false);
}
break;
@ -927,9 +932,9 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
// pop X
// lab1:
// call F() <- somehow this is marked as user of POP ?
ticode = picode->du1.idx[0].uses.front();
ticode = _ic.du1.idx[0].uses.front();
ti_hl = ticode->hlU();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ti_hl->opcode != HLI_CALL) and
(ti_hl->opcode != HLI_RET)))
continue;
@ -937,7 +942,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
_exp = g_exp_stk.pop(); /* pop last exp pushed */
switch (ticode->hl()->opcode) {
case HLI_ASSIGN:
locals.forwardSubs(_icHl.expr(), _exp, picode.base(), ticode, numHlIcodes);
locals.forwardSubs(_icHl.expr(), _exp, _ic, *ticode, numHlIcodes);
break;
case HLI_JCOND: case HLI_PUSH: case HLI_RET:
@ -950,7 +955,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
&locals);
if (res)
{
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
}
}
@ -968,9 +973,9 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
break;
case HLI_CALL:
ticode = picode->du1.idx[0].uses.front();
ticode = _ic.du1.idx[0].uses.front();
ti_hl = ticode->hlU();
_retVal = &_icHl.call.proc->type->retVal;
_retVal = &_icHl.call.proc->retVal;
switch (ti_hl->opcode)
{
case HLI_ASSIGN:
@ -980,13 +985,13 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
if (not res)
Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals);
//TODO: HERE missing: 2 regs
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
break;
case HLI_PUSH: case HLI_RET:
ti_hl->expr( _icHl.call.toAst() );
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
break;
@ -995,13 +1000,13 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
res = Expr::insertSubTreeReg (ti_hl->exp.v, _exp, _retVal->id.regi, &locals);
if (res) /* was substituted */
{
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
}
else /* cannot substitute function */
{
auto lhs = AstIdent::idID(_retVal,&locals,picode.base());
picode->setAsgn(lhs, _exp);
_ic.setAsgn(lhs, _exp);
}
break;
default:
@ -1014,33 +1019,34 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
}
}
else if (picode->du1.getNumRegsDef() == 2) /* long regs */
else if (_ic.du1.getNumRegsDef() == 2) /* long regs */
{
/* Check for only one use of these registers */
if ((picode->du1.numUses(0) == 1) and (picode->du1.numUses(1) == 1))
if ((_ic.du1.numUses(0) == 1) and (_ic.du1.numUses(1) == 1))
{
regi = picode->du1.regi[0]; //TODO: verify that regi actually should be assigned this
regi = _ic.du1.regi[0]; //TODO: verify that regi actually should be assigned this
switch (_icHl.opcode)
{
case HLI_ASSIGN:
/* Replace rhs of current icode into target icode expression */
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0])
/* Replace rhs of current icode into target
* icode expression */
if (_ic.du1.idx[0].uses[0] == _ic.du1.idx[1].uses[0])
{
ticode = picode->du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
ticode = _ic.du1.idx[0].uses.front();
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET)))
continue;
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,true);
locals.processTargetIcode(_ic, numHlIcodes, *ticode,true);
}
break;
case HLI_POP:
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0])
if (_ic.du1.idx[0].uses[0] == _ic.du1.idx[1].uses[0])
{
ticode = picode->du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
ticode = _ic.du1.idx[0].uses.front();
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET)))
continue;
@ -1048,17 +1054,16 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
_exp = g_exp_stk.pop(); /* pop last exp pushed */
switch (ticode->hl()->opcode) {
case HLI_ASSIGN:
forwardSubsLong (static_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
_exp, picode.base(), ticode, &numHlIcodes);
forwardSubsLong (dynamic_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
_exp, _ic, *ticode, &numHlIcodes);
break;
case HLI_JCOND:
case HLI_PUSH:
case HLI_JCOND: case HLI_PUSH:
res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v,
dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx);
if (res)
{
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
}
break;
@ -1071,7 +1076,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
break;
case HLI_CALL: /* check for function return */
ticode = picode->du1.idx[0].uses.front();
ticode = _ic.du1.idx[0].uses.front();
switch (ticode->hl()->opcode)
{
case HLI_ASSIGN:
@ -1081,32 +1086,32 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
ticode,HIGH_FIRST, picode.base(),
eDEF, *(++iICODE(ticode))->ll()));
ticode->hlU()->asgn.m_rhs = _exp;
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
break;
case HLI_PUSH:
case HLI_RET:
ticode->hlU()->expr( _icHl.call.toAst() );
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
break;
case HLI_JCOND:
_exp = _icHl.call.toAst();
_retVal = &picode->hl()->call.proc->type->retVal;
_retVal = &_ic.hl()->call.proc->retVal;
res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v,
locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base()));
if (res) /* was substituted */
{
picode->invalidate();
_ic.invalidate();
numHlIcodes--;
}
else /* cannot substitute function */
{
auto lhs = locals.createId(_retVal,picode.base());
picode->setAsgn(lhs, _exp);
_ic.setAsgn(lhs, _exp);
}
break;
default:
@ -1127,8 +1132,8 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
{
g_exp_stk.processExpPush(numHlIcodes, *picode);
}
else if(picode->du1.getNumRegsDef()!=0)
printf("Num def %d\n",picode->du1.getNumRegsDef());
else if(_ic.du1.getNumRegsDef()!=0)
printf("Num def %d\n",_ic.du1.getNumRegsDef());
/* For HLI_CALL instructions that use arguments from the stack,
* pop them from the expression stack and place them on the
@ -1142,11 +1147,11 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
/* If we could not substitute the result of a function,
* assign it to the corresponding registers */
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 _ic.du1.used(0)) and (_ic.du1.getNumRegsDef() > 0))
{
_exp = new FuncNode(_icHl.call.proc, _icHl.call.args);
auto lhs = AstIdent::idID (&_icHl.call.proc->type->retVal, &locals, picode.base());
picode->setAsgn(lhs, _exp);
auto lhs = AstIdent::idID (&_icHl.call.proc->retVal, &locals, picode.base());
_ic.setAsgn(lhs, _exp);
}
}
}
@ -1182,6 +1187,7 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if(not _liveOut.any())
return;
}
flg |= PROC_IS_FUNC;
isAx = _liveOut.testReg(rAX);
isBx = _liveOut.testReg(rBX);
isCx = _liveOut.testReg(rCX);
@ -1217,55 +1223,53 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if (isAx and isDx) /* long or pointer */
{
type->setReturnType(TYPE_LONG_SIGN);
type->m_call_conv->calculateStackLayout(this);
retVal.type = TYPE_LONG_SIGN;
retVal.loc = REG_FRAME;
retVal.longId() = LONGID_TYPE(rDX,rAX);
/*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin());
localId.propLongId (rAX, rDX, "");
}
else if (isAx or isBx or isCx or isDx) /* uint16_t */
{
eReg selected_reg;
retVal.type = TYPE_WORD_SIGN;
retVal.loc = REG_FRAME;
if (isAx)
selected_reg = rAX;
retVal.id.regi = rAX;
else if (isBx)
selected_reg = rBX;
retVal.id.regi = rBX;
else if (isCx)
selected_reg = rCX;
retVal.id.regi = rCX;
else
selected_reg = rDX;
type->setReturnType(TYPE_WORD_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,selected_reg);
retVal.id.regi = rDX;
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,retVal.id.regi);
}
else if(isAL or isBL or isCL or isDL)
{
eReg selected_reg;
retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
if (isAL)
selected_reg = rAL;
retVal.id.regi = rAL;
else if (isBL)
selected_reg = rBL;
retVal.id.regi = rBL;
else if (isCL)
selected_reg = rCL;
retVal.id.regi = rCL;
else
selected_reg = rDL;
type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
retVal.id.regi = rDL;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
}
else if(isAH or isBH or isCH or isDH)
{
eReg selected_reg;
retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
if (isAH)
selected_reg = rAH;
retVal.id.regi = rAH;
else if (isBH)
selected_reg = rBH;
retVal.id.regi = rBH;
else if (isCH)
selected_reg = rCH;
retVal.id.regi = rCH;
else
selected_reg = rDH;
type->setReturnType(TYPE_BYTE_SIGN);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
retVal.id.regi = rDH;
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
}
}
}

View File

@ -14,10 +14,10 @@
#include <cstring>
#include <iostream>
#include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QCommandLineParser>
#include <QtCore/QFile>
#include "ui/DccMainWindow.h"
/* Global variables - extern to other modules */
extern QString asm1_name, asm2_name; /* Assembler output filenames */
@ -25,12 +25,11 @@ extern SYMTAB symtab; /* Global symbol table */
extern STATS stats; /* cfg statistics */
extern OPTION option; /* Command line options */
static char *initargs(int argc, char *argv[]);
static void displayTotalStats(void);
static void displayTotalStats();
/****************************************************************************
* main
***************************************************************************/
void setupOptions(QCoreApplication &app) {
void setupOptions(const QCoreApplication &app) {
//[-a1a2cmsi]
QCommandLineParser parser;
parser.setApplicationDescription("dcc");
@ -80,7 +79,7 @@ void setupOptions(QCoreApplication &app) {
option.Interact = false;
option.Calls = parser.isSet(boolOpts[2]);
option.filename = args.first();
option.CustomEntryPoint = parser.value(entryPointOption).toUInt(0,16);
option.CustomEntryPoint = parser.value(entryPointOption).toUInt(nullptr,16);
if(parser.isSet(targetFileOption))
asm1_name = asm2_name = parser.value(targetFileOption);
else if(option.asm1 or option.asm2) {
@ -91,36 +90,23 @@ void setupOptions(QCoreApplication &app) {
}
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::setApplicationVersion("0.1");
setupOptions(app);
Project *proj = Project::get();
/* 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
* each procedure.
*/
proj->create(option.filename);
Project::get()->create(option.filename);
DccFrontend fe(&app);
proj->addLoadCommands(option.filename);
proj->processAllCommands();
if(proj->m_error_state) {
proj->dumpAllErrors();
if(not Project::get()->load()) {
return -1;
}
if (option.verbose)
proj->prog.displayLoadInfo();
Project::get()->prog.displayLoadInfo();
if(false==fe.FrontEnd ())
return -1;
if(option.asm1)
@ -137,9 +123,9 @@ int main(int argc, char **argv)
* analysis, data flow etc. and outputs it to output file ready for
* re-compilation.
*/
BackEnd(proj->callGraph);
BackEnd(Project::get()->callGraph);
proj->callGraph->write();
Project::get()->callGraph->write();
if (option.Stats)
displayTotalStats();

View File

@ -2,20 +2,55 @@
#include "dcc.h"
#include "project.h"
struct DccImpl : public IDcc {
PtrFunction m_current_func;
ilFunction m_current_func;
// IDcc interface
public:
bool load(QString name)
void BaseInit()
{
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;
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)
{
PtrFunction p(Project::get()->findByName(v));
if(p!=nullptr)
m_current_func = p;
lFunction & funcs(Project::get()->functions());
for(auto iter=funcs.begin(),fin=funcs.end(); iter!=fin; ++iter) {
if(iter->name==v) {
m_current_func = iter;
return;
}
}
}
QDir installDir() {
return QDir(".");

View File

@ -18,7 +18,6 @@
#include <iomanip>
#include <stdio.h>
#include <string.h>
#include "src/ui/StructuredTextTarget.h"
// Note: for the time being, there is no interactive disassembler
// for unix
@ -87,12 +86,12 @@ bool callArg(uint16_t off, char *temp); /* Check for procedure name */
//static FILE *dis_g_fp;
static CIcodeRec pc;
static int cb, numIcode, allocIcode;
static int cb, j, numIcode, allocIcode;
static map<int,int> pl;
static uint32_t nextInst;
//static bool fImpure;
static bool fImpure;
//static int g_lab;
static PtrFunction pProc; /* Points to current proc struct */
static Function * pProc; /* Points to current proc struct */
struct POSSTACK_ENTRY
{
@ -113,7 +112,7 @@ static vector<POSSTACK_ENTRY> posStack; /* position stack */
void LLInst::findJumpTargets(CIcodeRec &_pc)
{
if (srcIsImmed() and not testFlags(JMP_ICODE) and isJmpInst())
if (testFlags(I) and not testFlags(JMP_ICODE) and isJmpInst())
{
/* Replace the immediate operand with an icode index */
iICODE labTgt=_pc.labelSrch(src().getImm2());
@ -139,7 +138,7 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
* pass == 3 generates output on file .b
****************************************************************************/
void Disassembler::disassem(PtrFunction ppProc)
void Disassembler::disassem(Function * ppProc)
{
@ -214,7 +213,364 @@ void Disassembler::disassem(PtrFunction ppProc)
****************************************************************************/
void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass)
{
assert(false);
PROG &prog(Project::get()->prog);
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";
}
}
@ -273,19 +629,19 @@ static QTextStream & strDst(QTextStream &os,uint32_t flg, const LLOperand &pm)
/****************************************************************************
* strSrc *
****************************************************************************/
//QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
//{
// if(false==skip_comma)
// os<<", ";
// if (srcIsImmed())
// os<<strHex(src().getImm2());
// else if (testFlags(IM_SRC)) /* level 2 */
// os<<"dx:ax";
// else
// formatRM(os, src());
QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
{
if(false==skip_comma)
os<<", ";
if (testFlags(I))
os<<strHex(src().getImm2());
else if (testFlags(IM_SRC)) /* level 2 */
os<<"dx:ax";
else
formatRM(os, src());
// return os;
//}
return os;
}
@ -304,7 +660,7 @@ static char *strHex(uint32_t d)
/****************************************************************************
* interactDis - interactive disassembler *
****************************************************************************/
void interactDis(const PtrFunction & initProc, int initIC)
void interactDis(Function * initProc, int initIC)
{
QString procname = "UNKNOWN";
if(initProc)
@ -412,230 +768,5 @@ 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

@ -11,8 +11,8 @@
#include "dcc.h"
static std::map<eErrorId,std::string> errorMessage =
{
static const std::map<eErrorId,std::string> errorMessage =
{
{INVALID_ARG ,"Invalid option -%c\n"},
{INVALID_OPCODE ,"Invalid instruction %02X at location %06lX\n"},
{INVALID_386OP ,"Don't understand 80386 instruction %02X at location %06lX\n"},
@ -31,14 +31,15 @@
{NOT_DEF_USE ,"%x: Def - use not supported. Def op = %d, use op = %d.\n"},
{REPEAT_FAIL ,"Failed to construct repeat..until() condition.\n"},
{WHILE_FAIL ,"Failed to construct while() condition.\n"},
};
};
/****************************************************************************
fatalError: displays error message and exits the program.
****************************************************************************/
void fatalError(eErrorId errId, ...)
{ va_list args;
//#ifdef __UNIX__ /* ultrix */
{
va_list args;
//#ifdef __UNIX__ /* ultrix */
#if 0
int errId;
@ -51,8 +52,10 @@ void fatalError(eErrorId errId, ...)
if (errId == USAGE)
fprintf(stderr,"Usage: dcc [-a1a2cmpsvVi][-o asmfile] DOS_executable\n");
else {
auto msg_iter = errorMessage.find(errId);
assert(msg_iter!=errorMessage.end());
fprintf(stderr, "dcc: ");
vfprintf(stderr, errorMessage[errId].c_str(), args);
vfprintf(stderr, msg_iter->second.c_str(), args);
}
va_end(args);
exit((int)errId);
@ -63,8 +66,9 @@ void fatalError(eErrorId errId, ...)
reportError: reports the warning/error and continues with the program.
****************************************************************************/
void reportError(eErrorId errId, ...)
{ va_list args;
//#ifdef __UNIX__ /* ultrix */
{
va_list args;
//#ifdef __UNIX__ /* ultrix */
#if 0
int errId;
@ -74,6 +78,8 @@ void reportError(eErrorId errId, ...)
va_start(args, errId);
#endif
fprintf(stderr, "dcc: ");
vfprintf(stderr, errorMessage[errId].c_str(), args);
auto msg_iter = errorMessage.find(errId);
assert(msg_iter!=errorMessage.end());
vfprintf(stderr, msg_iter->second.c_str(), args);
va_end(args);
}

View File

@ -15,6 +15,7 @@
using namespace std;
using namespace boost;
extern Project g_proj;
//static BB * rmJMP(Function * pProc, int marker, BB * pBB);
//static void mergeFallThrough(Function * pProc, BB * pBB);
//static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last);
@ -92,7 +93,7 @@ void Function::createCFG()
pBB->addOutEdge(elem);
hasCase = true;
}
else if (ll->srcIsImmed() and not ll->testFlags(NO_LABEL)) //TODO: WHY NO_LABEL TESTIT
else if ((ll->getFlag() & (I | NO_LABEL)) == I) //TODO: WHY NO_LABEL TESTIT
{
pBB = BB::Create(current_range, ONE_BRANCH, this);
pBB->addOutEdge(ll->src().getImm2());

View File

@ -332,7 +332,7 @@ void Function::highLevelGen()
lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
}
if(ll->getOpcode()==iPUSH) {
if(ll->srcIsImmed()) {
if(ll->testFlags(I)) {
lhs = new Constant(src_ll->opz,src_ll->byteWidth());
}
// lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
@ -399,8 +399,7 @@ void Function::highLevelGen()
}
break;
case iMOV:
pIcode->setAsgn(lhs, rhs);
case iMOV: pIcode->setAsgn(lhs, rhs);
break;
case iMUL:
@ -433,8 +432,7 @@ void Function::highLevelGen()
break;
case iRET:
case iRETF:
pIcode->setUnary(HLI_RET, nullptr);
case iRETF: pIcode->setUnary(HLI_RET, nullptr);
break;
case iSHL:
@ -463,8 +461,6 @@ void Function::highLevelGen()
rhs = new BinaryOperator(XOR,lhs, rhs);
pIcode->setAsgn(lhs, rhs);
break;
//TODO: default: // mostly to silence static analyzer warnings ?
// delete rhs;
}
}
@ -559,11 +555,10 @@ void HLTYPE::set(Expr *l, Expr *r)
asgn.m_lhs=l;
asgn.m_rhs=r;
}
/** 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
/* 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
* 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
{
const HlTypeSupport *p = get();

View File

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

View File

@ -124,10 +124,11 @@ void Function::findIdioms()
/* Check for library functions that return a long register.
* Propagate this result */
if (pIcode->ll()->src().proc.proc != nullptr)
if ( pIcode->ll()->src().proc.proc->flg & PROC_ISLIB )
if ((pIcode->ll()->src().proc.proc->flg & PROC_ISLIB) and
(pIcode->ll()->src().proc.proc->flg & PROC_IS_FUNC))
{
if ((pIcode->ll()->src().proc.proc->getReturnType()==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->getReturnType() == TYPE_LONG_UNSIGN))
if ((pIcode->ll()->src().proc.proc->retVal.type==TYPE_LONG_SIGN)
or (pIcode->ll()->src().proc.proc->retVal.type == TYPE_LONG_UNSIGN))
localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/);
}
@ -212,12 +213,12 @@ void Function::findIdioms()
/* Check if number of parameter bytes match their calling convention */
if ((flg & PROC_HLL) and (not args.empty()))
{
args.m_minOff += (flg & PROC_FAR ? 4 : 2);
delta = args.m_maxOff - args.m_minOff;
args.m_minOff += ((flg & PROC_FAR)!=0 ? 4 : 2);
delta = args.maxOff - args.m_minOff;
if (cbParam != delta)
{
cbParam = delta;
callingConv(CConv::UNKNOWN);
callingConv(CConv::eUnknown);
}
}
}
@ -237,7 +238,7 @@ void Function::bindIcodeOff()
for(ICODE &c : Icode) // TODO: use filtered here
{
LLInst *ll=c.ll();
if (ll->srcIsImmed() and ll->isJmpInst())
if (ll->testFlags(I) and ll->isJmpInst())
{
iICODE loc=Icode.labelSrch(ll->src().getImm2());
if (loc!=Icode.end())
@ -254,7 +255,7 @@ void Function::bindIcodeOff()
LLInst *ll=icode.ll();
if (not ll->isJmpInst())
continue;
if (ll->srcIsImmed())
if (ll->testFlags(I) )
{
uint32_t found;
if (not Icode.labelSrch(ll->src().getImm2(), found))

View File

@ -147,13 +147,13 @@ bool Idiom18::match(iICODE picode)
break;
case 1: /* register variable */
/* Check previous instruction for a MOV */
if ( (m_icodes[0]->ll()->src().regi == m_icodes[1]->ll()->m_dst.regi))
if ( m_icodes[0]->ll()->src().regi == m_icodes[1]->ll()->m_dst.regi)
{
return true;
}
break;
case 2: /* local */
if ((m_icodes[0]->ll()->src().off == m_icodes[1]->ll()->m_dst.off))
if (m_icodes[0]->ll()->src().off == m_icodes[1]->ll()->m_dst.off)
{
return true;
}

View File

@ -25,7 +25,7 @@ bool Idiom3::match(iICODE picode)
/* Match ADD SP, immed */
for(int i=0; i<2; ++i)
m_icodes[i] = picode++;
if ( m_icodes[1]->ll()->srcIsImmed() and m_icodes[1]->ll()->match(iADD,rSP))
if ( m_icodes[1]->ll()->testFlags(I) and m_icodes[1]->ll()->match(iADD,rSP))
{
m_param_count = m_icodes[1]->ll()->src().getImm2();
return true;
@ -39,9 +39,9 @@ bool Idiom3::match(iICODE picode)
}
int Idiom3::action()
{
if (m_icodes[0]->ll()->srcIsImmed())
if (m_icodes[0]->ll()->testFlags(I) )
{
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::eCdecl);
}
else
{
@ -97,9 +97,9 @@ bool Idiom17::match(iICODE picode)
}
int Idiom17::action()
{
if (m_icodes[0]->ll()->srcIsImmed())
if (m_icodes[0]->ll()->testFlags(I))
{
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::eCdecl);
for(size_t idx=1; idx<m_icodes.size(); ++idx)
{
m_icodes[idx]->invalidate();

View File

@ -48,7 +48,7 @@ bool Idiom2::match(iICODE pIcode)
iICODE nicode;
if(pIcode==m_func->Icode.begin()) // pIcode->loc_ip == 0
return false;
if ( pIcode->ll()->srcIsImmed() or (not pIcode->ll()->match(rSP,rBP)) )
if ( pIcode->ll()->testFlags(I) or (not pIcode->ll()->match(rSP,rBP)) )
return false;
if(distance(pIcode,m_end)<3)
return false;
@ -63,7 +63,7 @@ bool Idiom2::match(iICODE pIcode)
}
if(nicode == m_end)
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)) )
{
m_icodes.push_back(nicode++); // Matched POP BP
@ -71,7 +71,7 @@ bool Idiom2::match(iICODE pIcode)
/* Match RET(F) */
if ( nicode != m_end and
not (nicode->ll()->testFlags(I | TARGET | CASE)) and
nicode->ll()->matchAny({iRET,iRETF})
(nicode->ll()->match(iRET) or nicode->ll()->match(iRETF))
)
{
m_icodes.push_back(nicode); // Matched RET
@ -120,7 +120,7 @@ bool Idiom4::match(iICODE pIcode)
{
iICODE prev1 = --iICODE(pIcode);
/* Check for POP BP */
if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->srcIsImmed() )
if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->testFlags(I) )
m_icodes.push_back(prev1);
else if(prev1!=m_func->Icode.begin())
{
@ -131,7 +131,7 @@ bool Idiom4::match(iICODE pIcode)
}
/* Check for RET(F) immed */
if (pIcode->ll()->srcIsImmed() )
if (pIcode->ll()->testFlags(I) )
{
m_param_count = (int16_t)pIcode->ll()->src().getImm2();
return true;
@ -148,7 +148,7 @@ int Idiom4::action()
if(m_param_count)
{
m_func->cbParam = (int16_t)m_param_count;
m_func->callingConv(CConv::PASCAL);
m_func->callingConv(CConv::ePascal);
}
return 1;
}

View File

@ -63,7 +63,7 @@ bool Idiom1::match(iICODE picode)
m_icodes.clear();
m_min_off = 0;
/* PUSH BP as first instruction of procedure */
if ( (not picode->ll()->srcIsImmed()) and picode->ll()->src().regi == rBP)
if ( (not picode->ll()->testFlags(I)) and picode->ll()->src().regi == rBP)
{
m_icodes.push_back( picode++ ); // insert iPUSH
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()};
/* Check for regL */
m_regL = matched[0]->m_dst.regi;
if (not matched[0]->srcIsImmed() and ((m_regL == rAX) or (m_regL ==rBX)))
if (not matched[0]->testFlags(I) and ((m_regL == rAX) or (m_regL ==rBX)))
{
/* Check for XOR regH, regH */
if (matched[1]->match(iXOR) and not matched[1]->srcIsImmed())
if (matched[1]->match(iXOR) and not matched[1]->testFlags(I))
{
m_regH = matched[1]->m_dst.regi;
if (m_regH == matched[1]->src().getReg2())
@ -84,7 +84,7 @@ bool Idiom13::match(iICODE pIcode)
/* Check for regL */
regi = m_icodes[0]->ll()->m_dst.regi;
if (not m_icodes[0]->ll()->srcIsImmed() and (regi >= rAL) and (regi <= rBH))
if (not m_icodes[0]->ll()->testFlags(I) and (regi >= rAL) and (regi <= rBH))
{
/* Check for MOV regH, 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;
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
if ( m_icodes[1]->ll()->match(iRCR,I) and
(m_icodes[1]->ll()->src().getImm2() == 1))
return true;
@ -65,7 +65,7 @@ bool Idiom15::match(iICODE pIcode)
if(distance(pIcode,m_end)<2)
return false;
/* Match SHL reg, 1 */
if (not pIcode->ll()->srcIsImmed() or (pIcode->ll()->src().getImm2() != 1))
if (not pIcode->ll()->testFlags(I) or (pIcode->ll()->src().getImm2() != 1))
return false;
m_icodes.clear();
regi = pIcode->ll()->m_dst.regi;
@ -110,7 +110,7 @@ bool Idiom12::match(iICODE pIcode)
return false;
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[1]->ll()->match(iRCL,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
return true;
return false;
@ -150,7 +150,7 @@ bool Idiom9::match(iICODE pIcode)
return false;
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
if (m_icodes[1]->ll()->match(iRCR,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
return true;
return false;

View File

@ -26,7 +26,7 @@ bool Idiom21::match (iICODE picode)
m_icodes[0]=picode++;
m_icodes[1]=picode++;
if (not m_icodes[1]->ll()->srcIsImmed())
if (not m_icodes[1]->ll()->testFlags(I))
return false;
dst = &m_icodes[0]->ll()->m_dst;
@ -87,8 +87,8 @@ bool Idiom7::match(iICODE picode)
}
int Idiom7::action()
{
Expr *lhs = AstIdent::id (*m_icode->ll(), DST, m_func, m_icode, *m_icode, NONE);
Expr *lhs;
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->du.use.reset(); /* clear register used in iXOR */
m_icode->ll()->setFlags(I);
@ -117,7 +117,7 @@ bool Idiom10::match(iICODE pIcode)
m_icodes[0]=pIcode++;
m_icodes[1]=pIcode++;
/* Check OR reg, reg */
if (not m_icodes[0]->ll()->srcIsImmed() and
if (not m_icodes[0]->ll()->testFlags(I) and
m_icodes[0]->ll()->src().isReg() and
(m_icodes[0]->ll()->src().getReg2() == m_icodes[0]->ll()->m_dst.getReg2()))
if (m_icodes[1]->ll()->match(iJNE)) //.conditionalJump()

View File

@ -10,6 +10,11 @@
#include "msvc_fixes.h"
#include <cstring>
#include <QtCore/QDebug>
static const int LOCAL_ID_DELTA = 25;
static const int IDX_ARRAY_DELTA = 5;
bool LONGID_TYPE::srcDstRegMatch(iICODE a, iICODE b) const
{
@ -54,9 +59,14 @@ ID::ID(hlType t, const LONGGLB_TYPE &s) : type(t),illegal(false)
assert((t==TYPE_LONG_SIGN) or (t==TYPE_LONG_UNSIGN));
}
eReg ID::getPairedRegister(eReg first) const {
if (longId().h() == first)
return (longId().l());
else if (longId().l() == first)
return (longId().h());
return rUNDEF;
}
#define LOCAL_ID_DELTA 25
#define IDX_ARRAY_DELTA 5
/* Creates a new identifier node of type t and returns it.
* Arguments: locSym : local long symbol table
@ -65,8 +75,7 @@ ID::ID(hlType t, const LONGGLB_TYPE &s) : type(t),illegal(false)
* ix : index into icode array where this var is used */
void LOCAL_ID::newIdent(hlType t, frameType f)
{
ID newid(t,f);
id_arr.push_back(newid);
id_arr.emplace_back(t,f);
}
@ -74,8 +83,6 @@ void LOCAL_ID::newIdent(hlType t, frameType f)
* TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */
int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
{
int idx;
/* Check for entry in the table */
auto found=std::find_if(id_arr.begin(),id_arr.end(),[t,regi](ID &el)->bool {
return ((el.type == t) and (el.id.regi == regi));
@ -84,9 +91,8 @@ int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
return found-id_arr.begin();
/* Not in table, create new identifier */
newIdent (t, REG_FRAME);
idx = id_arr.size() - 1;
id_arr[idx].id.regi = regi;
return (idx);
id_arr.back().id.regi = regi;
return id_arr.size() - 1;
}
@ -100,10 +106,7 @@ void LOCAL_ID::flagByteWordId (int off)
{
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off](ID &en)->bool {
//if (((en.type == TYPE_WORD_SIGN) or (en.type == TYPE_BYTE_SIGN)) and
if ((en.typeBitsize()<=16) and
(en.id.bwId.off == off) and (en.id.bwId.regOff == 0))
return true;
return false;
return ((en.typeBitsize()<=16) and (en.id.bwId.off == off) and (en.id.bwId.regOff == 0));
});
if(found==id_arr.end())
{
@ -117,8 +120,6 @@ void LOCAL_ID::flagByteWordId (int off)
* TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */
int LOCAL_ID::newByteWordStk(hlType t, int off, uint8_t regOff)
{
int idx;
/* Check for entry in the table */
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off,regOff](ID &el)->bool {
if ((el.id.bwId.off == off) and (el.id.bwId.regOff == regOff))
@ -130,10 +131,10 @@ int LOCAL_ID::newByteWordStk(hlType t, int off, uint8_t regOff)
/* Not in table, create new identifier */
newIdent (t, STK_FRAME);
idx = id_arr.size() - 1;
id_arr[idx].id.bwId.regOff = regOff;
id_arr[idx].id.bwId.off = off;
return (idx);
ID &last_id(id_arr.back());
last_id.id.bwId.regOff = regOff;
last_id.id.bwId.off = off;
return id_arr.size()-1;
}
@ -181,7 +182,7 @@ int LOCAL_ID::newLongReg(hlType t, const LONGID_TYPE &longT, iICODE ix_)
for (idx = 0; idx < id_arr.size(); idx++)
{
ID &entry(id_arr[idx]);
if(not entry.isLong() or (entry.loc != REG_FRAME))
if(not entry.isLongRegisterPair())
continue;
if (/*(locSym->id[idx].type == t) and Not checking type */
(entry.longId().h() == regH) and
@ -189,23 +190,22 @@ int LOCAL_ID::newLongReg(hlType t, const LONGID_TYPE &longT, iICODE ix_)
{
/* Check for occurrence in the list */
if (entry.idx.inList(ix_))
return (idx);
return idx;
else
{
/* Insert icode index in list */
entry.idx.push_back(ix_);
return (idx);
return idx;
}
}
}
/* Not in the table, create new identifier */
id_arr.push_back(ID(t, LONGID_TYPE(regH,regL)));
id_arr.emplace_back(t, LONGID_TYPE(regH,regL));
id_arr.back().idx.push_back(ix_);
return (id_arr.size() - 1);
}
/** Returns an identifier conditional expression node of type TYPE_LONG or
* TYPE_WORD_SIGN */
/** \returns an identifier conditional expression node of type TYPE_LONG or TYPE_WORD_SIGN */
AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_)
{
return AstIdent::idID(retVal,this,ix_);
@ -229,8 +229,8 @@ int LOCAL_ID::newLongGlb(int16_t seg, int16_t offH, int16_t offL,hlType t)
}
printf("%d",t);
/* Not in the table, create new identifier */
id_arr.push_back(ID(t, LONGGLB_TYPE(seg,offH,offL)));
return (id_arr.size() - 1);
id_arr.emplace_back(t, LONGGLB_TYPE(seg,offH,offL));
return id_arr.size() - 1;
}
@ -240,10 +240,8 @@ int LOCAL_ID::newLongGlb(int16_t seg, int16_t offH, int16_t offL,hlType t)
* TYPE_LONG_(UN)SIGN and returns the index to this new entry. */
int LOCAL_ID::newLongIdx( int16_t seg, int16_t offH, int16_t offL,uint8_t regi, hlType t)
{
size_t idx;
/* Check for entry in the table */
for (idx = 0; idx < id_arr.size(); idx++)
for (size_t idx = 0; idx < id_arr.size(); idx++)
{
if (/*(locSym->id[idx].type == t) and Not checking type */
(id_arr[idx].id.longGlb.seg == seg) and
@ -254,9 +252,8 @@ int LOCAL_ID::newLongIdx( int16_t seg, int16_t offH, int16_t offL,uint8_t regi,
}
/* Not in the table, create new identifier */
id_arr.push_back(ID(t,LONGGLB_TYPE(seg,offH,offL,regi)));
idx = id_arr.size() - 1;
return (idx);
id_arr.emplace_back(t,LONGGLB_TYPE(seg,offH,offL,regi));
return id_arr.size() - 1;
}
@ -282,7 +279,7 @@ int LOCAL_ID::newLongStk(hlType t, int offH, int offL)
flagByteWordId (offL);
/* Create new identifier */
id_arr.push_back(ID(t,LONG_STKID_TYPE(offH,offL)));
id_arr.emplace_back(t,LONG_STKID_TYPE(offH,offL));
return (id_arr.size() - 1);
}
@ -334,7 +331,7 @@ int LOCAL_ID::newLong(opLoc sd, iICODE pIcode, hlFirst f, iICODE ix,operDu du, L
else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */
printf ("long not supported, idx and no off\n");
return (idx);
return idx;
}
@ -356,22 +353,22 @@ bool checkLongEq (LONG_STKID_TYPE longId, iICODE pIcode, int i, Function * pProc
pmLdst = &atOffset.m_dst;
pmHsrc = &pIcode->ll()->src();
pmLsrc = &atOffset.src();
// if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off))
// {
// asgn.lhs = AstIdent::LongIdx (i);
// if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off))
// {
// asgn.lhs = AstIdent::LongIdx (i);
// if ( not pIcode->ll()->testFlags(NO_SRC) )
// {
// asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset);
// }
// return true;
// }
// else if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
// {
// asgn.lhs = AstIdent::Long (&pProc->localId, DST, pIcode, HIGH_FIRST, pIcode,eDEF, atOffset);
// asgn.rhs = AstIdent::LongIdx (i);
// return true;
// }
// if ( not pIcode->ll()->testFlags(NO_SRC) )
// {
// asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset);
// }
// return true;
// }
// else if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
// {
// asgn.lhs = AstIdent::Long (&pProc->localId, DST, pIcode, HIGH_FIRST, pIcode,eDEF, atOffset);
// asgn.rhs = AstIdent::LongIdx (i);
// return true;
// }
if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
{
@ -431,30 +428,23 @@ bool checkLongRegEq (LONGID_TYPE longId, iICODE pIcode, int i,
return false;
}
/* Given an index into the local identifier table for a long register
* variable, determines whether regi is the high or low part, and returns
* the other part */
eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
eReg LOCAL_ID::getPairedRegisterAt(int idx,eReg regi) const
{
ID *id;
id = &locTbl->id_arr[idx];
if ((id->loc == REG_FRAME) and ((id->type == TYPE_LONG_SIGN) or
(id->type == TYPE_LONG_UNSIGN)))
eReg res=rUNDEF; // Cristina: please check this!
const ID *id = &id_arr[idx];
if (id->isLongRegisterPair())
{
if (id->longId().h() == regi)
return (id->longId().l());
else if (id->longId().l() == regi)
return (id->longId().h());
res = id->getPairedRegister(regi);
}
return rUNDEF; // Cristina: please check this!
qWarning() << "Cannot find paired register";
return res;
}
/**
* 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
* placed in the local identifier table, as these registers belong to a
* long register identifier. */

View File

@ -2,40 +2,30 @@
* dcc project procedure list builder
* (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
****************************************************************************/
#include "parser.h"
#include "dcc.h"
#include "project.h"
#include "CallGraph.h"
#include "msvc_fixes.h"
#include "chklib.h"
#include "FollowControlFlow.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h> /* For exit() */
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <deque>
#include <QMap>
#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
#include <inttypes.h>
#include <cstring>
#include <cstdlib> /* For exit() */
#include <cstdio>
#include <sstream>
#include <algorithm>
#include <deque>
using namespace std;
//static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
static void setBits(int16_t type, uint32_t start, uint32_t len);
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);
//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.
* Size includes delimiter. */
@ -46,158 +36,106 @@ int strSize (const uint8_t *sym, char delim)
const uint8_t *end_ptr=std::find(sym,sym+(prog.cbImage-(till_end)),delim);
return end_ptr-sym+1;
}
static std::vector<ICODE> rewrite_DIV(LLInst *ll, ICODE &_Icode)
ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
{
ICODE synth_mov = ICODE(); // MOV rTMP, reg
ICODE synth_mod = ICODE(); // MOD
/* MOV rTMP, reg */
synth_mov.type = LOW_LEVEL_ICODE;
synth_mov.ll()->set(iMOV,0,rTMP);
ICODE eIcode = ICODE();
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,0,rTMP);
if (ll->testFlags(B) )
{
synth_mov.ll()->setFlags( B );
synth_mov.ll()->replaceSrc(rAX);
eIcode.ll()->setFlags( B );
eIcode.ll()->replaceSrc(rAX);
}
else /* implicit dx:ax */
{
synth_mov.ll()->setFlags( IM_SRC );
synth_mov.setRegDU( rDX, eUSE);
eIcode.ll()->setFlags( IM_SRC );
eIcode.setRegDU( rDX, eUSE);
}
synth_mov.setRegDU( rAX, eUSE);
synth_mov.setRegDU( rTMP, eDEF);
synth_mov.ll()->setFlags( SYNTHETIC );
/* eIcode.ll()->label = Project::get()->SynthLab++; */
synth_mov.ll()->label = _Icode.ll()->label;
eIcode.setRegDU( rAX, eUSE);
eIcode.setRegDU( rTMP, eDEF);
eIcode.ll()->setFlags( SYNTHETIC );
/* eIcode.ll()->label = SynthLab++; */
eIcode.ll()->label = _Icode.ll()->label;
Icode.addIcode(&eIcode);
/* iDIV, iIDIV */
Icode.addIcode(&_Icode);
/* iMOD */
synth_mod.type = LOW_LEVEL_ICODE;
synth_mod.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
synth_mod.ll()->replaceSrc(_Icode.ll()->src());
synth_mod.du = _Icode.du;
synth_mod.ll()->label = Project::get()->SynthLab++;
return {
synth_mov,
_Icode,
synth_mod
};
eIcode = ICODE();
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
eIcode.ll()->replaceSrc(_Icode.ll()->src());
eIcode.du = _Icode.du;
eIcode.ll()->label = SynthLab++;
return Icode.addIcode(&eIcode);
}
static std::vector<ICODE> rewrite_XCHG(LLInst *ll,ICODE &_Icode)
ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
{
/* MOV rTMP, regDst */
ICODE mov_tmp_dst;
mov_tmp_dst.type = LOW_LEVEL_ICODE;
mov_tmp_dst.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
mov_tmp_dst.setRegDU( rTMP, eDEF);
if(mov_tmp_dst.ll()->src().getReg2())
ICODE eIcode;
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
eIcode.setRegDU( rTMP, eDEF);
if(eIcode.ll()->src().getReg2())
{
eReg srcreg=mov_tmp_dst.ll()->src().getReg2();
mov_tmp_dst.setRegDU( srcreg, eUSE);
eReg srcreg=eIcode.ll()->src().getReg2();
eIcode.setRegDU( srcreg, eUSE);
if((srcreg>=rAL) and (srcreg<=rBH))
mov_tmp_dst.ll()->setFlags( B );
eIcode.ll()->setFlags( B );
}
mov_tmp_dst.ll()->label = ll->label;
eIcode.ll()->label = ll->label;
Icode.addIcode(&eIcode);
/* MOV regDst, regSrc */
ICODE mov_dst_src = _Icode; // copy all XCHG things, but set opcode to iMOV and mark it as synthetic insn
mov_dst_src.ll()->set(iMOV,SYNTHETIC|ll->getFlag());
ll->set(iMOV,SYNTHETIC|ll->getFlag());
Icode.addIcode(&_Icode);
ll->setOpcode(iXCHG); /* for next case */
/* MOV regSrc, rTMP */
ICODE mov_src_tmp;
mov_src_tmp.type = LOW_LEVEL_ICODE;
mov_src_tmp.ll()->set(iMOV,SYNTHETIC);
mov_src_tmp.ll()->replaceDst(ll->src());
if(mov_src_tmp.ll()->m_dst.regi)
eIcode = ICODE();
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,SYNTHETIC);
eIcode.ll()->replaceDst(ll->src());
if(eIcode.ll()->m_dst.regi)
{
if((mov_src_tmp.ll()->m_dst.regi>=rAL) and (mov_src_tmp.ll()->m_dst.regi<=rBH))
mov_src_tmp.ll()->setFlags( B );
mov_src_tmp.setRegDU( mov_src_tmp.ll()->m_dst.regi, eDEF);
if((eIcode.ll()->m_dst.regi>=rAL) and (eIcode.ll()->m_dst.regi<=rBH))
eIcode.ll()->setFlags( B );
eIcode.setRegDU( eIcode.ll()->m_dst.regi, eDEF);
}
mov_src_tmp.ll()->replaceSrc(rTMP);
mov_src_tmp.setRegDU( rTMP, eUSE);
mov_src_tmp.ll()->label = Project::get()->SynthLab++;
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;
eIcode.ll()->replaceSrc(rTMP);
eIcode.setRegDU( rTMP, eUSE);
eIcode.ll()->label = SynthLab++;
return Icode.addIcode(&eIcode);
}
/** FollowCtrl - Given an initial procedure, state information and symbol table
* builds a list of procedures reachable from the initial procedure
* using a depth first search. */
void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
{
Project *project(Project::get());
PROG &prog(Project::get()->prog);
ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
SYM * psym;
uint32_t offset;
eErrorId err;
bool done = false;
if (func.name.contains("chkstk"))
SYMTAB &global_symbol_table(Project::get()->symtab);
if (name.contains("chkstk"))
{
// Danger! Dcc will likely fall over in this code.
// So we act as though we have done with this proc
// pProc->flg &= ~TERMINATES; // Not sure about this
done = true;
// And mark it as a library function, so structure() won't choke on it
func.flg |= PROC_ISLIB;
flg |= PROC_ISLIB;
return;
}
if (option.VeryVerbose)
{
qDebug() << "Parsing proc" << func.name << "at"<< QString::number(pstate->IP,16).toUpper();
qDebug() << "Parsing proc" << name << "at" << QString::number(pstate->IP,16).toUpper();
}
while (not done )
@ -207,37 +145,31 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
break;
LLInst *ll = _Icode.ll();
pstate->IP += (uint32_t)ll->numBytes;
setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes);
func.process_operands(_Icode,pstate);
process_operands(_Icode,pstate);
/* Keep track of interesting instruction flags in procedure */
func.flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP));
flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP));
/* Check if this instruction has already been parsed */
iICODE labLoc = func.Icode.labelSrch(ll->label);
if (func.Icode.end()!=labLoc)
iICODE labLoc = Icode.labelSrch(ll->label);
if (Icode.end()!=labLoc)
{ /* Synthetic jump */
_Icode.type = LOW_LEVEL_ICODE;
ll->set(iJMP,I | SYNTHETIC | NO_OPS);
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
ll->label = Project::get()->SynthLab++;
ll->label = SynthLab++;
}
/* Copy Icode to Proc */
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV)) {
std::vector<ICODE> translated = rewrite_DIV(ll,_Icode);
for(const ICODE &ic : translated)
pIcode = func.Icode.addIcode(&ic);
}
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);
}
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV))
pIcode = translate_DIV(ll, _Icode);
else if (_Icode.ll()->getOpcode() == iXCHG)
pIcode = translate_XCHG(ll, _Icode);
else
pIcode = Icode.addIcode(&_Icode);
switch (ll->getOpcode()) {
/*** Conditional jumps ***/
@ -249,8 +181,9 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
case iJCXZ:
{
STATE StCopy;
int ip = func.Icode.size()-1; /* Index of this jump */
ICODE &prev(*(++func.Icode.rbegin())); /* Previous icode */
uint32_t lastIp = pstate->IP - 2;
int ip = Icode.size()-1; /* Index of this jump */
ICODE &prev(*(++Icode.rbegin())); /* Previous icode */
bool fBranch = false;
pstate->JCond.regi = 0;
@ -258,40 +191,41 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
/* This sets up range check for indexed JMPs hopefully
* Handles JA/JAE for fall through and JB/JBE on branch
*/
if (ip > 0 and prev.ll()->match(iCMP,I) )
if (ip > 0 and prev.ll()->getOpcode() == iCMP and (prev.ll()->testFlags(I)))
{
pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2();
if (ll->match(iJA) or ll->match(iJBE) )
pstate->JCond.immed++;
if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA)
pstate->JCond.regi = prev.ll()->m_dst.regi;
fBranch = (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
fBranch = (bool) (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
}
StCopy = *pstate;
//printf("From %X condJump to %X\n", lastIp, pstate->IP);
/* Straight line code */
project->addCommand(func.shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ?
this->FollowCtrl (pcallGraph, &StCopy); // recurrent ?
if (fBranch) /* Do branching code */
{
pstate->JCond.regi = prev.ll()->m_dst.regi;
}
/* Next icode. Note: not the same as GetLastIcode() because of the call to FollowCtrl() */
pIcode = func.Icode.GetIcode(ip);
/* do the jump path */
done = process_JMP(func.shared_from_this(),*pIcode, pstate, pcallGraph);
break;
}
/* Next icode. Note: not the same as GetLastIcode() because of the call
to FollowCtrl() */
pIcode = Icode.GetIcode(ip);
} /* Fall through to do the jump path */
/*** Jumps ***/
case iJMP:
case iJMPF: /* Returns true if we've run into a loop */
done = process_JMP (func.shared_from_this(),*pIcode, pstate, pcallGraph);
done = process_JMP (*pIcode, pstate, pcallGraph);
break;
/*** Calls ***/
case iCALL:
case iCALLF:
done = process_CALL(func.shared_from_this(),*pIcode, pcallGraph, pstate);
done = process_CALL (*pIcode, pcallGraph, pstate);
pstate->kill(rBX);
pstate->kill(rCX);
break;
@ -299,17 +233,46 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
/*** Returns ***/
case iRET:
case iRETF:
func.flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
func.flg &= ~TERMINATES;
done = true;
break;
this->flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
/* Fall through */
case iIRET:
func.flg &= ~TERMINATES;
this->flg &= ~TERMINATES;
done = true;
break;
case iINT:
done = resolveOSServices(ll, pstate);
if (ll->src().getImm2() == 0x21 and pstate->f[rAH])
{
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)
pIcode->ll()->setFlags(TERMINATES);
break;
@ -317,10 +280,16 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
case iMOV:
process_MOV(*pIcode->ll(), pstate);
break;
/* case iXCHG:
process_MOV (pIcode, pstate);
break; **** HERE ***/
case iSHL:
if (pstate->JCond.regi == ll->m_dst.regi)
{
if (ll->srcIsImmed() and ll->src().getImm2() == 1)
if ((ll->testFlags(I)) and ll->src().getImm2() == 1)
pstate->JCond.immed *= 2;
else
pstate->JCond.regi = 0;
@ -337,7 +306,7 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
/* and (Icode.ll()->flg & SEG_IMMED) */ )
{
offset = LH(&prog.image()[psym->label]);
pstate->setState( (ll->getOpcode() == iLDS)? rDS : rES,
pstate->setState( (ll->getOpcode() == iLDS)? rDS: rES,
LH(&prog.image()[psym->label + 2]));
pstate->setState( ll->m_dst.regi, (int16_t)offset);
psym->type = TYPE_PTR;
@ -347,12 +316,12 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
}
if (err) {
func.flg &= ~TERMINATES;
this->flg &= ~TERMINATES;
if (err == INVALID_386OP or err == INVALID_OPCODE)
{
fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label);
func.flg |= PROC_BADINST;
this->flg |= PROC_BADINST;
}
else if (err == IP_OUT_OF_RANGE)
fatalError (err, _Icode.ll()->label);
@ -376,7 +345,34 @@ void Function::extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &ta
table.finish = table.start + 2;
}
static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
/* process_JMP - Handles JMPs, returns true if we should end recursion */
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);
// mov cx,NUM_CASES
@ -393,9 +389,9 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
// jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(func->Icode.size()<8)
if(Icode.size()<8)
return false;
if(&func->Icode.back()!=&pIcode) // not the last insn in the list skip it
if(&Icode.back()!=&pIcode) // not the last insn in the list skip it
return false;
if(pIcode.ll()->src().regi != INDEX_BX) {
return false;
@ -403,7 +399,7 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
// find address-wise predecessors of the icode
std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : func->Icode) {
for(ICODE & ic : Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic;
}
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -416,11 +412,11 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
// pattern starts at the last jmp
ICODE *load_num_cases = matched[0];
ICODE *load_jump_table_addr = matched[1];
// ICODE *read_case_entry_insn = matched[2];
// ICODE *cmp_case_val_insn = matched[3];
// ICODE *exit_loop_insn = matched[4];
// ICODE *add_bx_insn = matched[5];
// ICODE *loop_insn = matched[6];
ICODE *read_case_entry_insn = matched[2];
ICODE *cmp_case_val_insn = matched[3];
ICODE *exit_loop_insn = matched[4];
ICODE *add_bx_insn = matched[5];
ICODE *loop_insn = matched[6];
ICODE *default_jmp = matched[7];
ICODE *last_jmp = matched[8];
for(int i=0; i<8; ++i) {
@ -453,12 +449,16 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
iICODE last_current_insn = (++Icode.rbegin()).base();
FollowCtrl (pcallGraph, &StCopy);
++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;
}
static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
{
PROG &prog(Project::get()->prog);
// mov cx,NUM_CASES
@ -479,9 +479,9 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
// jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(func->Icode.size()<12)
if(Icode.size()<12)
return false;
if(&func->Icode.back() != &pIcode) // not the last insn in the list skip it
if(&Icode.back() != &pIcode) // not the last insn in the list skip it
return false;
if(pIcode.ll()->src().regi != INDEX_BX) {
return false;
@ -489,7 +489,7 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
// find address-wise predecessors of the icode
std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : func->Icode) {
for(ICODE & ic : Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic;
}
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -535,19 +535,54 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
iICODE last_current_insn = (++Icode.rbegin()).base();
FollowCtrl (pcallGraph, &StCopy);
++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;
}
/* Look for switch() stmt. idiom of the form
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *pstate) {
const static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
uint32_t seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
{
PROG &prog(Project::get()->prog);
static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
ICODE _Icode;
uint32_t lastIp = pstate->IP - 1;
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();
//printf("From seg:%04X JMP(F) to %X\n", lastIp, pstate->IP);
if (pstate->IP == 0xFFFF0)
{
/* Nasty (wrong) trick use to reset, consider it as terminating */
pIcode.ll()->setFlags(TERMINATES);
pstate->setState( rCS, 0);
pstate->IP = 0;
}
int64_t i = pIcode.ll()->src().getImm2();
if (i < 0)
{
exit(1);
}
/* Return true if jump target is already parsed */
return Icode.alreadyDecoded(i);
}
/* We've got an indirect JMP - look for switch() stmt. idiom of the form
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
/* Ensure we have a uint16_t offset & valid seg */
if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and
@ -557,9 +592,8 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
pIcode.ll()->src().regi == INDEX_BX))
{
uint32_t offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
uint32_t endTable;
uint32_t i;
offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
/* Firstly look for a leading range check of the form:-
* CMP {BX | SI | DI}, immed
* JA | JAE | JB | JBE
@ -580,10 +614,10 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
/* Now do some heuristic pruning. Look for ptrs. into the table
* and for addresses that don't appear to point to valid code.
*/
uint32_t cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
for (i = offTable; i < endTable; i += 2)
{
uint32_t target = cs + LH(&prog.image()[i]);
target = cs + LH(&prog.image()[i]);
if (target < endTable and target >= offTable)
endTable = target;
else if (target >= (uint32_t)prog.cbImage)
@ -592,10 +626,10 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
for (i = offTable; i < endTable; i += 2)
{
uint32_t target = cs + LH(&prog.image()[i]);
target = cs + LH(&prog.image()[i]);
/* Be wary of 00 00 as code - it's probably data */
ICODE _Icode;
if (not (prog.image()[target] or prog.image()[target+1]) or scan(target, _Icode)!=NO_ERR)
if (not (prog.image()[target] or prog.image()[target+1]) or
scan(target, _Icode))
endTable = i;
}
@ -611,56 +645,37 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
setBits(BM_DATA, offTable, endTable - offTable);
pIcode.ll()->setFlags(SWITCH);
//pIcode.ll()->caseTbl2.numEntries = (endTable - offTable) / 2;
uint32_t k;
for (i = offTable, k = 0; i < endTable; i += 2)
{
StCopy = *pstate;
StCopy.IP = cs + LH(&prog.image()[i]);
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,k++));
}
return true;
}
}
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);
iICODE last_current_insn = (++Icode.rbegin()).base();
//ip = Icode.size();
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);
}
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 if jump target is already parsed */
return func->Icode.alreadyDecoded(i);
}
/* We've got an indirect JMP */
if(decodeIndirectJMP0(func,pIcode,pstate)) {
return true;
}
if(decodeIndirectJMP(func,pIcode,pstate)) {
}
if(decodeIndirectJMP(pIcode,pstate,pcallGraph)) {
return true;
}
if(decodeIndirectJMP2(func,pIcode,pstate)) {
if(decodeIndirectJMP2(pIcode,pstate,pcallGraph)) {
return true;
}
/* Can't do anything with this jump */
func->flg |= PROC_IJMP;
func->flg &= ~TERMINATES;
// TODO: consider adding a new user-interactive command ResolveControlFlowFailure ?
interactDis(func, func->Icode.size()-1);
flg |= PROC_IJMP;
flg &= ~TERMINATES;
interactDis(this, this->Icode.size()-1);
return true;
}
@ -674,16 +689,17 @@ static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, C
* programmer expected it to come back - otherwise surely a JMP would
* have been used. */
bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
{
Project &project(*Project::get());
PROG &prog(Project::get()->prog);
ICODE &last_insn(func->Icode.back());
ICODE &last_insn(Icode.back());
STATE localState; /* Local copy of the machine state */
uint32_t lastIp = pstate->IP - 2;
uint32_t off;
/* For Indirect Calls, find the function address */
bool indirect = false;
//pIcode.ll()->immed.proc.proc=fakeproc;
if ( not pIcode.ll()->srcIsImmed() )
if ( not pIcode.ll()->testFlags(I) )
{
/* Not immediate, i.e. indirect call */
@ -728,30 +744,30 @@ bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGrap
if (pIcode.ll()->getOpcode() == iCALLF)
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4);
else
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)pstate->r[rCS] << 4);
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)state.r[rCS] << 4);
pIcode.ll()->replaceSrc(LLOperand::CreateImm2( tgtAddr ) );
pIcode.ll()->setFlags(I);
indirect = true;
}
/* Process CALL. Function address is located in pIcode.ll()->immed.op */
if (pIcode.ll()->srcIsImmed())
if (pIcode.ll()->testFlags(I))
{
/* Search procedure list for one with appropriate entry point */
PtrFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
ilFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
/* Create a new procedure node and save copy of the state */
if ( iter == nullptr )
if ( not Project::get()->valid(iter) )
{
iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()});
iter = Project::get()->createFunction(0,"");
Function &x(*iter);
if(project.m_pattern_locator)
project.m_pattern_locator->LibCheck(x);
x.procEntry = pIcode.ll()->src().getImm2();
LibCheck(x);
if (x.flg & PROC_ISLIB)
{
/* A library function. No need to do any more to it */
pcallGraph->insertCallGraph (func, iter);
pcallGraph->insertCallGraph (this, iter);
//iter = (++pProcList.rbegin()).base();
last_insn.ll()->src().proc.proc = &x;
return false;
@ -767,21 +783,32 @@ bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGrap
x.depth = x.depth + 1;
x.flg |= TERMINATES;
/* Save machine state in localState, load up IP and CS.*/
localState = *pstate;
pstate->IP = pIcode.ll()->src().getImm2();
if (pIcode.ll()->getOpcode() == iCALLF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
x.state = *pstate;
/* Insert new procedure in call graph */
pcallGraph->insertCallGraph (func, iter);
- pcallGraph->insertCallGraph (this, iter);
//printf("From %X CALL to %X\n", lastIp, pstate->IP);
/* Process new procedure */
Project::get()->addCommand(iter,new FollowControlFlow(*pstate));
x.FollowCtrl (pcallGraph, 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
Project::get()->callGraph->insertCallGraph (func, iter);
Project::get()->callGraph->insertCallGraph (this, iter);
last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc
@ -800,7 +827,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
uint8_t srcReg = ll.src().regi;
if (dstReg > 0 and dstReg < INDEX_BX_SI)
{
if (ll.srcIsImmed())
if (ll.testFlags(I))
pstate->setState( dstReg, (int16_t)ll.src().getImm2());
else if (srcReg == 0) /* direct memory offset */
{
@ -857,7 +884,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]);
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);
}
psym->duVal.setFlags(eDuVal::DEF);
@ -905,8 +932,8 @@ void STKFRAME::updateFrameOff ( int16_t off, int _size, uint16_t duFlag)
}
/* Save maximum argument offset */
if ((uint32_t)this->m_maxOff < (off + (uint32_t)_size))
this->m_maxOff = off + (int16_t)_size;
if ((uint32_t)this->maxOff < (off + (uint32_t)_size))
this->maxOff = off + (int16_t)_size;
}
@ -1027,9 +1054,8 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
{
if (pm->regi == INDEX_BP) /* indexed on bp */
{
if (pm->off >= 2) {
if (pm->off >= 2)
pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE);
}
else if (pm->off < 0)
pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
}
@ -1062,7 +1088,7 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
}
/* Use of register */
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I))))
pIcode.du.use.addReg(pm->regi);
}
@ -1111,7 +1137,7 @@ static void def (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
}
}
/* Definition of register */
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I))))
{
assert(not pIcode.ll()->match(iPUSH));
pIcode.du1.addDef(pm->regi);
@ -1148,7 +1174,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
int sseg = (ll_ins.src().seg)? ll_ins.src().seg: rDS;
int cb = pIcode.ll()->testFlags(B) ? 1: 2;
//x86_op_t *im= pIcode.insn.x86_get_imm();
bool Imm = (pIcode.ll()->srcIsImmed());
bool Imm = (pIcode.ll()->testFlags(I));
switch (pIcode.ll()->getOpcode()) {
case iAND: case iOR: case iXOR:
@ -1167,7 +1193,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
case iXCHG:
/* This instruction is replaced by 3 instructions, only need
* to define the src operand and use the destination operand
* in the mean time.*/
* in the mean time. */
use(SRC, pIcode, this, pstate, cb);
def(DST, pIcode, this, pstate, cb);
break;
@ -1265,9 +1291,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
use(SRC, pIcode, this, pstate, cb);
break;
case iLOOP:
case iLOOPE:
case iLOOPNE:
case iLOOP: case iLOOPE: case iLOOPNE:
pIcode.du.def.addReg(rCX);
pIcode.du1.addDef(rCX);
case iJCXZ:
@ -1322,8 +1346,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
pIcode.du.use.addReg(rDX).addReg(sseg);
break;
case iIN:
case iOUT:
case iIN: case iOUT:
def(DST, pIcode, this, pstate, cb);
if (not Imm)
{

View File

@ -1,7 +0,0 @@
#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,6 +14,7 @@
#include <cstring>
#include <cassert>
extern Project g_proj;
/* Static indentation buffer */
static constexpr int indSize=81; /* size of indentation buffer; max 20 */
static char indentBuf[indSize] =
@ -27,7 +28,7 @@ const char *indentStr(int indLevel) // Indentation according to the depth of the
/* Inserts an outEdge at the current callGraph pointer if the newProc does
* not exist. */
void CALL_GRAPH::insertArc (PtrFunction newProc)
void CALL_GRAPH::insertArc (ilFunction newProc)
{
@ -43,7 +44,7 @@ void CALL_GRAPH::insertArc (PtrFunction newProc)
/* Inserts a (caller, callee) arc in the call graph tree. */
bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee)
bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
{
if (proc == caller)
{
@ -56,10 +57,10 @@ bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee)
return false;
}
//bool CALL_GRAPH::insertCallGraph(PtrFunction &caller, PtrFunction &callee)
//{
// return insertCallGraph(caller,callee);
//}
bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee)
{
return insertCallGraph(Project::get()->funcIter(caller),callee);
}
/* Displays the current node of the call graph, and invokes recursively on
@ -87,7 +88,7 @@ void CALL_GRAPH::write()
/* Updates the argument table by including the register(s) (ie. lhs of
* picode) and the actual expression (ie. rhs of picode).
* Note: register(s) are only included once in the table. */
void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
void LOCAL_ID::newRegArg(ICODE &picode, ICODE &ticode) const
{
AstIdent *lhs;
STKFRAME * call_args_stackframe, *target_stackframe;
@ -100,13 +101,13 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
eReg regH; /* Registers involved in arguments */
/* Flag ticode as having register arguments */
tproc = ticode->hl()->call.proc;
tproc = ticode.hl()->call.proc;
tproc->flg |= REG_ARGS;
/* Get registers and index into target procedure's local list */
call_args_stackframe = ticode->hl()->call.args;
call_args_stackframe = ticode.hl()->call.args;
target_stackframe = &tproc->args;
lhs = dynamic_cast<AstIdent *>(picode->hl()->asgn.lhs());
lhs = dynamic_cast<AstIdent *>(picode.hl()->asgn.lhs());
RegisterNode *lhs_reg = dynamic_cast<RegisterNode *>(lhs);
assert(lhs);
type = lhs->ident.type();
@ -187,13 +188,13 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
/* Do ps (actual arguments) */
STKSYM newsym;
newsym.setArgName(call_args_stackframe->size());
newsym.actual = picode->hl()->asgn.m_rhs;
newsym.actual = picode.hl()->asgn.m_rhs;
newsym.regs = lhs;
/* Mask off high and low register(s) in picode */
switch (type) {
case REGISTER:
id = &id_arr[lhs_reg->regiIdx];
picode->du.def.clrReg(id->id.regi);
picode.du.def.clrReg(id->id.regi);
if (id->id.regi < rAL)
newsym.type = TYPE_WORD_SIGN;
else
@ -201,8 +202,8 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
break;
case LONG_VAR:
id = &id_arr[lhs->ident.idNode.longIdx];
picode->du.def.clrReg(id->longId().h());
picode->du.def.clrReg(id->longId().l());
picode.du.def.clrReg(id->longId().h());
picode.du.def.clrReg(id->longId().l());
newsym.type = TYPE_LONG_SIGN;
break;
default:

View File

@ -1,37 +1,27 @@
#include <QtCore/QString>
#include <QtCore/QDir>
#include <utility>
#include "dcc.h"
#include "CallGraph.h"
#include "project.h"
#include "Procedure.h"
#include <QtCore/QString>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <utility>
using namespace std;
QString asm1_name, asm2_name; /* Assembler output filenames */
SYMTAB symtab; /* Global symbol table */
STATS stats; /* cfg statistics */
//PROG prog; /* programs fields */
OPTION option; /* Command line options */
Project *Project::s_instance = nullptr;
Project::Project() :
m_selected_loader(nullptr),
callGraph(nullptr),
m_pattern_locator(nullptr)
Project::Project() : callGraph(nullptr)
{
m_project_command_stream.setMaximumCommandCount(10);
connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool)));
}
void Project::initialize()
{
resetCommandsAndErrorState();
delete callGraph;
callGraph = nullptr;
}
void Project::create(const QString &a)
{
// TODO: reset all state.
initialize();
QFileInfo fi(a);
m_fname=a;
@ -49,52 +39,26 @@ bool Project::valid(ilFunction iter)
ilFunction Project::funcIter(Function *to_find)
{
auto iter=std::find_if(pProcList.begin(),pProcList.end(),
[to_find](const PtrFunction &f)->bool {return to_find->shared_from_this()==f;});
[to_find](const Function &f)->bool {return to_find==&f;});
assert(iter!=pProcList.end());
return iter;
}
PtrFunction Project::findByEntry(uint32_t entry)
ilFunction Project::findByEntry(uint32_t entry)
{
/* Search procedure list for one with appropriate entry point */
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
[entry](const PtrFunction &f) { return f->procEntry==entry; });
if(iter==pProcList.end())
return nullptr;
return *iter;
[entry](const Function &f) { return f.procEntry==entry; });
return iter;
}
/**
* \brief Search procedure list for one with given name
*/
PtrFunction Project::findByName(const QString &name)
ilFunction Project::createFunction(FunctionType *f,const QString &name)
{
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
[name](const PtrFunction &f) { return f->name==name; });
if(iter==pProcList.end())
return nullptr;
return *iter;
}
PtrFunction Project::createFunction(FunctionType *f,const QString &name,SegOffAddr addr)
{
PtrFunction func(Function::Create(f,0,name,0));
pProcList.push_back(func);
// FIXME: use provided segment addr !
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;
pProcList.push_back(*Function::Create(f,0,name,0));
return (++pProcList.rbegin()).base();
}
int Project::getSymIdxByAdd(uint32_t adr)
int Project::getSymIdxByAddr(uint32_t adr)
{
size_t i;
for (i = 0; i < symtab.size(); i++)
@ -133,106 +97,8 @@ Project *Project::get()
s_instance=new Project;
return s_instance;
}
SourceMachine *Project::machine()
{
return nullptr;
}
bool Project::addCommand(Command *cmd) {
bool res = m_project_command_stream.add(cmd);
emit commandListChanged();
return res;
}
bool Project::addCommand(PtrFunction f, Command *cmd)
{
bool res = m_function_streams[f].add(cmd);
emit commandListChanged();
return res;
}
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

@ -69,8 +69,8 @@ static bool isLong22 (iICODE pIcode, iICODE pEnd, iICODE &off)
// preincrement because pIcode is not checked here
iICODE icodes[] = { ++pIcode,++pIcode,++pIcode };
if ( icodes[1]->ll()->match(iCMP) and
(isJCond ((llIcode)icodes[0]->ll()->getOpcode())) and
(isJCond ((llIcode)icodes[2]->ll()->getOpcode())))
(isJCond (icodes[0]->ll()->getOpcode())) and
(isJCond (icodes[2]->ll()->getOpcode())))
{
off = initial_icode;
advance(off,2);
@ -500,7 +500,7 @@ int Function::findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE be
* JX lab
* => HLI_JCOND (regH:regL X 0) lab
* This is better code than HLI_JCOND (HI(regH:regL) | LO(regH:regL)) */
else if (pIcode->ll()->match(iOR) and (next1 != pEnd) and (isJCond ((llIcode)next1->ll()->getOpcode())))
else if (pIcode->ll()->match(iOR) and (next1 != pEnd) and (isJCond (next1->ll()->getOpcode())))
{
if (pLocId.longId().srcDstRegMatch(pIcode,pIcode))
{

View File

@ -1,4 +1,4 @@
/**
/*****************************************************************************
* dcc project scanner module
* Implements a simple state driven scanner to convert 8086 machine code into
* I-code
@ -19,7 +19,6 @@
#define S_EXT 0x000200 /* sign extend */
#define OP386 0x000400 /* 386 op-code */
#define NSP 0x000800 /* NOT_HLL if SP is src or dst */
// defined in Enums.h #define ICODEMASK 0xFF00FF /* Masks off parser flags */
static void rm(int i);
static void modrm(int i);
@ -51,15 +50,15 @@ static void none1(int i);
static void none2(int i);
static void checkInt(int i);
#define iZERO (llIcode)0 // For neatness
#define IC llIcode
static struct {
struct StateTabelEntry {
void (*state1)(int);
void (*state2)(int);
uint32_t flg;
llIcode opcode;
} stateTable[] = {
};
static const StateTabelEntry stateTable[] = {
{ modrm, none2, B , iADD }, /* 00 */
{ modrm, none2, 0 , iADD }, /* 01 */
{ modrm, none2, TO_REG | B , iADD }, /* 02 */
@ -75,7 +74,7 @@ static struct {
{ data1, axImp, B , iOR }, /* 0C */
{ data2, axImp, 0 , iOR }, /* 0D */
{ segop, none2, NO_SRC , iPUSH }, /* 0E */
{ none1, none2, OP386 , iZERO }, /* 0F */
{ none1, none2, OP386 , iINVALID }, /* 0F */
{ modrm, none2, B , iADC }, /* 10 */
{ modrm, none2, NSP , iADC }, /* 11 */
{ modrm, none2, TO_REG | B , iADC }, /* 12 */
@ -159,11 +158,11 @@ static struct {
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */
{ none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */
{ memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */
{ none1, none2, OP386 , iZERO }, /* 63 */
{ none1, none2, OP386 , iZERO }, /* 64 */
{ none1, none2, OP386 , iZERO }, /* 65 */
{ none1, none2, OP386 , iZERO }, /* 66 */
{ none1, none2, OP386 , iZERO }, /* 67 */
{ none1, none2, OP386 , iINVALID }, /* 63 */
{ none1, none2, OP386 , iINVALID }, /* 64 */
{ none1, none2, OP386 , iINVALID }, /* 65 */
{ none1, none2, OP386 , iINVALID }, /* 66 */
{ none1, none2, OP386 , iINVALID }, /* 67 */
{ data2, none2, NO_SRC , iPUSH }, /* 68 */
{ modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */
{ data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */
@ -188,10 +187,10 @@ static struct {
{ dispS, none2, 0 , iJGE }, /* 7D */
{ dispS, none2, 0 , iJLE }, /* 7E */
{ dispS, none2, 0 , iJG }, /* 7F */
{ immed, data1, B , iZERO }, /* 80 */
{ immed, data2, NSP , iZERO }, /* 81 */
{ immed, data1, B , iZERO }, /* 82 */ /* ?? */
{ immed, data1, NSP | S_EXT , iZERO }, /* 83 */
{ immed, data1, B , iINVALID }, /* 80 */
{ immed, data2, NSP , iINVALID }, /* 81 */
{ immed, data1, B , iINVALID }, /* 82 */ /* ?? */
{ immed, data1, NSP | S_EXT , iINVALID }, /* 83 */
{ modrm, none2, TO_REG | B , iTEST }, /* 84 */
{ modrm, none2, TO_REG | NSP , iTEST }, /* 85 */
{ modrm, none2, TO_REG | B , iXCHG }, /* 86 */
@ -252,8 +251,8 @@ static struct {
{ regop, data2, 0 , iMOV }, /* BD */
{ regop, data2, 0 , iMOV }, /* BE */
{ regop, data2, 0 , iMOV }, /* BF */
{ shift, data1, B , iZERO }, /* C0 */
{ shift, data1, NSP | SRC_B , iZERO }, /* C1 */
{ shift, data1, B , iINVALID }, /* C0 */
{ shift, data1, NSP | SRC_B , iINVALID }, /* C1 */
{ data2, none2, 0 , iRET }, /* C2 */
{ none1, none2, NO_OPS , iRET }, /* C3 */
{ memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */
@ -268,13 +267,13 @@ static struct {
{ data1,checkInt, NOT_HLL , iINT }, /* CD */
{ none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */
{ none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */
{ shift, const1, B , iZERO }, /* D0 */
{ shift, const1, SRC_B , iZERO }, /* D1 */
{ shift, none1, B , iZERO }, /* D2 */
{ shift, none1, SRC_B , iZERO }, /* D3 */
{ shift, const1, B , iINVALID }, /* D0 */
{ shift, const1, SRC_B , iINVALID }, /* D1 */
{ shift, none1, B , iINVALID }, /* D2 */
{ shift, none1, SRC_B , iINVALID }, /* D3 */
{ data1, axImp, NOT_HLL , iAAM }, /* D4 */
{ data1, axImp, NOT_HLL , iAAD }, /* D5 */
{ none1, none2, 0 , iZERO }, /* D6 */
{ none1, none2, 0 , iINVALID }, /* D6 */
{ memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */
{ escop, none2, FLOAT_OP , iESC }, /* D8 */
{ escop, none2, FLOAT_OP , iESC }, /* D9 */
@ -301,21 +300,21 @@ static struct {
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */
{ none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */
{ none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */
{ none1, none2, 0 , iZERO }, /* F1 */
{ none1, none2, 0 , iINVALID }, /* F1 */
{ prefix, none2, 0 , iREPNE}, /* F2 */
{ prefix, none2, 0 , iREPE }, /* F3 */
{ none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */
{ none1, none2, NO_OPS , iCMC }, /* F5 */
{ arith, none1, B , iZERO }, /* F6 */
{ arith, none1, NSP , iZERO }, /* F7 */
{ arith, none1, B , iINVALID }, /* F6 */
{ arith, none1, NSP , iINVALID }, /* F7 */
{ none1, none2, NO_OPS , iCLC }, /* F8 */
{ none1, none2, NO_OPS , iSTC }, /* F9 */
{ none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */
{ none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */
{ none1, none2, NO_OPS , iCLD }, /* FC */
{ none1, none2, NO_OPS , iSTD }, /* FD */
{ trans, none1, B , iZERO }, /* FE */
{ trans, none1, NSP , iZERO } /* FF */
{ trans, none1, B , iINVALID }, /* FE */
{ trans, none1, NSP , iINVALID } /* FF */
} ;
static uint16_t SegPrefix, RepPrefix;
@ -571,7 +570,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
}
// LLOperand conv = convertOperand(*p.insn.get_dest());
// assert(conv==p.ll()->dst);
if (p.ll()->getOpcode())
if (p.ll()->getOpcode()!=iINVALID)
{
/* Save bytes of image used */
p.ll()->numBytes = (uint8_t)((pInst - prog.image()) - ip);
@ -591,9 +590,10 @@ eErrorId scan(uint32_t ip, ICODE &p)
static bool relocItem(const uint8_t *p)
{
PROG &prog(Project::get()->prog);
int i;
uint32_t off = p - prog.image();
for (int i = 0; i < prog.cReloc; i++)
for (i = 0; i < prog.cReloc; i++)
if (prog.relocTable[i] == off)
return true;
return false;
@ -620,16 +620,16 @@ static int signex(uint8_t b)
return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s);
}
/**
* \brief Updates the source or destination field for the current
/****************************************************************************
* setAddress - Updates the source or destination field for the current
* 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
***************************************************************************/
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 */
LLOperand *pm = (! bool(stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src();
LLOperand *pm = (! (stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src();
/* Set segment. A later procedure (lookupAddr in proclist.c) will
* provide the value of this segment in the field segValue.
@ -786,7 +786,7 @@ static void memImp(int i)
static void memOnly(int )
{
if ((*pInst & 0xC0) == 0xC0)
pIcode->ll()->setOpcode((llIcode)0);
pIcode->ll()->setOpcode(iINVALID);
}
@ -796,7 +796,7 @@ static void memOnly(int )
static void memReg0(int i)
{
if (REG(*pInst) or (*pInst & 0xC0) == 0xC0)
pIcode->ll()->setOpcode((llIcode)0);
pIcode->ll()->setOpcode(iINVALID);
else
rm(i);
}
@ -840,8 +840,8 @@ static void trans(int i)
{
static llIcode transTable[8] =
{
(llIcode)iINC, iDEC, (llIcode)iCALL, (llIcode)iCALLF,
(llIcode)iJMP, (llIcode)iJMPF,(llIcode)iPUSH, (llIcode)0
iINC, iDEC, iCALL, iCALLF,
iJMP, iJMPF,iPUSH, (llIcode)0
};
LLInst *ll = pIcode->ll();
// if(transTable[REG(*pInst)]==iPUSH) {
@ -867,7 +867,7 @@ static void arith(int i)
uint8_t opcode;
static llIcode arithTable[8] =
{
iTEST, (llIcode)0, iNOT, iNEG,
iTEST, iINVALID, iNOT, iNEG,
iMUL , iIMUL, iDIV, iIDIV
};
opcode = arithTable[REG(*pInst)];
@ -984,7 +984,7 @@ static void dispF(int i)
****************************************************************************/
static void prefix(int )
{
if (pIcode->ll()->getOpcode() == iREPE or pIcode->ll()->getOpcode() == iREPNE)
if ((pIcode->ll()->getOpcode() == iREPE) or (pIcode->ll()->getOpcode() == iREPNE))
RepPrefix = pIcode->ll()->getOpcode();
else
SegPrefix = pIcode->ll()->getOpcode();
@ -992,7 +992,7 @@ static void prefix(int )
inline void BumpOpcode(LLInst &ll)
{
llIcode ic((llIcode)ll.getOpcode());
llIcode ic(ll.getOpcode());
ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type
ll.setOpcode(ic);
}
@ -1068,7 +1068,7 @@ static void none1(int )
****************************************************************************/
static void none2(int )
{
if ( pIcode->ll()->srcIsImmed() )
if ( pIcode->ll()->testFlags(I) )
pIcode->ll()->setFlags(NO_OPS);
}

View File

@ -1,24 +0,0 @@
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()

View File

@ -1,15 +0,0 @@
#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)

View File

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

View File

@ -1,22 +0,0 @@
#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

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

View File

@ -1,55 +0,0 @@
#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

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

View File

@ -1,53 +0,0 @@
#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)

View File

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

14
src/tests/loader.cpp Normal file
View File

@ -0,0 +1,14 @@
#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());
}

27
src/tests/project.cpp Normal file
View File

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

View File

@ -1,71 +0,0 @@
#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());
}

View File

@ -1,37 +0,0 @@
#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

@ -1,57 +0,0 @@
<?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>

View File

@ -1,147 +0,0 @@
#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);
}

View File

@ -1,53 +0,0 @@
#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

View File

@ -1,372 +0,0 @@
<?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

@ -1,124 +0,0 @@
#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

@ -1,65 +0,0 @@
#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

@ -1,74 +0,0 @@
<?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

@ -1,121 +0,0 @@
#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

@ -1,49 +0,0 @@
#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

@ -1,109 +0,0 @@
<?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>

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