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 */ /* the instruction proper */
enum x86_insn_prefix prefix; /* prefixes ORed together */ enum x86_insn_prefix prefix; /* prefixes ORed together */
char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */ char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */
char mnemonic[MAX_MNEM_STR+1]; char mnemonic[MAX_MNEM_STR];
x86_oplist_t *operands; /* list of explicit/implicit operands */ x86_oplist_t *operands; /* list of explicit/implicit operands */
size_t operand_count; /* total number of operands */ size_t operand_count; /* total number of operands */
size_t explicit_count; /* number of explicit operands */ size_t explicit_count; /* number of explicit operands */

View File

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

View File

@ -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 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: The code provided in this distribution is (C) by their authors:
- Cristina Cifuentes (most of dcc code) - Cristina Cifuentes (most of dcc code)
- Mike van Emmerik (signatures and prototype code) - Mike van Emmerik (signatures and prototype code)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,41 +1,33 @@
#pragma once #pragma once
#include "ast.h" #include "ast.h"
#ifdef PASCAL
#undef PASCAL
#endif
class QTextStream; class QTextStream;
struct CConv { struct CConv {
enum CC_Type { enum Type {
UNKNOWN=0, eUnknown=0,
C, eCdecl,
PASCAL ePascal
}; };
virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0; virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0;
//! given return and argument types fill Function's STKFRAME and return locations
virtual void calculateStackLayout(Function *func)=0;
virtual void writeComments(QTextStream &)=0; virtual void writeComments(QTextStream &)=0;
static CConv * create(CC_Type v); static CConv * create(Type v);
protected: protected:
}; };
struct C_CallingConvention : public CConv { struct C_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override; virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &) override; virtual void writeComments(QTextStream &);
void calculateStackLayout(Function *func) override;
private: private:
int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs); int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs);
}; };
struct Pascal_CallingConvention : public CConv { struct Pascal_CallingConvention : public CConv {
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override; virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
virtual void writeComments(QTextStream &) override; virtual void writeComments(QTextStream &);
void calculateStackLayout(Function *func) override;
}; };
struct Unknown_CallingConvention : public CConv { struct Unknown_CallingConvention : public CConv {
void processHLI(Function *func, Expr *_exp, iICODE picode) override {} void processHLI(Function *func, Expr *_exp, iICODE picode) {}
void calculateStackLayout(Function *func) override; virtual void writeComments(QTextStream &);
virtual void writeComments(QTextStream &) override;
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon<STKSYM>
//std::vector<STKSYM> sym; //std::vector<STKSYM> sym;
//STKSYM * sym; /* Symbols */ //STKSYM * sym; /* Symbols */
int16_t m_minOff; /* Initial offset in stack frame*/ int16_t m_minOff; /* Initial offset in stack frame*/
int16_t m_maxOff; /* Maximum offset in stack frame*/ int16_t maxOff; /* Maximum offset in stack frame*/
int cb; /* Number of bytes in arguments */ int cb; /* Number of bytes in arguments */
int numArgs; /* No. of arguments in the table*/ int numArgs; /* No. of arguments in the table*/
void adjustForArgType(size_t numArg_, hlType actType_); void adjustForArgType(size_t numArg_, hlType actType_);
STKFRAME() : m_minOff(0),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, EQUAL, NOT_EQUAL, LESS, GREATER_EQUAL,
LESS_EQUAL, GREATER, GREATER_EQUAL, LESS}; LESS_EQUAL, GREATER, GREATER_EQUAL, LESS};
struct AstIdent; struct AstIdent;
class Function; struct Function;
struct STKFRAME; struct STKFRAME;
struct LOCAL_ID; struct LOCAL_ID;
struct ICODE; struct ICODE;
@ -221,9 +221,6 @@ struct AstIdent : public UnaryOperator
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym); virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);
virtual Expr *insertSubTreeLongReg(Expr *_expr, int longIdx); virtual Expr *insertSubTreeLongReg(Expr *_expr, int longIdx);
virtual bool xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locId); 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 struct GlobalVariable : public AstIdent
{ {
@ -241,7 +238,7 @@ struct GlobalVariable : public AstIdent
struct GlobalVariableIdx : public AstIdent struct GlobalVariableIdx : public AstIdent
{ {
bool valid; bool valid;
int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */ int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */
virtual Expr *clone() const virtual Expr *clone() const
{ {
@ -255,9 +252,9 @@ struct GlobalVariableIdx : public AstIdent
struct Constant : public AstIdent struct Constant : public AstIdent
{ {
struct _kte struct _kte
{ /* for CONSTANT only */ { /* for CONSTANT only */
uint32_t kte; /* value of the constant */ uint32_t kte; /* value of the constant */
uint8_t size; /* #bytes size constant */ uint8_t size; /* #bytes size constant */
} kte; } kte;
Constant(uint32_t _kte, uint8_t size) Constant(uint32_t _kte, uint8_t size)
@ -272,11 +269,11 @@ struct Constant : public AstIdent
} }
QString walkCondExpr(Function *pProc, int *numLoc) const; QString walkCondExpr(Function *pProc, int *numLoc) const;
int hlTypeSize(Function *pproc) const; int hlTypeSize(Function *pproc) const;
hlType expType(Function *pproc) const; hlType expType(Function *pproc) const { return TYPE_CONST; }
}; };
struct FuncNode : public AstIdent struct FuncNode : public AstIdent
{ {
struct _call { /* for FUNCTION only */ struct _call { /* for FUNCTION only */
Function *proc; Function *proc;
STKFRAME *args; STKFRAME *args;
} call; } call;
@ -297,8 +294,8 @@ struct FuncNode : public AstIdent
struct RegisterNode : public AstIdent struct RegisterNode : public AstIdent
{ {
const LOCAL_ID *m_syms; const LOCAL_ID *m_syms;
regType regiType; /* for REGISTER only */ regType regiType; /* for REGISTER only */
int regiIdx; /* index into localId, REGISTER */ int regiIdx; /* index into localId, REGISTER */
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym); virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);

View File

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

View File

@ -22,31 +22,31 @@
#include "BasicBlock.h" #include "BasicBlock.h"
class Project; class Project;
/* CALL GRAPH NODE */ /* CALL GRAPH NODE */
extern bundle cCode; /* Output C procedure's declaration and code */ extern bundle cCode; /* Output C procedure's declaration and code */
/**** Global variables ****/ /**** Global variables ****/
extern QString asm1_name, asm2_name; /* Assembler output filenames */ extern QString asm1_name, asm2_name; /* Assembler output filenames */
typedef struct { /* Command line option flags */ /** Command line option flags */
unsigned verbose : 1; struct OPTION
unsigned VeryVerbose : 1; {
unsigned asm1 : 1; /* Early disassembly listing */ bool verbose;
unsigned asm2 : 1; /* Disassembly listing after restruct */ bool VeryVerbose;
unsigned Map : 1; bool asm1; /* Early disassembly listing */
unsigned Stats : 1; bool asm2; /* Disassembly listing after restruct */
unsigned Interact : 1; /* Interactive mode */ bool Map;
unsigned Calls : 1; /* Follow register indirect calls */ bool Stats;
QString filename; /* The input filename */ bool Interact; /* Interactive mode */
bool Calls; /* Follow register indirect calls */
QString filename; /* The input filename */
uint32_t CustomEntryPoint; uint32_t CustomEntryPoint;
} OPTION; };
extern OPTION option; /* Command line options */ extern OPTION option; /* Command line options */
#include "BinaryImage.h" #include "BinaryImage.h"
/* Memory map states */ /* Memory map states */
enum eAreaType enum eAreaType
{ {
@ -59,13 +59,13 @@ enum eAreaType
/* Intermediate instructions statistics */ /* Intermediate instructions statistics */
struct STATS struct STATS
{ {
int numBBbef; /* number of basic blocks initially */ int numBBbef; /* number of basic blocks initially */
int numBBaft; /* number of basic blocks at the end */ int numBBaft; /* number of basic blocks at the end */
int nOrder; /* n-th order */ int nOrder; /* n-th order */
int numLLIcode; /* number of low-level Icode instructions */ int numLLIcode; /* number of low-level Icode instructions */
int numHLIcode; /* number of high-level Icode instructions */ int numHLIcode; /* number of high-level Icode instructions */
int totalLL; /* total number of low-level Icode insts */ int totalLL; /* total number of low-level Icode insts */
int totalHL; /* total number of high-level Icod insts */ int totalHL; /* total number of high-level Icod insts */
}; };
extern STATS stats; /* Icode statistics */ extern STATS stats; /* Icode statistics */
@ -76,17 +76,18 @@ extern STATS stats; /* Icode statistics */
void udm(void); /* udm.c */ void udm(void); /* udm.c */
void freeCFG(BB * cfg); /* graph.c */ void freeCFG(BB * cfg); /* graph.c */
BB * newBB(BB *, int, int, uint8_t, int, Function *); /* graph.c */ BB * newBB(BB *, int, int, uint8_t, int, Function *); /* graph.c */
void BackEnd(CALL_GRAPH *); /* backend.c */ void BackEnd(CALL_GRAPH *); /* backend.c */
extern char *cChar(uint8_t c); /* backend.c */ extern char *cChar(uint8_t c); /* backend.c */
eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */ eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */
void parse (CALL_GRAPH * *); /* parser.c */ void parse (CALL_GRAPH * *); /* parser.c */
extern int strSize (const uint8_t *, char); /* parser.c */ extern int strSize (const uint8_t *, char); /* parser.c */
void 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 */ bool JmpInst(llIcode opcode); /* idioms.c */
queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */ queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */
bool SetupLibCheck(QString pattern_file_id); /* chklib.c */ bool SetupLibCheck(void); /* chklib.c */
void CleanupLibCheck(void); /* chklib.c */ void CleanupLibCheck(void); /* chklib.c */
bool LibCheck(Function &p); /* chklib.c */ bool LibCheck(Function &p); /* chklib.c */
@ -99,7 +100,5 @@ QString writeJcondInv(HLTYPE, Function *, int *);
/* Exported funcions from locident.c */ /* Exported funcions from locident.c */
bool checkLongEq(LONG_STKID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &atOffset); bool checkLongEq(LONG_STKID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &atOffset);
bool checkLongRegEq(LONGID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &); bool checkLongRegEq(LONGID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &);
eReg otherLongRegi(eReg, int, LOCAL_ID *);
extern const char *indentStr(int level); extern const char *indentStr(int level);

View File

@ -4,11 +4,21 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QDir> #include <QtCore/QDir>
class IStructuredTextTarget; class IXmlTarget;
struct IDcc { struct IDcc {
static IDcc *get(); 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 installDir()=0;
virtual QDir dataDir(QString kind)=0; virtual QDir dataDir(QString kind)=0;
}; };

View File

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

View File

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

View File

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

View File

@ -28,7 +28,7 @@ struct LLInst;
typedef std::list<ICODE>::iterator iICODE; typedef std::list<ICODE>::iterator iICODE;
struct IDX_ARRAY : public std::vector<iICODE> struct IDX_ARRAY : public std::vector<iICODE>
{ {
bool inList(iICODE idx) bool inList(iICODE idx) const
{ {
return std::find(begin(),end(),idx)!=end(); return std::find(begin(),end(),idx)!=end();
} }
@ -36,32 +36,32 @@ struct IDX_ARRAY : public std::vector<iICODE>
enum frameType enum frameType
{ {
STK_FRAME, /* For stack vars */ STK_FRAME, /* For stack vars */
REG_FRAME, /* For register variables */ REG_FRAME, /* For register variables */
GLB_FRAME /* For globals */ GLB_FRAME /* For globals */
}; };
struct BWGLB_TYPE struct BWGLB_TYPE
{ {
int16_t seg; /* segment value */ int16_t seg; /* segment value */
int16_t off; /* offset */ int16_t off; /* offset */
eReg regi; /* optional indexed register */ eReg regi; /* optional indexed register */
} ; } ;
/* For TYPE_LONG_(UN)SIGN on the stack */ /* For TYPE_LONG_(UN)SIGN on the stack */
struct LONG_STKID_TYPE struct LONG_STKID_TYPE
{ {
int offH; /* high offset from BP */ int offH; /* high offset from BP */
int offL; /* low offset from BP */ int offL; /* low offset from BP */
LONG_STKID_TYPE(int h,int l) : offH(h),offL(l) {} LONG_STKID_TYPE(int h,int l) : offH(h),offL(l) {}
}; };
/* For TYPE_LONG_(UN)SIGN registers */ /* For TYPE_LONG_(UN)SIGN registers */
struct LONGID_TYPE struct LONGID_TYPE
{ {
protected: protected:
eReg m_h; /* high register */ eReg m_h; /* high register */
eReg m_l; /* low register */ eReg m_l; /* low register */
public: public:
void set(eReg highpart,eReg lowpart) void set(eReg highpart,eReg lowpart)
{ {
@ -75,7 +75,7 @@ public:
LONGID_TYPE(eReg h,eReg l) : m_h(h),m_l(l) {} LONGID_TYPE(eReg h,eReg l) : m_h(h),m_l(l) {}
}; };
struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */ struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */
{ {
int16_t seg; /* segment value */ int16_t seg; /* segment value */
int16_t offH; /* offset high */ int16_t offH; /* offset high */
@ -93,28 +93,30 @@ struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */
struct ID struct ID
{ {
protected: protected:
LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */ LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */
public: public:
hlType type; /* Probable type */ hlType type; /* Probable type */
bool illegal; /* Boolean: not a valid field any more */
//std::vector<iICODE> idx;
IDX_ARRAY idx; /* Index into icode array (REG_FRAME only) */ IDX_ARRAY idx; /* Index into icode array (REG_FRAME only) */
frameType loc; /* Frame location */ frameType loc; /* Frame location */
bool illegal; /* Boolean: not a valid field any more */
bool hasMacro; /* Identifier requires a macro */ bool hasMacro; /* Identifier requires a macro */
char macro[10]; /* Macro for this identifier */ char macro[10]; /* Macro for this identifier */
QString name; /* Identifier's name */ QString name; /* Identifier's name */
union ID_UNION { /* Different types of identifiers */ union ID_UNION { /* Different types of identifiers */
friend struct ID;
protected:
LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */ LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */
eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */ public:
eReg regi; /* For TYPE_BYTE(WORD)_(UN)SIGN registers */
struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */ struct { /* For TYPE_BYTE(WORD)_(UN)SIGN on the stack */
uint8_t regOff; /* register offset (if any) */ uint8_t regOff; /* register offset (if any) */
int off; /* offset from BP */ int off; /* offset from BP */
} bwId; } bwId;
BWGLB_TYPE bwGlb; /* For TYPE_BYTE(uint16_t)_(UN)SIGN globals */ BWGLB_TYPE bwGlb; /* For TYPE_BYTE(uint16_t)_(UN)SIGN globals */
LONGGLB_TYPE longGlb; LONGGLB_TYPE longGlb;
struct { /* For TYPE_LONG_(UN)SIGN constants */ struct { /* For TYPE_LONG_(UN)SIGN constants */
uint32_t h; /* high uint16_t */ uint32_t h; /* high uint16_t */
uint32_t l; /* low uint16_t */ uint32_t l; /* low uint16_t */
} longKte; } longKte;
ID_UNION() { /*new (&longStkId) LONG_STKID_TYPE();*/} ID_UNION() { /*new (&longStkId) LONG_STKID_TYPE();*/}
} id; } id;
@ -140,6 +142,8 @@ public:
sprintf (buf, "loc%d", i); sprintf (buf, "loc%d", i);
name=buf; name=buf;
} }
bool isLongRegisterPair() const { return (loc == REG_FRAME) and isLong();}
eReg getPairedRegister(eReg first) const;
}; };
struct LOCAL_ID struct LOCAL_ID
@ -167,10 +171,11 @@ public:
void flagByteWordId(int off); void flagByteWordId(int off);
void propLongId(uint8_t regL, uint8_t regH, const QString & name); void propLongId(uint8_t regL, uint8_t regH, const QString & name);
size_t csym() const {return id_arr.size();} size_t csym() const {return id_arr.size();}
void newRegArg(iICODE picode, iICODE ticode) const; void newRegArg(ICODE & picode, ICODE & ticode) const;
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong) const; void processTargetIcode(ICODE & picode, int &numHlIcodes, ICODE & ticode, bool isLong) const;
void forwardSubs(Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode, int &numHlIcodes) const; void forwardSubs(Expr *lhs, Expr *rhs, ICODE & picode, ICODE & ticode, int &numHlIcodes) const;
AstIdent *createId(const ID *retVal, iICODE ix_); AstIdent *createId(const ID *retVal, iICODE ix_);
eReg getPairedRegisterAt(int idx,eReg first) const;
}; };

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

@ -1,89 +1,9 @@
#include "CallConvention.h"
#include "Procedure.h"
#include <QtCore/QTextStream>
#include <ostream> #include <ostream>
#include <cassert> #include <cassert>
static void calculateReturnLocations(Function *func) { #include "CallConvention.h"
switch(func->getReturnType()) { #include <QtCore/QTextStream>
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;
}
static void rebuildArguments_FromStackLayout(Function *func) { CConv *CConv::create(Type v)
STKFRAME &stk(func->args);
std::map<int,const STKSYM *> arg_locations;
FunctionType *f;
for(const STKSYM & s: stk) {
if(s.label>0) {
arg_locations[s.label] = &s;
}
}
if(arg_locations.empty())
return;
std::vector<Type> argtypes;
auto stack_loc_iter = arg_locations.begin();
for(int i=stack_loc_iter->first; i<=arg_locations.rbegin()->first; ) {
int till_next_loc=stack_loc_iter->first-i;
if(till_next_loc==0) {
int entry_size=stack_loc_iter->second->size;
argtypes.push_back({stack_loc_iter->second->type});
i+=entry_size;
++stack_loc_iter;
} else {
if(till_next_loc>=4) {
argtypes.push_back({TYPE_LONG_SIGN});
i+=4;
} else if(till_next_loc>=2) {
argtypes.push_back({TYPE_WORD_SIGN});
i+=2;
} else {
argtypes.push_back({TYPE_BYTE_SIGN});
i+=1;
}
}
}
f = FunctionType::get({func->type->getReturnType()},argtypes,func->type->isVarArg());
f->retVal = func->type->retVal;
delete func->type;
func->type = f;
}
CConv *CConv::create(CC_Type v)
{ {
static C_CallingConvention *c_call = nullptr; static C_CallingConvention *c_call = nullptr;
static Pascal_CallingConvention *p_call = nullptr; static Pascal_CallingConvention *p_call = nullptr;
@ -95,9 +15,9 @@ CConv *CConv::create(CC_Type v)
if(nullptr==u_call) if(nullptr==u_call)
u_call = new Unknown_CallingConvention; u_call = new Unknown_CallingConvention;
switch(v) { switch(v) {
case UNKNOWN: return u_call; case eUnknown: return u_call;
case C: return c_call; case eCdecl: return c_call;
case PASCAL: return p_call; case ePascal: return p_call;
} }
assert(false); assert(false);
return nullptr; return nullptr;
@ -107,31 +27,11 @@ void C_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * C calling convention.\n"; ostr << " * C calling convention.\n";
} }
void C_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Pascal_CallingConvention::writeComments(QTextStream & ostr) void Pascal_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * Pascal calling convention.\n"; ostr << " * Pascal calling convention.\n";
} }
void Pascal_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
//TODO: pascal args are passed in reverse order ?
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}
void Unknown_CallingConvention::writeComments(QTextStream & ostr) void Unknown_CallingConvention::writeComments(QTextStream & ostr)
{ {
ostr << " * Unknown calling convention.\n"; ostr << " * Unknown calling convention.\n";
} }
void Unknown_CallingConvention::calculateStackLayout(Function *func)
{
calculateReturnLocations(func);
rebuildArguments_FromStackLayout(func);
calculateArgLocations_allOnStack(func);
}

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 "DccFrontend.h"
#include "Loaders.h"
#include "dcc.h" #include "dcc.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "project.h" #include "project.h"
#include "disassem.h" #include "disassem.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "Command.h"
#include "chklib.h"
#include <QtCore/QFileInfo> #include <QtCore/QFileInfo>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <cstdio> #include <cstdio>
class Loader
{
bool loadIntoProject(IProject *);
};
struct PSP { /* PSP structure */
uint16_t int20h; /* interrupt 20h */
uint16_t eof; /* segment, end of allocation block */
uint8_t res1; /* reserved */
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
uint8_t int22h[4]; /* vector for terminate routine */
uint8_t int23h[4]; /* vector for ctrl+break routine */
uint8_t int24h[4]; /* vector for error routine */
uint8_t res2[22]; /* reserved */
uint16_t segEnv; /* segment address of environment block */
uint8_t res3[34]; /* reserved */
uint8_t int21h[6]; /* opcode for int21h and far return */
uint8_t res4[6]; /* reserved */
uint8_t fcb1[16]; /* default file control block 1 */
uint8_t fcb2[16]; /* default file control block 2 */
uint8_t res5[4]; /* reserved */
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
};
static struct MZHeader { /* EXE file header */
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
uint8_t sigHi;
uint16_t lastPageSize; /* Size of the last page */
uint16_t numPages; /* Number of pages in the file */
uint16_t numReloc; /* Number of relocation items */
uint16_t numParaHeader; /* # of paragraphs in the header */
uint16_t minAlloc; /* Minimum number of paragraphs */
uint16_t maxAlloc; /* Maximum number of paragraphs */
uint16_t initSS; /* Segment displacement of stack */
uint16_t initSP; /* Contents of SP at entry */
uint16_t checkSum; /* Complemented checksum */
uint16_t initIP; /* Contents of IP at entry */
uint16_t initCS; /* Segment displacement of code */
uint16_t relocTabOffset; /* Relocation table offset */
uint16_t overlayNum; /* Overlay number */
} header;
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
//static void LoadImage(char *filename); //static void LoadImage(char *filename);
static void displayMemMap(void); static void displayMemMap(void);
/**************************************************************************** /****************************************************************************
@ -21,19 +62,19 @@ static void displayMemMap(void);
***************************************************************************/ ***************************************************************************/
void PROG::displayLoadInfo(void) void PROG::displayLoadInfo(void)
{ {
int i; int i;
printf("File type is %s\n", (fCOM)?"COM":"EXE"); printf("File type is %s\n", (fCOM)?"COM":"EXE");
// if (not fCOM) { if (not fCOM) {
// printf("Signature = %02X%02X\n", header.sigLo, header.sigHi); printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
// printf("File size %% 512 = %04X\n", LH(&header.lastPageSize)); printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
// printf("File size / 512 = %04X pages\n", LH(&header.numPages)); printf("File size / 512 = %04X pages\n", LH(&header.numPages));
// printf("# relocation items = %04X\n", LH(&header.numReloc)); printf("# relocation items = %04X\n", LH(&header.numReloc));
// printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader)); printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
// printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc)); printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
// printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc)); printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
// } }
printf("Load image size = %08lX\n", cbImage); // - sizeof(PSP) printf("Load image size = %08lX\n", cbImage - sizeof(PSP));
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP); printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP); printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
@ -55,7 +96,7 @@ static void fill(int ip, char *bf)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
static uint8_t type[4] = {'.', 'd', 'c', 'x'}; static uint8_t type[4] = {'.', 'd', 'c', 'x'};
uint8_t i; uint8_t i;
for (i = 0; i < 16; i++, ip++) for (i = 0; i < 16; i++, ip++)
{ {
@ -73,7 +114,7 @@ static void displayMemMap(void)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
char c, b1[33], b2[33], b3[33]; char c, b1[33], b2[33], b3[33];
uint8_t i; uint8_t i;
int ip = 0; int ip = 0;
@ -84,10 +125,10 @@ static void displayMemMap(void)
printf("%06X %s\n", ip, b1); printf("%06X %s\n", ip, b1);
ip += 16; ip += 16;
for (i = 3, c = b1[1]; i < 32 and c == b1[i]; i += 2) for (i = 3, c = b1[1]; i < 32 and c == b1[i]; i += 2)
; /* Check if all same */ ; /* Check if all same */
if (i > 32) if (i > 32)
{ {
fill(ip, b2); /* Skip until next two are not same */ fill(ip, b2); /* Skip until next two are not same */
fill(ip+16, b3); fill(ip+16, b3);
if (not (strcmp(b1, b2) || strcmp(b1, b3))) if (not (strcmp(b1, b2) || strcmp(b1, b3)))
{ {
@ -125,106 +166,370 @@ bool DccFrontend::FrontEnd ()
/* Search through code looking for impure references and flag them */ /* Search through code looking for impure references and flag them */
Disassembler ds(1); Disassembler ds(1);
for(PtrFunction &f : Project::get()->pProcList) for(Function &f : Project::get()->pProcList)
{ {
f->markImpure(); f.markImpure();
if (option.asm1) if (option.asm1)
{ {
ds.disassem(f); ds.disassem(&f);
} }
} }
if (option.Interact) if (option.Interact)
{ {
interactDis(Project::get()->pProcList.front(), 0); /* Interactive disassembler */ interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
} }
/* Converts jump target addresses to icode offsets */ /* Converts jump target addresses to icode offsets */
for(PtrFunction &f : Project::get()->pProcList) for(Function &f : Project::get()->pProcList)
{ {
f->bindIcodeOff(); f.bindIcodeOff();
} }
/* Print memory bitmap */ /* Print memory bitmap */
if (option.Map) if (option.Map)
displayMemMap(); displayMemMap();
return(true); // we no longer own proj ! return(true); // we no longer own proj !
} }
struct DosLoader {
protected:
void prepareImage(PROG &prog,size_t sz,QFile &fp) {
/* Allocate a block of memory for the program. */
prog.cbImage = sz + sizeof(PSP);
prog.Imagez = new uint8_t [prog.cbImage];
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
prog.Imagez[1] = 0x20; /* for termination checking */
/* Read in the image past where a PSP would go */
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
}
};
struct ComLoader : public DosLoader {
bool canLoad(QFile &fp) {
fp.seek(0);
char sig[2];
if(2==fp.read(sig,2)) {
return not (sig[0] == 0x4D and sig[1] == 0x5A);
}
return false;
}
bool load(PROG &prog,QFile &fp) {
fp.seek(0);
/* COM file
* In this case the load module size is just the file length
*/
auto cb = fp.size();
/* COM programs start off with an ORG 100H (to leave room for a PSP)
* This is also the implied start address so if we load the image
* at offset 100H addresses should all line up properly again.
*/
prog.initCS = 0;
prog.initIP = 0x100;
prog.initSS = 0;
prog.initSP = 0xFFFE;
prog.cReloc = 0;
prepareImage(prog, cb, fp);
/* Set up memory map */
cb = (prog.cbImage + 3) / 4;
prog.map = (uint8_t *)malloc(cb);
memset(prog.map, BM_UNKNOWN, (size_t)cb);
return true;
}
};
#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 * 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 /* Parses the program, builds the call graph, and returns the list of
* procedures found */ * procedures found */
void DccFrontend::parse(Project &proj) void DccFrontend::parse(Project &proj)
{ {
PROG &prog(proj.prog);
STATE state;
/* Set initial state */ /* Set initial state */
proj.addCommand(new MachineStateInitialization); state.setState(rES, 0); /* PSP segment */
proj.addCommand(new FindMain); 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) /* Check for special settings of initial state, based on idioms of the
{ startup code */
assert(ctx && ctx->m_project); state.checkStartup();
Project &proj(*ctx->m_project); ilFunction start_proc;
const PROG &prog(proj.prog); /* Make a struct for the initial procedure */
proj.m_entry_state.setState(rES, 0); /* PSP segment */ if (prog.offMain != -1)
proj.m_entry_state.setState(rDS, 0); {
proj.m_entry_state.setState(rCS, prog.initCS); start_proc = proj.createFunction(0,"main");
proj.m_entry_state.setState(rSS, prog.initSS); start_proc->retVal.loc = REG_FRAME;
proj.m_entry_state.setState(rSP, prog.initSP); start_proc->retVal.type = TYPE_WORD_SIGN;
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP; start_proc->retVal.id.regi = rAX;
proj.SynthLab = SYNTHESIZED_MIN; /* We know where main() is. Start the flow of control from there */
return true; start_proc->procEntry = prog.offMain;
}
bool FindMain::execute(CommandContext *ctx) {
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction start_func = proj.findByName("start");
if(ctx->m_project->m_entry_state.IP==0) {
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
return false;
}
/* Check for special settings of initial state, based on idioms of the startup code */
if(checkStartup(ctx->m_project->m_entry_state)) {
start_func->markDoNotDecompile(); // we have main, do not decompile the start proc
//TODO: main arguments and return values should depend on detected compiler/library
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
main_type->setCallingConvention(CConv::C);
proj.addCommand(new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type));
proj.addCommand(new LoadPatternLibrary());
} else {
start_func->state = proj.m_entry_state; // just in case we fail to find main, initialize 'state' for start func
}
return true;
}
QString CreateFunction::instanceDescription() const {
return QString("%1 \"%2\" @ 0x%3").arg(name()).arg(m_name).arg(m_addr.addr,0,16,QChar('0'));
}
bool CreateFunction::execute(CommandContext *ctx) {
Project &proj(*ctx->m_project);
const PROG &prog(proj.prog);
PtrFunction func = proj.createFunction(m_type,m_name,m_addr);
if(m_name=="main") {
/* In medium and large models, the segment of main may (will?) not be /* In medium and large models, the segment of main may (will?) not be
the same as the initial CS segment (of the startup code) */ the same as the initial CS segment (of the startup code) */
proj.m_entry_state.setState(rCS, prog.segMain); state.setState(rCS, prog.segMain);
proj.m_entry_state.IP = prog.offMain; state.IP = prog.offMain;
func->state = proj.m_entry_state;
} }
if(m_name=="start") { else
proj.addCommand(new MachineStateInitialization); {
proj.addCommand(new FindMain); start_proc = proj.createFunction(0,"start");
/* Create initial procedure at program start address */
start_proc->procEntry = (uint32_t)state.IP;
} }
// proj.addCommand(new ProcessFunction); /* The state info is for the first procedure */
//proj.addCommand(new FollowControl()); 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 */ /* Recursively build entire procedure list */
//proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state); start_proc->FollowCtrl(proj.callGraph, &state);
return true;
/* 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 "msvc_fixes.h"
#include "project.h" #include "project.h"
#include "scanner.h" #include "scanner.h"
#include "ui/StructuredTextTarget.h"
#include <QtCore/QDebug>
//FunctionType *Function::getFunctionType() const //FunctionType *Function::getFunctionType() const
//{ //{
@ -38,100 +35,6 @@ void JumpTable::pruneEntries(uint16_t cs)
} }
void Function::callingConv(CConv::CC_Type v) { void Function::callingConv(CConv::Type v) {
type->setCallingConvention(v); m_call_conv=CConv::create(v);
getFunctionType()->m_call_conv->calculateStackLayout(this);
}
static QString sizeToPtrName(int size)
{
switch(size)
{
case 1:
return "BYTE ptr" ;
case 2:
return "WORD ptr";
case 4:
return "DWORD ptr";
}
return "UNKOWN ptr";
}
static void toStructuredText(STKFRAME &stk,IStructuredTextTarget *out, int level) {
int curlevel = 0;
int maxlevel = stk.m_maxOff - stk.m_minOff;
for(STKSYM & p : stk)
{
if (curlevel > p.label)
{
qWarning() << "error, var collapse!!!";
curlevel = p.label;
}
else if (curlevel < p.label)
{
out->addSpace(4);
out->prtt(QString("gap len = %1").arg(p.label - curlevel,0,16));
curlevel = p.label;
out->addEOL();
}
out->addSpace(4);
out->addTaggedString(XT_Symbol,p.name,&p);
out->prtt("equ");
out->addSpace();
out->prtt(sizeToPtrName(p.size));
out->addSpace();
if (p.arrayMembers>1)
{
out->addTaggedString(XT_Number,QString::number(p.arrayMembers,16));
out->prtt("dup (?)");
out->addSpace();
}
out->TAGbegin(XT_Number, NULL);
out->prtt(QString("%1h").arg(p.label,0,16));
out->TAGend(XT_Number);
out->addEOL();
curlevel += p.size * p.arrayMembers;
}
if (curlevel < maxlevel)
{
out->prtt(QString(" gap len = %1h").arg(maxlevel - curlevel,0,16));
}
}
extern void toStructuredText(LLInst *insn,IStructuredTextTarget *out, int level);
static void toStructuredText(ICODE &stk,IStructuredTextTarget *out, int level) {
if(level==0) {
toStructuredText(stk.ll(),out,level);
}
}
void Function::toStructuredText(IStructuredTextTarget *out, int level)
{
out->TAGbegin(XT_Function, this);
out->addTaggedString(XT_FuncName,name);
out->prtt(" proc");
out->addEOL();
::toStructuredText(args,out,level);
out->addEOL();
for(ICODE &ic : Icode) {
::toStructuredText(ic,out,level);
}
out->addTaggedString(XT_FuncName,name);
out->addSpace();
out->prtt("endp");
out->addEOL();
out->TAGend(XT_Function);
}
void FunctionType::setCallingConvention(CConv::CC_Type cc)
{
m_call_conv=CConv::create(cc);
assert(m_call_conv);
}
void Function::switchState(DecompilationStep s)
{
nStep = s;
} }

View File

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

View File

@ -13,6 +13,7 @@
#include "project.h" #include "project.h"
#include <QtCore/QTextStream> #include <QtCore/QTextStream>
#include <QtCore/QDebug>
#include <boost/range.hpp> #include <boost/range.hpp>
#include <boost/range/adaptor/filtered.hpp> #include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm.hpp> #include <boost/range/algorithm.hpp>
@ -29,12 +30,15 @@ using namespace boost::adaptors;
extern int strSize (const uint8_t *, char); extern int strSize (const uint8_t *, char);
extern char *cChar(uint8_t c); extern char *cChar(uint8_t c);
namespace
{
// Conditional operator symbols in C. Index by condOp enumeration type // 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 */ /* Local expression stack */
//typedef struct _EXP_STK { //typedef struct _EXP_STK {
@ -43,13 +47,13 @@ static const char * const condOpSym[] = { " <= ", " < ", " == ", " != ", " > ",
//} EXP_STK; - for local expression stack //} EXP_STK; - for local expression stack
/* Returns the integer i in C hexadecimal format */ /* 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]; static char buf[10];
sprintf (buf, "%s%x", (i > 9) ? "0x" : "", i); sprintf (buf, "%s%x", (i > 9) ? "0x" : "", i);
return (buf); return buf;
}
} }
/* Sets the du record for registers according to the du flag */ /* Sets the du record for registers according to the du flag */
void ICODE::setRegDU (eReg regi, operDu du_in) void ICODE::setRegDU (eReg regi, operDu du_in)
@ -62,19 +66,19 @@ void ICODE::setRegDU (eReg regi, operDu du_in)
} }
switch (du_in) switch (du_in)
{ {
case eDEF: case eDEF:
du.def.addReg(regi); du.def.addReg(regi);
du1.addDef(regi); du1.addDef(regi);
break; break;
case eUSE: case eUSE:
du.use.addReg(regi); du.use.addReg(regi);
break; break;
case USE_DEF: case USE_DEF:
du.addDefinedAndUsed(regi); du.addDefinedAndUsed(regi);
du1.addDef(regi); du1.addDef(regi);
break; break;
case NONE: /* do nothing */ case NONE: /* do nothing */
break; break;
} }
} }
@ -84,24 +88,24 @@ void ICODE::copyDU(const ICODE &duIcode, operDu _du, operDu duDu)
{ {
switch (_du) switch (_du)
{ {
case eDEF: case eDEF:
if (duDu == eDEF) if (duDu == eDEF)
du.def=duIcode.du.def; du.def=duIcode.du.def;
else else
du.def=duIcode.du.use; du.def=duIcode.du.use;
break; break;
case eUSE: case eUSE:
if (duDu == eDEF) if (duDu == eDEF)
du.use = duIcode.du.def; du.use = duIcode.du.def;
else else
du.use = duIcode.du.use; du.use = duIcode.du.use;
break; break;
case USE_DEF: case USE_DEF:
du = duIcode.du; du = duIcode.du;
break; break;
case NONE: case NONE:
assert(false); assert(false);
break; break;
} }
} }
@ -114,7 +118,7 @@ void ICODE::copyDU(const ICODE &duIcode, operDu _du, operDu duDu)
/* Returns a unary conditional expression node. This procedure should /* Returns a unary conditional expression node. This procedure should
* only be used with the following conditional node types: NEGATION, * only be used with the following conditional node types: NEGATION,
* ADDRESSOF, DEREFERENCE, POST_INC, POST_DEC, PRE_INC, PRE_DEC */ * ADDRESSOF, DEREFERENCE, POST_INC, POST_DEC, PRE_INC, PRE_DEC */
/* Returns an identifier conditional expression node of type GLOB_VAR */ /* Returns an identifier conditional expression node of type GLOB_VAR */
@ -124,7 +128,7 @@ GlobalVariable::GlobalVariable(int16_t segValue, int16_t off)
valid = true; valid = true;
ident.idType = GLOB_VAR; ident.idType = GLOB_VAR;
adr = opAdr(segValue, off); adr = opAdr(segValue, off);
auto i=Project::get()->getSymIdxByAdd(adr); auto i=Project::get()->getSymIdxByAddr(adr);
if ( not Project::get()->validSymIdx(i) ) if ( not Project::get()->validSymIdx(i) )
{ {
printf ("Error, glob var not found in symtab\n"); 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 QString GlobalVariable::walkCondExpr(Function *, int *) const
{ {
if(valid) if(valid)
return Project::get()->symtab[globIdx].name; return Project::get()->symbolName(globIdx);
return "INVALID GlobalVariable"; return "INVALID GlobalVariable";
} }
@ -164,7 +168,7 @@ AstIdent *AstIdent::Loc(int off, LOCAL_ID *localId)
AstIdent *AstIdent::Param(int off, const STKFRAME * argSymtab) AstIdent *AstIdent::Param(int off, const STKFRAME * argSymtab)
{ {
AstIdent *newExp; AstIdent *newExp;
newExp = new AstIdent(); newExp = new AstIdent();
newExp->ident.idType = PARAM; newExp->ident.idType = PARAM;
auto iter=argSymtab->findByLabel(off); auto iter=argSymtab->findByLabel(off);
@ -222,7 +226,7 @@ AstIdent *AstIdent::Long(LOCAL_ID *localId, opLoc sd, iICODE pIcode, hlFirst f,
{ {
AstIdent *newExp; AstIdent *newExp;
/* Check for long constant and save it as a constant expression */ /* Check for long constant and save it as a constant expression */
if ((sd == SRC) and pIcode->ll()->srcIsImmed()) /* constant */ if ((sd == SRC) and pIcode->ll()->testFlags(I)) /* constant */
{ {
int value; int value;
if (f == HIGH_FIRST) if (f == HIGH_FIRST)
@ -256,29 +260,29 @@ AstIdent *AstIdent::Other(eReg seg, eReg regi, int16_t off)
/* Returns an identifier conditional expression node of type TYPE_LONG or /* Returns an identifier conditional expression node of type TYPE_LONG or
* TYPE_WORD_SIGN */ * TYPE_WORD_SIGN */
AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_) AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_)
{ {
int idx;
AstIdent *newExp=nullptr; AstIdent *newExp=nullptr;
switch(retVal->type) switch(retVal->type)
{ {
case TYPE_LONG_SIGN: case TYPE_LONG_SIGN:
{ {
newExp = new AstIdent(); 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.idType = LONG_VAR;
newExp->ident.idNode.longIdx = idx; newExp->ident.idNode.longIdx = idx;
break; break;
} }
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),WORD_REG,locsym); case TYPE_WORD_SIGN:
break; newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),WORD_REG,locsym);
case TYPE_BYTE_SIGN: break;
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),BYTE_REG,locsym); case TYPE_BYTE_SIGN:
break; newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),BYTE_REG,locsym);
default: break;
fprintf(stderr,"AstIdent::idID unhandled type %d\n",retVal->type); default:
fprintf(stderr,"AstIdent::idID unhandled type %d\n",retVal->type);
} }
return (newExp); return (newExp);
} }
@ -292,11 +296,11 @@ AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_)
Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_,ICODE &duIcode, operDu du) Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_,ICODE &duIcode, operDu du)
{ {
Expr *newExp; Expr *newExp;
int idx; /* idx into pIcode->localId table */ int idx; /* idx into pIcode->localId table */
const LLOperand &pm(*ll_insn.get(sd)); const LLOperand &pm(*ll_insn.get(sd));
if ( ((sd == DST) and ll_insn.testFlags(IM_DST)) or if ( ((sd == DST) and ll_insn.testFlags(IM_DST)) or
((sd == SRC) and ll_insn.testFlags(IM_SRC)) or ((sd == SRC) and ll_insn.testFlags(IM_SRC)) or
(sd == LHS_OP)) /* for MUL lhs */ (sd == LHS_OP)) /* for MUL lhs */
@ -306,14 +310,14 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
duIcode.setRegDU (rDX, du); duIcode.setRegDU (rDX, du);
duIcode.setRegDU (rAX, du); duIcode.setRegDU (rAX, du);
} }
else if ((sd == DST) and ll_insn.testFlags(IM_TMP_DST)) else if ((sd == DST) and ll_insn.testFlags(IM_TMP_DST))
{ /* implicit tmp */ { /* implicit tmp */
newExp = new RegisterNode(LLOperand(rTMP,2), &pProc->localId); newExp = new RegisterNode(LLOperand(rTMP,2), &pProc->localId);
duIcode.setRegDU(rTMP, (operDu)eUSE); 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); newExp = new Constant(ll_insn.src().getImm2(), 2);
else if (pm.regi == rUNDEF) /* global variable */ else if (pm.regi == rUNDEF) /* global variable */
newExp = new GlobalVariable(pm.segValue, pm.off); newExp = new GlobalVariable(pm.segValue, pm.off);
@ -323,7 +327,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
newExp = new RegisterNode(pm, &pProc->localId); newExp = new RegisterNode(pm, &pProc->localId);
duIcode.setRegDU( pm.regi, du); duIcode.setRegDU( pm.regi, du);
} }
else if (pm.off) /* offset */ else if (pm.off) /* offset */
{ // TODO: this is ABI specific, should be actually based on Function calling conv { // TODO: this is ABI specific, should be actually based on Function calling conv
if ((pm.seg == rSS) and (pm.regi == INDEX_BP)) /* idx on bp */ if ((pm.seg == rSS) and (pm.regi == INDEX_BP)) /* idx on bp */
@ -345,20 +349,19 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
newExp = AstIdent::Other (pm.seg, pm.regi, pm.off); newExp = AstIdent::Other (pm.seg, pm.regi, pm.off);
/**** check long ops, indexed global var *****/ /**** check long ops, indexed global var *****/
} }
else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */ else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */
{ {
if ((pm.seg == rDS) and (pm.regi > INDEX_BP_DI)) /* dereference */ if ((pm.seg == rDS) and (pm.regi > INDEX_BP_DI)) /* dereference */
{ {
eReg selected; eReg selected;
switch (pm.regi) { switch (pm.regi) {
case INDEX_SI: selected = rSI; break; case INDEX_SI: selected = rSI; break;
case INDEX_DI: selected = rDI; break; case INDEX_DI: selected = rDI; break;
case INDEX_BP: selected = rBP; break; case INDEX_BP: selected = rBP; break;
case INDEX_BX: selected = rBX; break; case INDEX_BX: selected = rBX; break;
default: default:
newExp = nullptr; newExp = nullptr;
assert(false); assert(false);
} }
//NOTICE: was selected, 0 //NOTICE: was selected, 0
newExp = new RegisterNode(LLOperand(selected, 0), &pProc->localId); newExp = new RegisterNode(LLOperand(selected, 0), &pProc->localId);
@ -368,7 +371,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
else else
newExp = AstIdent::Other (pm.seg, pm.regi, 0); newExp = AstIdent::Other (pm.seg, pm.regi, 0);
} }
return (newExp); return newExp;
} }
@ -376,35 +379,32 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
condId LLInst::idType(opLoc sd) const condId LLInst::idType(opLoc sd) const
{ {
const LLOperand &pm((sd == SRC) ? src() : m_dst); const LLOperand &pm((sd == SRC) ? src() : m_dst);
if ((sd == SRC) and srcIsImmed()) if ((sd == SRC) and testFlags(I))
return (CONSTANT); return CONSTANT;
else if (pm.regi == 0) else if (pm.regi == 0)
return (GLOB_VAR); return GLOB_VAR;
else if ( pm.isReg() ) else if ( pm.isReg() )
return (REGISTER); return REGISTER;
else if ((pm.seg == rSS) and (pm.regi == INDEX_BP)) 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 ? //TODO: which pm.seg/pm.regi pairs should produce PARAM/LOCAL_VAR ?
if (pm.off >= 0) if (pm.off >= 0)
return (PARAM); return PARAM;
else return LOCAL_VAR;
return (LOCAL_VAR);
} }
else 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 int Expr::hlTypeSize(Function * pproc) const
{ {
if (this == nullptr) if (this == nullptr)
return (2); /* for TYPE_UNKNOWN */ return 2; /* for TYPE_UNKNOWN */
fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type); fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type);
return 2; // CC: is this correct? return 2; // CC: is this correct?
} }
/* Returns the type of the expression */ /* Returns the type of the expression */
@ -429,22 +429,22 @@ int AstIdent::hlTypeSize(Function *pproc) const
{ {
switch (ident.idType) switch (ident.idType)
{ {
case GLOB_VAR: case GLOB_VAR:
assert(false); assert(false);
return 1; return 1;
case LOCAL_VAR: case LOCAL_VAR:
return (hlSize[pproc->localId.id_arr[ident.idNode.localIdx].type]); return (hlSize[pproc->localId.id_arr[ident.idNode.localIdx].type]);
case PARAM: case PARAM:
return (hlSize[pproc->args[ident.idNode.paramIdx].type]); return (hlSize[pproc->args[ident.idNode.paramIdx].type]);
case STRING: case STRING:
return (2); return 2;
case LONG_VAR: case LONG_VAR:
return (4); return 4;
case OTHER: case OTHER:
return (2); return 2;
default: default:
assert(false); assert(false);
return -1; return -1;
} /* eos */ } /* eos */
} }
hlType BinaryOperator::expType(Function *pproc) const hlType BinaryOperator::expType(Function *pproc) const
@ -478,24 +478,24 @@ hlType AstIdent::expType(Function *pproc) const
{ {
switch (ident.idType) switch (ident.idType)
{ {
case UNDEF: case UNDEF:
case CONSTANT: case CONSTANT:
case FUNCTION: case FUNCTION:
case REGISTER: case REGISTER:
case GLOB_VAR: case GLOB_VAR:
case GLOB_VAR_IDX: case GLOB_VAR_IDX:
assert(false); assert(false);
return TYPE_UNKNOWN; return TYPE_UNKNOWN;
case LOCAL_VAR: case LOCAL_VAR:
return (pproc->localId.id_arr[ident.idNode.localIdx].type); return (pproc->localId.id_arr[ident.idNode.localIdx].type);
case PARAM: case PARAM:
return (pproc->args[ident.idNode.paramIdx].type); return (pproc->args[ident.idNode.paramIdx].type);
case STRING: case STRING:
return (TYPE_STR); return (TYPE_STR);
case LONG_VAR: case LONG_VAR:
return (pproc->localId.id_arr[ident.idNode.longIdx].type); return (pproc->localId.id_arr[ident.idNode.longIdx].type);
default: default:
return (TYPE_UNKNOWN); return (TYPE_UNKNOWN);
} /* eos */ } /* eos */
return (TYPE_UNKNOWN); return (TYPE_UNKNOWN);
} }
@ -508,17 +508,17 @@ hlType AstIdent::expType(Function *pproc) const
Expr * HlTypeSupport::performLongRemoval (eReg regi, LOCAL_ID *locId, Expr *tree) Expr * HlTypeSupport::performLongRemoval (eReg regi, LOCAL_ID *locId, Expr *tree)
{ {
switch (tree->m_type) { switch (tree->m_type) {
case BOOLEAN_OP: case BOOLEAN_OP:
case POST_INC: case POST_DEC: case POST_INC: case POST_DEC:
case PRE_INC: case PRE_DEC: case PRE_INC: case PRE_DEC:
case NEGATION: case ADDRESSOF: case NEGATION: case ADDRESSOF:
case DEREFERENCE: case DEREFERENCE:
case IDENTIFIER: case IDENTIFIER:
return tree->performLongRemoval(regi,locId); return tree->performLongRemoval(regi,locId);
break; break;
default: default:
fprintf(stderr,"performLongRemoval attemped on %d\n",tree->m_type); fprintf(stderr,"performLongRemoval attemped on %d\n",tree->m_type);
break; break;
} }
return tree; return tree;
} }
@ -529,7 +529,7 @@ static QString getString (int offset)
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
QString o; QString o;
int strLen, i; int strLen, i;
strLen = strSize (&prog.image()[offset], '\0'); strLen = strSize (&prog.image()[offset], '\0');
o += '"'; o += '"';
for (i = 0; i < strLen; i++) for (i = 0; i < strLen; i++)
@ -540,7 +540,7 @@ static QString getString (int offset)
QString BinaryOperator::walkCondExpr(Function * pProc, int* numLoc) const QString BinaryOperator::walkCondExpr(Function * pProc, int* numLoc) const
{ {
assert(rhs()); assert(rhs());
return QString("(%1%2%3)") return QString("(%1%2%3)")
.arg((m_op!=NOT) ? lhs()->walkCondExpr(pProc, numLoc) : "") .arg((m_op!=NOT) ? lhs()->walkCondExpr(pProc, numLoc) : "")
.arg(condOpSym[m_op]) .arg(condOpSym[m_op])
@ -554,67 +554,71 @@ QString AstIdent::walkCondExpr(Function *pProc, int *numLoc) const
STKSYM * psym; /* Pointer to argument in the stack */ STKSYM * psym; /* Pointer to argument in the stack */
QString codeContents; QString codeContents;
QString collectedContents; QString collectedContents;
QTextStream codeOut(&codeContents); QTextStream codeOut(&codeContents);
QTextStream o(&collectedContents); QTextStream o(&collectedContents);
switch (ident.idType) switch (ident.idType)
{ {
case LOCAL_VAR: case LOCAL_VAR:
o << pProc->localId.id_arr[ident.idNode.localIdx].name; o << pProc->localId.id_arr[ident.idNode.localIdx].name;
break; break;
case PARAM: case PARAM:
psym = &pProc->args[ident.idNode.paramIdx]; psym = &pProc->args[ident.idNode.paramIdx];
if (psym->hasMacro) if (psym->hasMacro)
o << psym->macro<<"("<<psym->name<< ")"; o << psym->macro<<"("<<psym->name<< ")";
else else
o << psym->name; o << psym->name;
break; break;
case STRING: case STRING:
o << getString (ident.idNode.strIdx); o << getString (ident.idNode.strIdx);
break; break;
case LONG_VAR: case LONG_VAR:
id = &pProc->localId.id_arr[ident.idNode.longIdx]; id = &pProc->localId.id_arr[ident.idNode.longIdx];
if (id->name[0] != '\0') /* STK_FRAME & REG w/name*/ if (id->name[0] != '\0') /* STK_FRAME & REG w/name*/
o << id->name; o << id->name;
else if (id->loc == REG_FRAME) else if (id->loc == REG_FRAME)
{ {
id->setLocalName(++(*numLoc)); id->setLocalName(++(*numLoc));
codeOut <<TypeContainer::typeName(id->type)<< " "<<id->name<<"; "; codeOut <<TypeContainer::typeName(id->type)<< " "<<id->name<<"; ";
codeOut <<"/* "<<Machine_X86::regName(id->longId().h()) << ":" << codeOut <<"/* "<<Machine_X86::regName(id->longId().h()) << ":" <<
Machine_X86::regName(id->longId().l()) << " */\n"; Machine_X86::regName(id->longId().l()) << " */\n";
o << id->name; o << id->name;
pProc->localId.propLongId (id->longId().l(),id->longId().h(), id->name); pProc->localId.propLongId (id->longId().l(),id->longId().h(), id->name);
} }
else /* GLB_FRAME */ else /* GLB_FRAME */
{ {
if (id->id.longGlb.regi == 0) /* not indexed */ if (id->id.longGlb.regi == 0) /* not indexed */
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"]"; o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"]";
else if (id->id.longGlb.regi == rBX) else if (id->id.longGlb.regi == rBX)
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"][bx]"; o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"][bx]";
} else {
break; qCritical() << "AstIdent::walkCondExpr unhandled LONG_VAR in GLB_FRAME";
case OTHER: assert(false);
off = ident.idNode.other.off; }
o << Machine_X86::regName(ident.idNode.other.seg)<< "["; }
o << Machine_X86::regName(ident.idNode.other.regi); break;
if (off < 0) case OTHER:
o << "-"<< hexStr (-off); off = ident.idNode.other.off;
else if (off>0) o << Machine_X86::regName(ident.idNode.other.seg)<< "[";
o << "+"<< hexStr (off); o << Machine_X86::regName(ident.idNode.other.regi);
o << "]"; if (off < 0)
break; o << "-"<< hexStr (-off);
default: else if (off>0)
assert(false); o << "+"<< hexStr (off);
return ""; o << "]";
break;
default:
assert(false);
return "";
} /* eos */ } /* eos */
cCode.appendDecl(codeContents); cCode.appendDecl(codeContents);
return collectedContents; return collectedContents;
} }
QString UnaryOperator::wrapUnary(Function *pProc, int *numLoc,QChar op) const QString UnaryOperator::wrapUnary(Function *pProc, int *numLoc,QChar op) const
{ {
@ -632,33 +636,33 @@ QString UnaryOperator::walkCondExpr(Function *pProc, int *numLoc) const
QString outStr; QString outStr;
switch(m_type) switch(m_type)
{ {
case NEGATION: case NEGATION:
outStr+=wrapUnary(pProc,numLoc,'!'); outStr+=wrapUnary(pProc,numLoc,'!');
break; break;
case ADDRESSOF: case ADDRESSOF:
outStr+=wrapUnary(pProc,numLoc,'&'); outStr+=wrapUnary(pProc,numLoc,'&');
break; break;
case DEREFERENCE: case DEREFERENCE:
outStr+=wrapUnary(pProc,numLoc,'*'); outStr+=wrapUnary(pProc,numLoc,'*');
break; break;
case POST_INC: case POST_INC:
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "++"; outStr += unaryExp->walkCondExpr (pProc, numLoc) + "++";
break; break;
case POST_DEC: case POST_DEC:
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "--"; outStr += unaryExp->walkCondExpr (pProc, numLoc) + "--";
break; break;
case PRE_INC: case PRE_INC:
outStr += "++" + unaryExp->walkCondExpr (pProc, numLoc); outStr += "++" + unaryExp->walkCondExpr (pProc, numLoc);
break; break;
case PRE_DEC: case PRE_DEC:
outStr += "--" + unaryExp->walkCondExpr (pProc, numLoc); outStr += "--" + unaryExp->walkCondExpr (pProc, numLoc);
break; break;
} }
return outStr; return outStr;
} }
@ -666,9 +670,6 @@ QString UnaryOperator::walkCondExpr(Function *pProc, int *numLoc) const
/* Walks the conditional expression tree and returns the result on a string */ /* Walks the conditional expression tree and returns the result on a string */
/* Changes the boolean conditional operator at the root of this expression */ /* Changes the boolean conditional operator at the root of this expression */
void BinaryOperator::changeBoolOp (condOp newOp) void BinaryOperator::changeBoolOp (condOp newOp)
{ {
@ -690,7 +691,7 @@ bool Expr::insertSubTreeReg (AstIdent *&tree, Expr *_expr, eReg regi,const LOCAL
* register regi */ * register regi */
bool Expr::insertSubTreeReg (Expr *&tree, Expr *_expr, eReg regi,const LOCAL_ID *locsym) bool Expr::insertSubTreeReg (Expr *&tree, Expr *_expr, eReg regi,const LOCAL_ID *locsym)
{ {
if (tree == nullptr) if (tree == nullptr)
return false; return false;
Expr *temp=tree->insertSubTreeReg(_expr,regi,locsym); Expr *temp=tree->insertSubTreeReg(_expr,regi,locsym);
@ -705,20 +706,20 @@ bool Expr::insertSubTreeReg (Expr *&tree, Expr *_expr, eReg regi,const LOCAL_ID
Expr *UnaryOperator::insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym) Expr *UnaryOperator::insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym)
{ {
Expr *temp; Expr *temp;
switch (m_type) { switch (m_type) {
case NEGATION: case NEGATION:
case ADDRESSOF: case ADDRESSOF:
case DEREFERENCE: case DEREFERENCE:
temp = unaryExp->insertSubTreeReg( _expr, regi, locsym); temp = unaryExp->insertSubTreeReg( _expr, regi, locsym);
if (nullptr!=temp) if (nullptr!=temp)
{ {
unaryExp = temp; unaryExp = temp;
return this; return this;
} }
return nullptr; return nullptr;
default: default:
fprintf(stderr,"insertSubTreeReg attempt on unhandled type %d\n",m_type); fprintf(stderr,"insertSubTreeReg attempt on unhandled type %d\n",m_type);
} }
return nullptr; return nullptr;
} }
@ -799,9 +800,8 @@ Expr *BinaryOperator::insertSubTreeLongReg(Expr *_expr, int longIdx)
Expr *AstIdent::insertSubTreeLongReg(Expr *_expr, int longIdx) Expr *AstIdent::insertSubTreeLongReg(Expr *_expr, int longIdx)
{ {
if (ident.idNode.longIdx == longIdx) if (ident.idNode.longIdx == longIdx)
{
return _expr; return _expr;
}
return nullptr; return nullptr;
} }
@ -817,67 +817,51 @@ Expr *BinaryOperator::clone() const
Expr *BinaryOperator::inverse() 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, LESS_EQUAL, LESS, DUMMY,DUMMY,DUMMY,DUMMY,
DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY,
DUMMY, DBL_OR, DBL_AND}; DUMMY, DBL_OR, DBL_AND};
BinaryOperator *res=reinterpret_cast<BinaryOperator *>(this->clone()); BinaryOperator *res=reinterpret_cast<BinaryOperator *>(this->clone());
switch (m_op) switch (m_op)
{ {
case LESS_EQUAL: case LESS: case EQUAL: case LESS_EQUAL: case LESS: case EQUAL:
case NOT_EQUAL: case GREATER: case GREATER_EQUAL: case NOT_EQUAL: case GREATER: case GREATER_EQUAL:
res->m_op = invCondOp[m_op]; res->m_op = invCondOp[m_op];
return res; return res;
case AND: case OR: case XOR: case NOT: case ADD: case AND: case OR: case XOR: case NOT: case ADD:
case SUB: case MUL: case DIV: case SHR: case SHL: case MOD: case SUB: case MUL: case DIV: case SHR: case SHL: case MOD:
return UnaryOperator::Create(NEGATION, res); return UnaryOperator::Create(NEGATION, res);
case DBL_AND: case DBL_OR: case DBL_AND: case DBL_OR:
res->m_op = invCondOp[m_op]; res->m_op = invCondOp[m_op];
res->m_lhs=m_lhs->inverse (); res->m_lhs=m_lhs->inverse ();
res->m_rhs=m_rhs->inverse (); res->m_rhs=m_rhs->inverse ();
return res; return res;
default: default:
fprintf(stderr,"BinaryOperator::inverse attempt on unhandled op %d\n",m_op); fprintf(stderr,"BinaryOperator::inverse attempt on unhandled op %d\n",m_op);
} /* eos */ } /* eos */
assert(false); assert(false);
return res; return res;
} }
Expr *AstIdent::performLongRemoval(eReg regi, LOCAL_ID *locId) Expr *AstIdent::performLongRemoval(eReg regi, LOCAL_ID *locId)
{ {
eReg otherRegi; /* high or low part of long register */ eReg otherRegi; /* high or low part of long register */
if (ident.idType == LONG_VAR) if (ident.idType != LONG_VAR)
{ return this;
otherRegi = otherLongRegi (regi, ident.idNode.longIdx, locId); otherRegi = locId->getPairedRegisterAt(ident.idNode.longIdx,regi);
delete this; bool long_was_signed = locId->id_arr[ident.idNode.longIdx].isSigned();
return new RegisterNode(locId->newByteWordReg(TYPE_WORD_SIGN,otherRegi),WORD_REG,locId); delete this;
} return new RegisterNode(locId->newByteWordReg(long_was_signed ? TYPE_WORD_SIGN : TYPE_WORD_UNSIGN,otherRegi),WORD_REG,locId);
return this;
} }
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 QString Constant::walkCondExpr(Function *, int *) const
{ {
if (kte.kte < 1000) if (kte.kte < 1000)
return QString::number(kte.kte); return QString::number(kte.kte);
else return "0x" + QString::number(kte.kte,16);
return "0x" + QString::number(kte.kte,16);
} }
int Constant::hlTypeSize(Function *) const int Constant::hlTypeSize(Function *) const
@ -885,11 +869,6 @@ int Constant::hlTypeSize(Function *) const
return kte.size; return kte.size;
} }
hlType Constant::expType(Function *pproc) const
{
return TYPE_CONST;
}
QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
{ {
return pProc->writeCall(call.proc,*call.args, numLoc); 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 int FuncNode::hlTypeSize(Function *) const
{ {
return hlSize[call.proc->getReturnType()]; return hlSize[call.proc->retVal.type];
} }
hlType FuncNode::expType(Function *) const hlType FuncNode::expType(Function *) const
{ {
return call.proc->getReturnType(); return call.proc->retVal.type;
} }

View File

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

File diff suppressed because it is too large Load Diff

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

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

View File

@ -7,27 +7,29 @@
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include <boost/range/algorithm.hpp> #include <boost/range/algorithm.hpp>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <cassert>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
namespace {
typedef std::list<int> nodeList; /* dfsLast index to the node */ typedef std::list<int> nodeList; /* dfsLast index to the node */
#define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum))
/* there is a path on the DFST from a to b if the a was first visited in a /* there is a path on the DFST from a to b if the a was first visited in a
* dfs, and a was later visited than b when doing the last visit of each * dfs, and a was later visited than b when doing the last visit of each
* node. */ * node. */
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, * during the dfs traversal (ie. s has a smaller dfsFirst number) or s == p,
* then it is a backedge. * then it is a backedge.
* Also incrementes the number of backedges entries to the header node. */ * 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) 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 */ * 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) if (currImmDom == NO_DOM)
return (predImmDom); return (predImmDom);
@ -57,67 +59,44 @@ static int commonDom (int currImmDom, int predImmDom, Function * pProc)
} }
return (currImmDom); 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) /* Returns whether or not the node n (dfsLast numbering of a basic block)
* is on the list l. */ * 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(); 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. */ /* 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(); 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). /* Finds the follow of the endless loop headed at node head (if any).
* The follow node is the closest node to the loop. */ * 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; head->loopFollow = MAX;
for( int loop_node : loopNodes) 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; int succ = typeaddr.BBptr->dfsLastNum;
if ((not inList(loopNodes, succ)) and (succ < head->loopFollow)) if ((not inList(loopNodes, succ)) and (succ < head->loopFollow))
@ -130,34 +109,34 @@ static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
//static void findNodesInLoop(BB * latchNode,BB * head,PPROC pProc,queue *intNodes) //static void findNodesInLoop(BB * latchNode,BB * head,PPROC pProc,queue *intNodes)
/* Flags nodes that belong to the loop determined by (latchNode, head) and /* Flags nodes that belong to the loop determined by (latchNode, head) and
* determines the type of loop. */ * 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; int i, headDfsNum, intNodeType;
nodeList loopNodes; nodeList loopNodes;
int immedDom, /* dfsLast index to immediate dominator */ int immedDom, /* dfsLast index to immediate dominator */
thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */ thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */
BB * pbb; BB * pbb;
/* Flag nodes in loop headed by head (except header node) */ /* Flag nodes in loop headed by head (except header node) */
headDfsNum = head->dfsLastNum; headDfsNum = head->dfsLastNum;
head->loopHead = headDfsNum; head->loopHead = headDfsNum;
insertList (loopNodes, headDfsNum); loopNodes.push_back(headDfsNum);
for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++) for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++)
{ {
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */ if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
continue; continue;
immedDom = pProc->m_dfsLast[i]->immedDom; immedDom = pProc->m_dfsLast[i]->immedDom;
if (inList (loopNodes, immedDom) and inInt(pProc->m_dfsLast[i], intNodes)) 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*/ if (pProc->m_dfsLast[i]->loopHead == NO_NODE)/*not in other loop*/
pProc->m_dfsLast[i]->loopHead = headDfsNum; pProc->m_dfsLast[i]->loopHead = headDfsNum;
} }
} }
latchNode->loopHead = headDfsNum; latchNode->loopHead = headDfsNum;
if (latchNode != head) if (latchNode != head)
insertList (loopNodes, latchNode->dfsLastNum); loopNodes.push_back(latchNode->dfsLastNum);
/* Determine type of loop and follow node */ /* Determine type of loop and follow node */
intNodeType = head->nodeType; intNodeType = head->nodeType;
@ -192,7 +171,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum; head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum;
latchNode->back().ll()->setFlags(JX_LOOP); latchNode->back().ll()->setFlags(JX_LOOP);
} }
else /* latch = 1-way */ else /* latch = 1-way */
if (latchNode->nodeType == LOOP_NODE) if (latchNode->nodeType == LOOP_NODE)
{ {
head->loopType = eNodeHeaderType::REPEAT_TYPE; head->loopType = eNodeHeaderType::REPEAT_TYPE;
@ -218,7 +197,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
} }
/* Check if couldn't find it, then it is a strangely formed /* Check if couldn't find it, then it is a strangely formed
* loop, so it is safer to consider it an endless loop */ * loop, so it is safer to consider it an endless loop */
if (pbb->dfsLastNum <= head->dfsLastNum) if (pbb->dfsLastNum <= head->dfsLastNum)
{ {
head->loopType = eNodeHeaderType::ENDLESS_TYPE; head->loopType = eNodeHeaderType::ENDLESS_TYPE;
@ -228,7 +207,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
pbb = pProc->m_dfsLast[pbb->immedDom]; pbb = pProc->m_dfsLast[pbb->immedDom];
} }
if (pbb->dfsLastNum > head->dfsLastNum) if (pbb->dfsLastNum > head->dfsLastNum)
pProc->m_dfsLast[head->loopFollow]->loopHead = NO_NODE; /*****/ pProc->m_dfsLast[head->loopFollow]->loopHead = NO_NODE; /*****/
head->back().ll()->setFlags(JX_LOOP); head->back().ll()->setFlags(JX_LOOP);
} }
else else
@ -237,49 +216,95 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
findEndlessFollow (pProc, loopNodes, head); findEndlessFollow (pProc, loopNodes, head);
} }
freeList(loopNodes); loopNodes.clear();
} }
/** \returns whether the BB indexed by s is a successor of the BB indexed by \arg h
//static void findNodesInInt (queue **intNodes, int level, interval *Ii) * \note that h is a case node.
/* Recursive procedure to find nodes that belong to the interval (ie. nodes */
* from G1). */ bool successor (int s, int h, Function * pProc)
static void findNodesInInt (queue &intNodes, int level, interval *Ii)
{ {
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++)
{
currNode = m_dfsLast[currIdx];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue;
for (BB * inedge : currNode->inEdges)
{ {
findNodesInInt(intNodes,level-1,en->correspInt); 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) void Function::structLoops(derSeq *derivedG)
{ {
interval *Ii; interval *Ii;
BB * intHead, /* interval header node */ BB * intHead, /* interval header node */
* pred, /* predecessor node */ * pred, /* predecessor node */
* latchNode;/* latching node (in case of loops) */ * latchNode;/* latching node (in case of loops) */
size_t level = 0; /* derived sequence level */ size_t level = 0; /* derived sequence level */
interval *initInt; /* initial interval */ interval *initInt; /* initial interval */
queue intNodes; /* list of interval nodes */ queue intNodes; /* list of interval nodes */
/* Structure loops */ /* Structure loops */
/* for all derived sequences Gi */ /* for all derived sequences Gi */
for(auto & elem : *derivedG) for(auto & elem : *derivedG)
{ {
level++; level++;
Ii = elem.Ii; for (Ii = elem.Ii; Ii!=nullptr; Ii = Ii->next) /* for all intervals Ii of Gi */
while (Ii) /* for all intervals Ii of Gi */
{ {
latchNode = nullptr; latchNode = nullptr;
intNodes.clear(); intNodes.clear();
@ -321,45 +346,6 @@ void Function::structLoops(derSeq *derivedG)
latchNode->flg |= IS_LATCH_NODE; 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);
} }
} }
} }
@ -369,7 +355,7 @@ static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
* has a case node. */ * has a case node. */
void Function::structCases() void Function::structCases()
{ {
int exitNode = NO_NODE; /* case exit node */ int exitNode = NO_NODE; /* case exit node */
nodeList caseNodes; /* temporary: list of nodes in case */ nodeList caseNodes; /* temporary: list of nodes in case */
/* Linear scan of the nodes in reverse dfsLast order, searching for /* Linear scan of the nodes in reverse dfsLast order, searching for
@ -387,9 +373,7 @@ void Function::structCases()
if ((not successor(j, i, this)) and (m_dfsLast[j]->immedDom == i)) if ((not successor(j, i, this)) and (m_dfsLast[j]->immedDom == i))
{ {
if (exitNode == NO_NODE) if (exitNode == NO_NODE)
{
exitNode = j; exitNode = j;
}
else if (m_dfsLast[exitNode]->inEdges.size() < m_dfsLast[j]->inEdges.size()) else if (m_dfsLast[exitNode]->inEdges.size() < m_dfsLast[j]->inEdges.size())
exitNode = j; exitNode = j;
} }
@ -398,7 +382,7 @@ void Function::structCases()
/* Tag nodes that belong to the case by recording the /* Tag nodes that belong to the case by recording the
* header field with caseHeader. */ * header field with caseHeader. */
insertList (caseNodes, i); caseNodes.push_back(i);
m_dfsLast[i]->caseHead = i; m_dfsLast[i]->caseHead = i;
for(TYPEADR_TYPE &pb : caseHeader->edges) for(TYPEADR_TYPE &pb : caseHeader->edges)
{ {
@ -411,38 +395,24 @@ 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 */ /* Structures if statements */
void Function::structIfs () void Function::structIfs ()
{ {
size_t followInEdges; /* Largest # in-edges so far */ size_t followInEdges; /* Largest # in-edges so far */
int curr, /* Index for linear scan of nodes */ int curr, /* Index for linear scan of nodes */
/*desc,*/ /* Index for descendant */ /*desc,*/ /* Index for descendant */
follow; /* Possible follow node */ follow; /* Possible follow node */
nodeList domDesc, /* List of nodes dominated by curr */ nodeList domDesc, /* List of nodes dominated by curr */
unresolved /* List of unresolved if nodes */ unresolved /* List of unresolved if nodes */
; ;
BB * currNode, /* Pointer to current node */ BB * currNode, /* Pointer to current node */
* pbb; * pbb;
/* Linear scan of nodes in reverse dfsLast order */ /* Linear scan of nodes in reverse dfsLast order */
for (curr = numBBs - 1; curr >= 0; curr--) for (curr = numBBs - 1; curr >= 0; curr--)
{ {
currNode = m_dfsLast[curr]; currNode = m_dfsLast[curr];
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */ if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
continue; continue;
if ((currNode->nodeType == TWO_BRANCH) and (not currNode->back().ll()->testFlags(JX_LOOP))) if ((currNode->nodeType == TWO_BRANCH) and (not currNode->back().ll()->testFlags(JX_LOOP)))
@ -455,7 +425,7 @@ void Function::structIfs ()
{ {
if (m_dfsLast[desc]->immedDom == curr) if (m_dfsLast[desc]->immedDom == curr)
{ {
insertList (domDesc, desc); domDesc.push_back(desc);
pbb = m_dfsLast[desc]; pbb = m_dfsLast[desc];
if ((pbb->inEdges.size() - pbb->numBackEdges) >= followInEdges) if ((pbb->inEdges.size() - pbb->numBackEdges) >= followInEdges)
{ {
@ -474,9 +444,9 @@ void Function::structIfs ()
flagNodes (unresolved, follow, this); flagNodes (unresolved, follow, this);
} }
else else
insertList (unresolved, curr); unresolved.push_back(curr);
} }
freeList (domDesc); domDesc.clear();
} }
} }
bool Function::removeInEdge_Flag_and_ProcessLatch(BB *pbb,BB *a,BB *b) 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) void Function::structure(derSeq *derivedG)
{ {
/* Find immediate dominators of the graph */ /* Find immediate dominators of the graph */

View File

@ -22,6 +22,9 @@
using namespace boost; using namespace boost;
using namespace boost::adaptors; using namespace boost::adaptors;
using namespace std;
namespace
{
struct ExpStack struct ExpStack
{ {
Function *func; 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 * Expression stack functions
**************************************************************************/ **************************************************************************/
@ -92,8 +146,6 @@ bool ExpStack::empty()
return expStk.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 /* Returns the index of the local variable or parameter at offset off, if it
* is in the stack frame provided. */ * 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 */ /* Eliminates all condition codes and generates new hlIcode instructions */
void Function::elimCondCodes () void Function::elimCondCodes ()
{ {
@ -196,7 +226,7 @@ void Function::elimCondCodes ()
notSup = true; notSup = true;
std::cout << hex<<defIcode.loc_ip; std::cout << hex<<defIcode.loc_ip;
reportError (JX_NOT_DEF, defIcode.ll()->getOpcode()); reportError (JX_NOT_DEF, defIcode.ll()->getOpcode());
flg |= PROC_ASM; /* generate asm */ flg |= PROC_ASM; /* generate asm */
} }
if (not notSup) if (not notSup)
{ {
@ -224,7 +254,7 @@ void Function::elimCondCodes ()
ICODE &a(*defAt); ICODE &a(*defAt);
ICODE &b(*useAt); ICODE &b(*useAt);
reportError (NOT_DEF_USE,a.ll()->label,a.ll()->getOpcode(),b.ll()->getOpcode()); reportError (NOT_DEF_USE,a.ll()->label,a.ll()->getOpcode(),b.ll()->getOpcode());
flg |= PROC_ASM; /* generate asm */ flg |= PROC_ASM; /* generate asm */
} }
break; break;
} }
@ -269,7 +299,7 @@ void Function::genLiveKtes ()
def.reset(); def.reset();
pbb = m_dfsLast[i]; pbb = m_dfsLast[i];
if (pbb->flg & INVALID_BB) if (pbb->flg & INVALID_BB)
continue; // skip invalid BBs continue; // skip invalid BBs
for(ICODE &insn : *pbb) for(ICODE &insn : *pbb)
{ {
if ((insn.type == HIGH_LEVEL_ICODE) and ( insn.valid() )) if ((insn.type == HIGH_LEVEL_ICODE) and ( insn.valid() ))
@ -295,9 +325,9 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
Function * pcallee; /* invoked subroutine */ Function * pcallee; /* invoked subroutine */
//ICODE *ticode /* icode that invokes a subroutine */ //ICODE *ticode /* icode that invokes a subroutine */
; ;
LivenessSet prevLiveOut, /* previous live out */ LivenessSet prevLiveOut, /* previous live out */
prevLiveIn; /* previous live in */ prevLiveIn; /* previous live in */
bool change; /* is there change in the live sets?*/ bool change; /* is there change in the live sets?*/
/* liveOut for this procedure */ /* liveOut for this procedure */
liveOut = in_liveOut; liveOut = in_liveOut;
@ -322,12 +352,12 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
pbb->liveOut = in_liveOut; pbb->liveOut = in_liveOut;
/* Get return expression of function */ /* Get return expression of function */
if (getReturnType()!=TYPE_UNKNOWN) if (flg & PROC_IS_FUNC)
{ {
auto picode = pbb->rbegin(); /* icode of function return */ auto picode = pbb->rbegin(); /* icode of function return */
if (picode->hl()->opcode == HLI_RET) if (picode->hl()->opcode == HLI_RET)
{ {
picode->hlU()->expr(AstIdent::idID(&type->retVal, &localId, (++pbb->rbegin()).base())); picode->hlU()->expr(AstIdent::idID(&retVal, &localId, (++pbb->rbegin()).base()));
picode->du.use = in_liveOut; picode->du.use = in_liveOut;
} }
} }
@ -354,7 +384,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
} }
else /* library routine */ 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() (pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any()
) )
pbb->liveOut = pcallee->liveOut; pbb->liveOut = pcallee->liveOut;
@ -364,7 +394,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() )) if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() ))
{ {
switch (pcallee->getReturnType()) { switch (pcallee->retVal.type) {
case TYPE_LONG_SIGN: case TYPE_LONG_SIGN:
case TYPE_LONG_UNSIGN: case TYPE_LONG_UNSIGN:
ticode.du1.setDef(rAX).addDef(rDX); ticode.du1.setDef(rAX).addDef(rDX);
@ -448,7 +478,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
if (not ticode->du.def.testRegAndSubregs(regi) and liveOut.testRegAndSubregs(regi) ) if (not ticode->du.def.testRegAndSubregs(regi) and liveOut.testRegAndSubregs(regi) )
start_at->du.lastDefRegi.addReg(regi); start_at->du.lastDefRegi.addReg(regi);
} }
else /* only 1 instruction in this basic block */ else /* only 1 instruction in this basic block */
{ {
/* Check if last definition of this register */ /* Check if last definition of this register */
if ( liveOut.testRegAndSubregs(regi) ) if ( liveOut.testRegAndSubregs(regi) )
@ -462,7 +492,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
* on optimized code. */ * on optimized code. */
void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode) void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
{ {
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->getReturnType()!=TYPE_UNKNOWN))) if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->flg & PROC_IS_FUNC)))
return; return;
BB *tbb = this->edges[0].BBptr; BB *tbb = this->edges[0].BBptr;
@ -489,7 +519,7 @@ void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
* thus remove it. Also check that this is not a return * thus remove it. Also check that this is not a return
* from a library function (routines such as printf * from a library function (routines such as printf
* return an integer, which is normally not taken into * return an integer, which is normally not taken into
* account by the programmer). */ * account by the programmer). */
void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode) void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
{ {
if (picode->valid() and not picode->du1.used(defRegIdx) and if (picode->valid() and not picode->du1.used(defRegIdx) and
@ -497,7 +527,7 @@ void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
(not ((picode->hl()->opcode == HLI_CALL) and (not ((picode->hl()->opcode == HLI_CALL) and
(picode->hl()->call.proc->flg & PROC_ISLIB)))) (picode->hl()->call.proc->flg & PROC_ISLIB))))
{ {
if (not (this->liveOut.testRegAndSubregs(regi))) /* not liveOut */ if (not (this->liveOut.testRegAndSubregs(regi))) /* not liveOut */
{ {
bool res = picode->removeDefRegi (regi, defRegIdx+1,&Parent->localId); bool res = picode->removeDefRegi (regi, defRegIdx+1,&Parent->localId);
if (res == true) if (res == true)
@ -512,7 +542,7 @@ void BB::RemoveUnusedDefs(eReg regi, int defRegIdx, iICODE picode)
} }
} }
} }
else /* liveOut */ else /* liveOut */
picode->du.lastDefRegi.addReg(regi); picode->du.lastDefRegi.addReg(regi);
} }
} }
@ -563,7 +593,7 @@ void Function::genDU1 ()
} }
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the rhs of picode. */ /* 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; bool res;
UnaryOperator *lhs_unary; UnaryOperator *lhs_unary;
@ -579,16 +609,16 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
return; return;
/* Insert on rhs of ticode, if possible */ /* Insert on rhs of ticode, if possible */
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.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) if (res)
{ {
picode->invalidate(); picode.invalidate();
numHlIcodes--; numHlIcodes--;
} }
else else
{ {
/* Try to insert it on lhs of ticode*/ /* 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) if(op)
{ {
eReg inserted = id_arr[lhs_reg->regiIdx].id.regi; eReg inserted = id_arr[lhs_reg->regiIdx].id.regi;
@ -599,45 +629,18 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
return; 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) if (res)
{ {
picode->invalidate(); picode.invalidate();
numHlIcodes--; numHlIcodes--;
} }
} }
} }
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the expression exp given */ /** Returns whether the elements of the expression rhs are all x-clear from
static void forwardSubsLong (int longIdx, Expr *_exp, iICODE picode, iICODE ticode, int *numHlIcodes) * instruction f up to instruction t. */
{
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
* instruction f up to instruction t. */
bool UnaryOperator::xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locs) bool UnaryOperator::xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locs)
{ {
if(nullptr==unaryExp) if(nullptr==unaryExp)
@ -672,12 +675,14 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
Expr *_exp; Expr *_exp;
bool res; bool res;
int size_of_arg=0; int size_of_arg=0;
Project &proj(*Project::get()); PROG &prog(Project::get()->prog);
/* if (numArgs == 0) /* if (numArgs == 0)
return; */ return; */
assert(pProc==g_exp_stk.func); assert(pProc==g_exp_stk.func);
_exp = g_exp_stk.pop(); _exp = g_exp_stk.pop();
if (callee->flg & PROC_ISLIB) /* library function */ if (callee->isLibrary() ) /* library function */
{ {
if (callee->args.numArgs > 0) if (callee->args.numArgs > 0)
{ {
@ -692,7 +697,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
} }
else { else {
if(numArgs<callee->args.size()) { 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)) { if((callee->args[numArgs].type==TYPE_STR) or (callee->args[numArgs].type==TYPE_PTR)) {
RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top()); RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top());
AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top()); AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top());
@ -720,7 +725,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
} }
} }
} }
else /* user function */ else /* user function */
{ {
if (callee->args.numArgs > 0) if (callee->args.numArgs > 0)
{ {
@ -730,7 +735,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
callee->args.adjustForArgType (numArgs, _exp->expType (pProc)); 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 /* Do not update the size of k if the expression was a segment register
* in a near call */ * in a near call */
if (res == false) if (res == false)
@ -745,11 +750,11 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
/** Eliminates extraneous intermediate icode instructions when finding /** Eliminates extraneous intermediate icode instructions when finding
* expressions. Generates new hlIcodes in the form of expression trees. * expressions. Generates new hlIcodes in the form of expression trees.
* For HLI_CALL hlIcodes, places the arguments in the argument list. */ * 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; bool res;
HLTYPE &p_hl(*picode->hlU()); HLTYPE &p_hl(*picode.hlU());
HLTYPE &t_hl(*ticode->hlU()); HLTYPE &t_hl(*ticode.hlU());
AstIdent *lhs_ident = dynamic_cast<AstIdent *>(p_hl.asgn.lhs()); AstIdent *lhs_ident = dynamic_cast<AstIdent *>(p_hl.asgn.lhs());
switch (t_hl.opcode) switch (t_hl.opcode)
@ -787,14 +792,14 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
} }
if (res) if (res)
{ {
picode->invalidate(); picode.invalidate();
numHlIcodes--; numHlIcodes--;
} }
break; break;
case HLI_CALL: /* register arguments */ case HLI_CALL: /* register arguments */
newRegArg ( picode, ticode); newRegArg ( picode, ticode);
picode->invalidate(); picode.invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
default: default:
@ -835,19 +840,19 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
int k; int k;
pp = picode->hl()->call.proc; pp = picode->hl()->call.proc;
cb = pp->cbParam; /* fixed # arguments */ cb = pp->cbParam; /* fixed # arguments */
k = 0; k = 0;
numArgs = 0; numArgs = 0;
while(k<cb) while(k<cb)
{ {
_exp = g_exp_stk.pop(); _exp = g_exp_stk.pop();
if (pp->flg & PROC_ISLIB) /* library function */ if (pp->isLibrary() ) /* library function */
{ {
if (pp->args.numArgs > 0) if (pp->args.numArgs > 0)
_exp = func->adjustActArgType(_exp, pp->args[numArgs].type); _exp = func->adjustActArgType(_exp, pp->args[numArgs].type);
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), func); res = picode->newStkArg (_exp, picode->ll()->getOpcode(), func);
} }
else /* user function */ else /* user function */
{ {
if (pp->args.numArgs >0) if (pp->args.numArgs >0)
{ {
@ -855,9 +860,10 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
{ {
fprintf(stderr,"Would try to adjustForArgType with null _exp\n"); fprintf(stderr,"Would try to adjustForArgType with null _exp\n");
} }
pp->args.adjustForArgType (numArgs,_exp->expType (func)); 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) if (res == false)
k += _exp->hlTypeSize (func); k += _exp->hlTypeSize (func);
@ -876,31 +882,30 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
{ {
bool res; bool res;
ID *_retVal; // function return value ID *_retVal; // function return value
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL */
//Expr *lhs; // exp ptr for return value of a HLI_CALL iICODE ticode; // Target icode */
iICODE ticode; // Target icode
HLTYPE *ti_hl=nullptr; HLTYPE *ti_hl=nullptr;
uint8_t regi; uint8_t regi;
numHlIcodes = 0; numHlIcodes = 0;
assert(&fnc->localId==&locals); assert(&fnc->localId==&locals);
// register(s) to be forward substituted // register(s) to be forward substituted */
auto valid_and_highlevel = instructions | filtered(ICODE::TypeAndValidFilter<HIGH_LEVEL_ICODE>()); auto valid_and_highlevel = instructions | filtered(ICODE::TypeAndValidFilter<HIGH_LEVEL_ICODE>());
for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++) for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++)
{ {
ICODE &_ic(*picode); ICODE &_ic(*picode);
HLTYPE &_icHl(*picode->hlU()); HLTYPE &_icHl(*_ic.hlU());
numHlIcodes++; 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 /* Check for only one use of this register. If this is
* the last definition of the register in this BB, check * the last definition of the register in this BB, check
* that it is not liveOut from this basic block */ * 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 /* Check that this register is not liveOut, if it
* is the last definition of the register */ * 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 */ /* Check if we can forward substitute this register */
switch (_icHl.opcode) switch (_icHl.opcode)
@ -909,16 +914,16 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
/* Replace rhs of current icode into target /* Replace rhs of current icode into target
* icode expression */ * icode expression */
ticode = picode->du1.idx[0].uses.front(); ticode = _ic.du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and ((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET))) (ticode->hl()->opcode != HLI_RET)))
continue; 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)) end(), locals))
{ {
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,false); locals.processTargetIcode(_ic, numHlIcodes, *ticode,false);
} }
break; break;
@ -927,9 +932,9 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
// pop X // pop X
// lab1: // lab1:
// call F() <- somehow this is marked as user of POP ? // 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(); 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_CALL) and
(ti_hl->opcode != HLI_RET))) (ti_hl->opcode != HLI_RET)))
continue; continue;
@ -937,7 +942,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
_exp = g_exp_stk.pop(); /* pop last exp pushed */ _exp = g_exp_stk.pop(); /* pop last exp pushed */
switch (ticode->hl()->opcode) { switch (ticode->hl()->opcode) {
case HLI_ASSIGN: case HLI_ASSIGN:
locals.forwardSubs(_icHl.expr(), _exp, picode.base(), ticode, numHlIcodes); locals.forwardSubs(_icHl.expr(), _exp, _ic, *ticode, numHlIcodes);
break; break;
case HLI_JCOND: case HLI_PUSH: case HLI_RET: case HLI_JCOND: case HLI_PUSH: case HLI_RET:
@ -950,7 +955,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
&locals); &locals);
if (res) if (res)
{ {
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
} }
} }
@ -960,7 +965,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
newRegArg (pProc, picode, ticode); newRegArg (pProc, picode, ticode);
picode->invalidate(); picode->invalidate();
numHlIcodes--; numHlIcodes--;
break; */ break; */
default: default:
fprintf(stderr,"unhandled BB::findBBExps target opcode %d\n",ticode->hl()->opcode); fprintf(stderr,"unhandled BB::findBBExps target opcode %d\n",ticode->hl()->opcode);
@ -968,9 +973,9 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
break; break;
case HLI_CALL: case HLI_CALL:
ticode = picode->du1.idx[0].uses.front(); ticode = _ic.du1.idx[0].uses.front();
ti_hl = ticode->hlU(); ti_hl = ticode->hlU();
_retVal = &_icHl.call.proc->type->retVal; _retVal = &_icHl.call.proc->retVal;
switch (ti_hl->opcode) switch (ti_hl->opcode)
{ {
case HLI_ASSIGN: case HLI_ASSIGN:
@ -980,28 +985,28 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
if (not res) if (not res)
Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals); Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals);
//TODO: HERE missing: 2 regs //TODO: HERE missing: 2 regs
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
case HLI_PUSH: case HLI_RET: case HLI_PUSH: case HLI_RET:
ti_hl->expr( _icHl.call.toAst() ); ti_hl->expr( _icHl.call.toAst() );
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
case HLI_JCOND: case HLI_JCOND:
_exp = _icHl.call.toAst(); _exp = _icHl.call.toAst();
res = Expr::insertSubTreeReg (ti_hl->exp.v, _exp, _retVal->id.regi, &locals); res = Expr::insertSubTreeReg (ti_hl->exp.v, _exp, _retVal->id.regi, &locals);
if (res) /* was substituted */ if (res) /* was substituted */
{ {
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
} }
else /* cannot substitute function */ else /* cannot substitute function */
{ {
auto lhs = AstIdent::idID(_retVal,&locals,picode.base()); auto lhs = AstIdent::idID(_retVal,&locals,picode.base());
picode->setAsgn(lhs, _exp); _ic.setAsgn(lhs, _exp);
} }
break; break;
default: 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 */ /* 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) switch (_icHl.opcode)
{ {
case HLI_ASSIGN: case HLI_ASSIGN:
/* Replace rhs of current icode into target icode expression */ /* Replace rhs of current icode into target
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0]) * icode expression */
if (_ic.du1.idx[0].uses[0] == _ic.du1.idx[1].uses[0])
{ {
ticode = picode->du1.idx[0].uses.front(); ticode = _ic.du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and ((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET))) (ticode->hl()->opcode != HLI_RET)))
continue; continue;
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,true); locals.processTargetIcode(_ic, numHlIcodes, *ticode,true);
} }
break; break;
case HLI_POP: 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(); ticode = _ic.du1.idx[0].uses.front();
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
((ticode->hl()->opcode != HLI_CALL) and ((ticode->hl()->opcode != HLI_CALL) and
(ticode->hl()->opcode != HLI_RET))) (ticode->hl()->opcode != HLI_RET)))
continue; continue;
@ -1048,21 +1054,20 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
_exp = g_exp_stk.pop(); /* pop last exp pushed */ _exp = g_exp_stk.pop(); /* pop last exp pushed */
switch (ticode->hl()->opcode) { switch (ticode->hl()->opcode) {
case HLI_ASSIGN: case HLI_ASSIGN:
forwardSubsLong (static_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx, forwardSubsLong (dynamic_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
_exp, picode.base(), ticode, &numHlIcodes); _exp, _ic, *ticode, &numHlIcodes);
break; break;
case HLI_JCOND: case HLI_JCOND: case HLI_PUSH:
case HLI_PUSH:
res = Expr::insertSubTreeLongReg (_exp, res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v, ticode->hlU()->exp.v,
dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx); dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx);
if (res) if (res)
{ {
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
} }
break; break;
case HLI_CALL: /*** missing ***/ case HLI_CALL: /*** missing ***/
break; break;
default: default:
fprintf(stderr,"BB::findBBExps Unhandled target op %d\n",ticode->hl()->opcode); fprintf(stderr,"BB::findBBExps Unhandled target op %d\n",ticode->hl()->opcode);
@ -1071,7 +1076,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
break; break;
case HLI_CALL: /* check for function return */ 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) switch (ticode->hl()->opcode)
{ {
case HLI_ASSIGN: case HLI_ASSIGN:
@ -1081,32 +1086,32 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
ticode,HIGH_FIRST, picode.base(), ticode,HIGH_FIRST, picode.base(),
eDEF, *(++iICODE(ticode))->ll())); eDEF, *(++iICODE(ticode))->ll()));
ticode->hlU()->asgn.m_rhs = _exp; ticode->hlU()->asgn.m_rhs = _exp;
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
case HLI_PUSH: case HLI_PUSH:
case HLI_RET: case HLI_RET:
ticode->hlU()->expr( _icHl.call.toAst() ); ticode->hlU()->expr( _icHl.call.toAst() );
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
break; break;
case HLI_JCOND: case HLI_JCOND:
_exp = _icHl.call.toAst(); _exp = _icHl.call.toAst();
_retVal = &picode->hl()->call.proc->type->retVal; _retVal = &_ic.hl()->call.proc->retVal;
res = Expr::insertSubTreeLongReg (_exp, res = Expr::insertSubTreeLongReg (_exp,
ticode->hlU()->exp.v, ticode->hlU()->exp.v,
locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base())); locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base()));
if (res) /* was substituted */ if (res) /* was substituted */
{ {
picode->invalidate(); _ic.invalidate();
numHlIcodes--; numHlIcodes--;
} }
else /* cannot substitute function */ else /* cannot substitute function */
{ {
auto lhs = locals.createId(_retVal,picode.base()); auto lhs = locals.createId(_retVal,picode.base());
picode->setAsgn(lhs, _exp); _ic.setAsgn(lhs, _exp);
} }
break; break;
default: default:
@ -1127,8 +1132,8 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
{ {
g_exp_stk.processExpPush(numHlIcodes, *picode); g_exp_stk.processExpPush(numHlIcodes, *picode);
} }
else if(picode->du1.getNumRegsDef()!=0) else if(_ic.du1.getNumRegsDef()!=0)
printf("Num def %d\n",picode->du1.getNumRegsDef()); printf("Num def %d\n",_ic.du1.getNumRegsDef());
/* For HLI_CALL instructions that use arguments from the stack, /* For HLI_CALL instructions that use arguments from the stack,
* pop them from the expression stack and place them on the * 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, /* If we could not substitute the result of a function,
* assign it to the corresponding registers */ * 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); _exp = new FuncNode(_icHl.call.proc, _icHl.call.args);
auto lhs = AstIdent::idID (&_icHl.call.proc->type->retVal, &locals, picode.base()); auto lhs = AstIdent::idID (&_icHl.call.proc->retVal, &locals, picode.base());
picode->setAsgn(lhs, _exp); _ic.setAsgn(lhs, _exp);
} }
} }
} }
@ -1182,6 +1187,7 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if(not _liveOut.any()) if(not _liveOut.any())
return; return;
} }
flg |= PROC_IS_FUNC;
isAx = _liveOut.testReg(rAX); isAx = _liveOut.testReg(rAX);
isBx = _liveOut.testReg(rBX); isBx = _liveOut.testReg(rBX);
isCx = _liveOut.testReg(rCX); isCx = _liveOut.testReg(rCX);
@ -1217,55 +1223,53 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
if (isAx and isDx) /* long or pointer */ if (isAx and isDx) /* long or pointer */
{ {
type->setReturnType(TYPE_LONG_SIGN); retVal.type = TYPE_LONG_SIGN;
type->m_call_conv->calculateStackLayout(this); retVal.loc = REG_FRAME;
retVal.longId() = LONGID_TYPE(rDX,rAX);
/*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin()); /*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin());
localId.propLongId (rAX, rDX, ""); localId.propLongId (rAX, rDX, "");
} }
else if (isAx or isBx or isCx or isDx) /* uint16_t */ else if (isAx or isBx or isCx or isDx) /* uint16_t */
{ {
eReg selected_reg; retVal.type = TYPE_WORD_SIGN;
retVal.loc = REG_FRAME;
if (isAx) if (isAx)
selected_reg = rAX; retVal.id.regi = rAX;
else if (isBx) else if (isBx)
selected_reg = rBX; retVal.id.regi = rBX;
else if (isCx) else if (isCx)
selected_reg = rCX; retVal.id.regi = rCX;
else else
selected_reg = rDX; retVal.id.regi = rDX;
type->setReturnType(TYPE_WORD_SIGN); /*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,retVal.id.regi);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,selected_reg);
} }
else if(isAL or isBL or isCL or isDL) else if(isAL or isBL or isCL or isDL)
{ {
eReg selected_reg; retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
if (isAL) if (isAL)
selected_reg = rAL; retVal.id.regi = rAL;
else if (isBL) else if (isBL)
selected_reg = rBL; retVal.id.regi = rBL;
else if (isCL) else if (isCL)
selected_reg = rCL; retVal.id.regi = rCL;
else else
selected_reg = rDL; retVal.id.regi = rDL;
type->setReturnType(TYPE_BYTE_SIGN); /*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
} }
else if(isAH or isBH or isCH or isDH) else if(isAH or isBH or isCH or isDH)
{ {
eReg selected_reg; retVal.type = TYPE_BYTE_SIGN;
retVal.loc = REG_FRAME;
if (isAH) if (isAH)
selected_reg = rAH; retVal.id.regi = rAH;
else if (isBH) else if (isBH)
selected_reg = rBH; retVal.id.regi = rBH;
else if (isCH) else if (isCH)
selected_reg = rCH; retVal.id.regi = rCH;
else else
selected_reg = rDH; retVal.id.regi = rDH;
type->setReturnType(TYPE_BYTE_SIGN); /*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
type->m_call_conv->calculateStackLayout(this);
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
} }
} }
} }
@ -1288,10 +1292,10 @@ void Function::dataFlow(LivenessSet &_liveOut)
liveAnal = true; liveAnal = true;
elimCondCodes(); elimCondCodes();
genLiveKtes(); genLiveKtes();
liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */ liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */
if (not (flg & PROC_ASM)) /* can generate C for pProc */ if (not (flg & PROC_ASM)) /* can generate C for pProc */
{ {
genDU1 (); /* generate def/use level 1 chain */ genDU1 (); /* generate def/use level 1 chain */
findExps (); /* forward substitution algorithm */ findExps (); /* forward substitution algorithm */
} }
} }

View File

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

View File

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

View File

@ -18,7 +18,6 @@
#include <iomanip> #include <iomanip>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "src/ui/StructuredTextTarget.h"
// Note: for the time being, there is no interactive disassembler // Note: for the time being, there is no interactive disassembler
// for unix // for unix
@ -29,7 +28,7 @@ using namespace std;
#define POS_LAB 15 /* Position of label */ #define POS_LAB 15 /* Position of label */
#define POS_OPC 20 /* Position of opcode */ #define POS_OPC 20 /* Position of opcode */
#define POS_OPR 25 /* Position of operand */ #define POS_OPR 25 /* Position of operand */
#define WID_PTR 10 /* Width of the "xword ptr" lingo */ #define WID_PTR 10 /* Width of the "xword ptr" lingo */
#define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */ #define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */
#define POS_CMT 54 /* Position of comment */ #define POS_CMT 54 /* Position of comment */
@ -87,12 +86,12 @@ bool callArg(uint16_t off, char *temp); /* Check for procedure name */
//static FILE *dis_g_fp; //static FILE *dis_g_fp;
static CIcodeRec pc; static CIcodeRec pc;
static int cb, numIcode, allocIcode; static int cb, j, numIcode, allocIcode;
static map<int,int> pl; static map<int,int> pl;
static uint32_t nextInst; static uint32_t nextInst;
//static bool fImpure; static bool fImpure;
//static int g_lab; //static int g_lab;
static PtrFunction pProc; /* Points to current proc struct */ static Function * pProc; /* Points to current proc struct */
struct POSSTACK_ENTRY struct POSSTACK_ENTRY
{ {
@ -108,12 +107,12 @@ static vector<POSSTACK_ENTRY> posStack; /* position stack */
#define printfd(x) printf(x) #define printfd(x) printf(x)
#define dis_newline() printf("\n") #define dis_newline() printf("\n")
#define dis_show() // Nothing to do unless using Curses #define dis_show() // Nothing to do unless using Curses
void LLInst::findJumpTargets(CIcodeRec &_pc) void LLInst::findJumpTargets(CIcodeRec &_pc)
{ {
if (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 */ /* Replace the immediate operand with an icode index */
iICODE labTgt=_pc.labelSrch(src().getImm2()); iICODE labTgt=_pc.labelSrch(src().getImm2());
@ -134,12 +133,12 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
} }
/***************************************************************************** /*****************************************************************************
* disassem - Prints a disassembled listing of a procedure. * disassem - Prints a disassembled listing of a procedure.
* pass == 1 generates output on file .a1 * pass == 1 generates output on file .a1
* pass == 2 generates output on file .a2 * pass == 2 generates output on file .a2
* pass == 3 generates output on file .b * pass == 3 generates output on file .b
****************************************************************************/ ****************************************************************************/
void Disassembler::disassem(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) 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 * * strSrc *
****************************************************************************/ ****************************************************************************/
//QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma) QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
//{ {
// if(false==skip_comma) if(false==skip_comma)
// os<<", "; os<<", ";
// if (srcIsImmed()) if (testFlags(I))
// os<<strHex(src().getImm2()); os<<strHex(src().getImm2());
// else if (testFlags(IM_SRC)) /* level 2 */ else if (testFlags(IM_SRC)) /* level 2 */
// os<<"dx:ax"; os<<"dx:ax";
// else else
// formatRM(os, src()); formatRM(os, src());
// return os; return os;
//} }
@ -304,7 +660,7 @@ static char *strHex(uint32_t d)
/**************************************************************************** /****************************************************************************
* interactDis - interactive disassembler * * interactDis - interactive disassembler *
****************************************************************************/ ****************************************************************************/
void interactDis(const PtrFunction & initProc, int initIC) void interactDis(Function * initProc, int initIC)
{ {
QString procname = "UNKNOWN"; QString procname = "UNKNOWN";
if(initProc) if(initProc)
@ -334,29 +690,29 @@ void LLInst::flops(QTextStream &out)
} }
else switch (op & 0x30) else switch (op & 0x30)
{ {
case 0x00: case 0x00:
case 0x10: case 0x10:
out << "dword ptr "; out << "dword ptr ";
break;
case 0x20:
out << "qword ptr ";
break;
case 0x30:
switch (op)
{
case 0x3C: /* FBLD */
case 0x3E: /* FBSTP */
out << "tbyte ptr ";
break; break;
case 0x3D: /* FILD 64 bit */ case 0x20:
case 0x3F: /* FISTP 64 bit */
out << "qword ptr "; out << "qword ptr ";
break; break;
case 0x30:
switch (op)
{
case 0x3C: /* FBLD */
case 0x3E: /* FBSTP */
out << "tbyte ptr ";
break;
case 0x3D: /* FILD 64 bit */
case 0x3F: /* FISTP 64 bit */
out << "qword ptr ";
break;
default: default:
out << "uint16_t ptr "; out << "uint16_t ptr ";
break; break;
} }
} }
out.setFieldWidth(0); out.setFieldWidth(0);
formatRM(out, m_dst); formatRM(out, m_dst);
@ -371,271 +727,46 @@ void LLInst::flops(QTextStream &out)
int destRegIdx=m_dst.regi - rAX; int destRegIdx=m_dst.regi - rAX;
switch (op) switch (op)
{ {
case 0x0C: case 0x0C:
out << szFlops0C[destRegIdx]; out << szFlops0C[destRegIdx];
break; break;
case 0x0D: case 0x0D:
out << szFlops0D[destRegIdx]; out << szFlops0D[destRegIdx];
break; break;
case 0x0E: case 0x0E:
out << szFlops0E[destRegIdx]; out << szFlops0E[destRegIdx];
break; break;
case 0x0F: case 0x0F:
out << szFlops0F[destRegIdx]; out << szFlops0F[destRegIdx];
break; break;
case 0x15: case 0x15:
out << szFlops15[destRegIdx]; out << szFlops15[destRegIdx];
break; break;
case 0x1C: case 0x1C:
out << szFlops1C[destRegIdx]; out << szFlops1C[destRegIdx];
break; break;
case 0x33: case 0x33:
out << szFlops33[destRegIdx]; out << szFlops33[destRegIdx];
break; break;
case 0x3C: case 0x3C:
out << szFlops3C[destRegIdx]; out << szFlops3C[destRegIdx];
break; break;
default: default:
out << Machine_X86::floatOpName(0x40+op); out << Machine_X86::floatOpName(0x40+op);
if ((op >= 0x20) and (op <= 0x27)) if ((op >= 0x20) and (op <= 0x27))
{ {
/* This is the ST(i), ST form. */ /* This is the ST(i), ST form. */
out << "ST("<<destRegIdx - rAX<<"),ST"; out << "ST("<<destRegIdx - rAX<<"),ST";
} }
else else
{ {
/* ST, ST(i) */ /* ST, ST(i) */
out << "ST,ST("<<destRegIdx; out << "ST,ST("<<destRegIdx;
} }
break; break;
} }
} }
} }
struct AsmFormatter {
IStructuredTextTarget * target;
int operand_count;
void visitOperand(const LLOperand &pm) {
if(not pm.isSet())
return;
if(operand_count>0) {
target->prtt(", ");
}
operand_count++;
if (pm.immed and not pm.isReg()) {
//target->addTaggedString(XT_Keyword,szPtr[flg&B]);
target->addTaggedString(XT_Number,strHex(pm.getImm2()));
return;
}
if (pm.segOver)
{
target->prtt(Machine_X86::regName(pm.segOver)+':');
}
if (pm.regi == rUNDEF)
{
target->prtt(QString("[")+strHex((uint32_t)pm.off)+"]");
}
else if (pm.isReg())
{
target->prtt(Machine_X86::regName(pm.regi));
}
else if (pm.off)
{
if (pm.off < 0)
{
target->prtt("["+Machine_X86::regName(pm.regi)+"-"+strHex((uint32_t)(- pm.off))+"]");
}
else
{
target->prtt("["+Machine_X86::regName(pm.regi)+"+"+strHex((uint32_t)(pm.off))+"]");
}
}
else
target->prtt("["+Machine_X86::regName(pm.regi)+"]");
}
};
void toStructuredText(LLInst *insn,IStructuredTextTarget *out, int level) {
AsmFormatter formatter {out};
const LLInst &inst(*insn);
QString opcode = Machine_X86::opcodeName(insn->getOpcode());
out->addSpace(4);
out->addTaggedString(XT_Number,QString("%1").arg(insn->label,8,16,QChar('0').toUpper()));
out->addSpace(4);
out->addTaggedString(XT_Keyword,Machine_X86::opcodeName(insn->getOpcode()),insn);
out->addSpace(2);
switch(insn->getOpcode()) {
case iADD: case iADC: case iSUB: case iSBB: case iAND: case iOR:
case iXOR: case iTEST: case iCMP: case iMOV: case iLEA: case iXCHG:
case iSAR: case iSHL: case iSHR: case iRCL: case iRCR: case iROL:
case iROR:
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
break;
case iINC: case iDEC: case iNEG: case iNOT: case iPOP:
formatter.visitOperand(insn->dst());
break;
case iPUSH:
formatter.visitOperand(insn->dst());
break;
case iDIV: case iIDIV: case iMUL: case iIMUL: case iMOD:
if (inst.srcIsImmed())
{
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
}
else
formatter.visitOperand(insn->dst());
break;
case iLDS: case iLES: case iBOUND:
formatter.visitOperand(insn->dst());
formatter.visitOperand(insn->src());
break;
case iJB: case iJBE: case iJAE: case iJA:
case iJL: case iJLE: case iJGE: case iJG:
case iJE: case iJNE: case iJS: case iJNS:
case iJO: case iJNO: case iJP: case iJNP:
case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
case iJMP: case iJMPF:
/* Check if there is a symbol here */
{
// ICODE *lab=pc.GetIcode(inst.src().getImm2());
// selectTable(Label);
// if ((inst.src().getImm2() < (uint32_t)numIcode) and /* Ensure in range */
// readVal(operands_s, lab->ll()->label, nullptr))
// {
// break; /* Symbolic label. Done */
// }
}
if (inst.testFlags(NO_LABEL))
{
//strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op));
out->addTaggedString(XT_AsmLabel,strHex(inst.src().getImm2()));
}
else if (inst.srcIsImmed() )
{
int64_t tgt_addr = inst.src().getImm2();
if (inst.getOpcode() == iJMPF)
{
out->addTaggedString(XT_Keyword," far ptr ");
}
out->addTaggedString(XT_AsmLabel,QString("L_%1").arg(strHex(tgt_addr)));
}
else if (inst.getOpcode() == iJMPF)
{
out->addTaggedString(XT_Keyword,"dword ptr");
formatter.visitOperand(inst.src());
}
else
{
formatter.visitOperand(inst.src());
}
break;
case iCALL: case iCALLF:
if (inst.srcIsImmed())
{
out->addTaggedString(XT_Keyword,QString("%1 ptr ").arg((inst.getOpcode() == iCALL) ? "near" : "far"));
out->addTaggedString(XT_AsmLabel,(inst.src().proc.proc)->name);
}
else if (inst.getOpcode() == iCALLF)
{
out->addTaggedString(XT_Keyword,"dword ptr ");
formatter.visitOperand(inst.src());
}
else
formatter.visitOperand(inst.src());
break;
case iENTER:
formatter.visitOperand(inst.dst());
formatter.visitOperand(inst.src());
break;
case iRET:
case iRETF:
case iINT:
formatter.visitOperand(inst.src());
break;
case iCMPS: case iREPNE_CMPS: case iREPE_CMPS:
case iSCAS: case iREPNE_SCAS: case iREPE_SCAS:
case iSTOS: case iREP_STOS:
case iLODS: case iREP_LODS:
case iMOVS: case iREP_MOVS:
case iINS: case iREP_INS:
case iOUTS: case iREP_OUTS:
if (inst.src().segOver)
{
bool is_dx_src=(inst.getOpcode() == iOUTS or inst.getOpcode() == iREP_OUTS);
if(is_dx_src)
{
out->addTaggedString(XT_Symbol,"dx");
out->prtt(", ");
out->addTaggedString(XT_Keyword,szPtr[inst.getFlag() & B]);
out->addSpace(2);
}
else
out->addTaggedString(XT_Keyword,szPtr[inst.getFlag() & B]);
if (inst.getOpcode() == iLODS or
inst.getOpcode() == iREP_LODS or
inst.getOpcode() == iOUTS or
inst.getOpcode() == iREP_OUTS)
{
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver)); // szWreg[src.segOver-rAX]
}
else
{
out->addTaggedString(XT_Symbol,"es:[di]");
out->prtt(", ");
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver));
}
out->addTaggedString(XT_Symbol,":[si]");
}
else
{
out->delChars(2); // TODO: this is wonky way of adding instruction suffix
if(inst.getFlag() & B)
out->addTaggedString(XT_Keyword,"B");
else
out->addTaggedString(XT_Keyword,"W");
out->addSpace(2);
}
break;
case iXLAT:
if (inst.src().segOver)
{
out->addTaggedString(XT_Keyword,QString(" ") + szPtr[1]);
out->addTaggedString(XT_Symbol,Machine_X86::regName(inst.src().segOver)+":[bx]");
}
break;
case iIN:
out->addTaggedString(XT_Symbol, (inst.getFlag() & B)? "al" : "ax");
out->prtt(", ");
formatter.visitOperand(inst.src());
break;
case iOUT:
{
formatter.visitOperand(inst.src());
if(inst.srcIsImmed())
out->addTaggedString(XT_Number, strHex(inst.src().getImm2()));
else
out->addTaggedString(XT_Symbol, "dx");
out->prtt(", ");
out->addTaggedString(XT_Symbol, (inst.getFlag() & B)? "al" : "ax");
}
}
out->addEOL();
}

View File

@ -11,36 +11,37 @@
#include "dcc.h" #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_ARG ,"Invalid option -%c\n"},
{INVALID_OPCODE ,"Invalid instruction %02X at location %06lX\n"}, {INVALID_OPCODE ,"Invalid instruction %02X at location %06lX\n"},
{INVALID_386OP ,"Don't understand 80386 instruction %02X at location %06lX\n"}, {INVALID_386OP ,"Don't understand 80386 instruction %02X at location %06lX\n"},
{FUNNY_SEGOVR ,"Segment override with no memory operand at location %06lX\n"}, {FUNNY_SEGOVR ,"Segment override with no memory operand at location %06lX\n"},
{FUNNY_REP ,"REP prefix without a string instruction at location %06lX\n"}, {FUNNY_REP ,"REP prefix without a string instruction at location %06lX\n"},
{CANNOT_OPEN ,"Cannot open %s\n"}, {CANNOT_OPEN ,"Cannot open %s\n"},
{CANNOT_READ ,"Error while reading %s\n"}, {CANNOT_READ ,"Error while reading %s\n"},
{MALLOC_FAILED ,"malloc of %ld bytes failed\n"}, {MALLOC_FAILED ,"malloc of %ld bytes failed\n"},
{NEWEXE_FORMAT ,"Don't understand new EXE format\n"}, {NEWEXE_FORMAT ,"Don't understand new EXE format\n"},
{NO_BB ,"Failed to find a BB for jump to %ld in proc %s\n"}, {NO_BB ,"Failed to find a BB for jump to %ld in proc %s\n"},
{INVALID_SYNTHETIC_BB,"Basic Block is a synthetic jump\n"}, {INVALID_SYNTHETIC_BB,"Basic Block is a synthetic jump\n"},
{INVALID_INT_BB ,"Failed to find a BB for interval\n"}, {INVALID_INT_BB ,"Failed to find a BB for interval\n"},
{IP_OUT_OF_RANGE ,"Instruction at location %06lX goes beyond loaded image\n"}, {IP_OUT_OF_RANGE ,"Instruction at location %06lX goes beyond loaded image\n"},
{DEF_NOT_FOUND ,"Definition not found for condition code usage at opcode %d\n"}, {DEF_NOT_FOUND ,"Definition not found for condition code usage at opcode %d\n"},
{JX_NOT_DEF ,"JX use, definition not supported at opcode #%d\n"}, {JX_NOT_DEF ,"JX use, definition not supported at opcode #%d\n"},
{NOT_DEF_USE ,"%x: Def - use not supported. Def op = %d, use op = %d.\n"}, {NOT_DEF_USE ,"%x: Def - use not supported. Def op = %d, use op = %d.\n"},
{REPEAT_FAIL ,"Failed to construct repeat..until() condition.\n"}, {REPEAT_FAIL ,"Failed to construct repeat..until() condition.\n"},
{WHILE_FAIL ,"Failed to construct while() condition.\n"}, {WHILE_FAIL ,"Failed to construct while() condition.\n"},
}; };
/**************************************************************************** /****************************************************************************
fatalError: displays error message and exits the program. fatalError: displays error message and exits the program.
****************************************************************************/ ****************************************************************************/
void fatalError(eErrorId errId, ...) void fatalError(eErrorId errId, ...)
{ va_list args; {
//#ifdef __UNIX__ /* ultrix */ va_list args;
//#ifdef __UNIX__ /* ultrix */
#if 0 #if 0
int errId; int errId;
va_start(args); va_start(args);
errId = va_arg(args, int); errId = va_arg(args, int);
@ -49,10 +50,12 @@ void fatalError(eErrorId errId, ...)
#endif #endif
if (errId == USAGE) if (errId == USAGE)
fprintf(stderr,"Usage: dcc [-a1a2cmpsvVi][-o asmfile] DOS_executable\n"); fprintf(stderr,"Usage: dcc [-a1a2cmpsvVi][-o asmfile] DOS_executable\n");
else { else {
auto msg_iter = errorMessage.find(errId);
assert(msg_iter!=errorMessage.end());
fprintf(stderr, "dcc: "); fprintf(stderr, "dcc: ");
vfprintf(stderr, errorMessage[errId].c_str(), args); vfprintf(stderr, msg_iter->second.c_str(), args);
} }
va_end(args); va_end(args);
exit((int)errId); exit((int)errId);
@ -63,10 +66,11 @@ void fatalError(eErrorId errId, ...)
reportError: reports the warning/error and continues with the program. reportError: reports the warning/error and continues with the program.
****************************************************************************/ ****************************************************************************/
void reportError(eErrorId errId, ...) void reportError(eErrorId errId, ...)
{ va_list args; {
//#ifdef __UNIX__ /* ultrix */ va_list args;
//#ifdef __UNIX__ /* ultrix */
#if 0 #if 0
int errId; int errId;
va_start(args); va_start(args);
errId = va_arg(args, int); errId = va_arg(args, int);
@ -74,6 +78,8 @@ void reportError(eErrorId errId, ...)
va_start(args, errId); va_start(args, errId);
#endif #endif
fprintf(stderr, "dcc: "); 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); va_end(args);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,6 +10,11 @@
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include <cstring> #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 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)); 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. /* Creates a new identifier node of type t and returns it.
* Arguments: locSym : local long symbol table * 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 */ * ix : index into icode array where this var is used */
void LOCAL_ID::newIdent(hlType t, frameType f) void LOCAL_ID::newIdent(hlType t, frameType f)
{ {
ID newid(t,f); id_arr.emplace_back(t,f);
id_arr.push_back(newid);
} }
@ -74,19 +83,16 @@ void LOCAL_ID::newIdent(hlType t, frameType f)
* TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */ * TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */
int LOCAL_ID::newByteWordReg(hlType t, eReg regi) int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
{ {
int idx;
/* Check for entry in the table */ /* Check for entry in the table */
auto found=std::find_if(id_arr.begin(),id_arr.end(),[t,regi](ID &el)->bool { 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)); return ((el.type == t) and (el.id.regi == regi));
}); });
if(found!=id_arr.end()) if(found!=id_arr.end())
return found-id_arr.begin(); return found-id_arr.begin();
/* Not in table, create new identifier */ /* Not in table, create new identifier */
newIdent (t, REG_FRAME); newIdent (t, REG_FRAME);
idx = id_arr.size() - 1; id_arr.back().id.regi = regi;
id_arr[idx].id.regi = regi; return id_arr.size() - 1;
return (idx);
} }
@ -99,11 +105,8 @@ int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
void LOCAL_ID::flagByteWordId (int off) void LOCAL_ID::flagByteWordId (int off)
{ {
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off](ID &en)->bool { 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.type == TYPE_WORD_SIGN) or (en.type == TYPE_BYTE_SIGN)) and
if ((en.typeBitsize()<=16) and return ((en.typeBitsize()<=16) and (en.id.bwId.off == off) and (en.id.bwId.regOff == 0));
(en.id.bwId.off == off) and (en.id.bwId.regOff == 0))
return true;
return false;
}); });
if(found==id_arr.end()) if(found==id_arr.end())
{ {
@ -117,23 +120,21 @@ void LOCAL_ID::flagByteWordId (int off)
* TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */ * TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */
int LOCAL_ID::newByteWordStk(hlType t, int off, uint8_t regOff) int LOCAL_ID::newByteWordStk(hlType t, int off, uint8_t regOff)
{ {
int idx;
/* Check for entry in the table */ /* Check for entry in the table */
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off,regOff](ID &el)->bool { 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)) if ((el.id.bwId.off == off) and (el.id.bwId.regOff == regOff))
return true; return true;
return false; return false;
}); });
if(found!=id_arr.end()) if(found!=id_arr.end())
return found-id_arr.begin(); //return Index to found element return found-id_arr.begin(); //return Index to found element
/* Not in table, create new identifier */ /* Not in table, create new identifier */
newIdent (t, STK_FRAME); newIdent (t, STK_FRAME);
idx = id_arr.size() - 1; ID &last_id(id_arr.back());
id_arr[idx].id.bwId.regOff = regOff; last_id.id.bwId.regOff = regOff;
id_arr[idx].id.bwId.off = off; last_id.id.bwId.off = off;
return (idx); return id_arr.size()-1;
} }
@ -152,9 +153,9 @@ int LOCAL_ID::newIntIdx(int16_t seg, int16_t off, eReg regi, hlType t)
for (size_t 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 */ if (/*(locSym->id[idx].type == t) and Not checking type */
(id_arr[idx].id.bwGlb.seg == seg) and (id_arr[idx].id.bwGlb.seg == seg) and
(id_arr[idx].id.bwGlb.off == off) and (id_arr[idx].id.bwGlb.off == off) and
(id_arr[idx].id.bwGlb.regi == regi)) (id_arr[idx].id.bwGlb.regi == regi))
return (idx); return (idx);
} }
@ -181,7 +182,7 @@ int LOCAL_ID::newLongReg(hlType t, const LONGID_TYPE &longT, iICODE ix_)
for (idx = 0; idx < id_arr.size(); idx++) for (idx = 0; idx < id_arr.size(); idx++)
{ {
ID &entry(id_arr[idx]); ID &entry(id_arr[idx]);
if(not entry.isLong() or (entry.loc != REG_FRAME)) if(not entry.isLongRegisterPair())
continue; continue;
if (/*(locSym->id[idx].type == t) and Not checking type */ if (/*(locSym->id[idx].type == t) and Not checking type */
(entry.longId().h() == regH) and (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 */ /* Check for occurrence in the list */
if (entry.idx.inList(ix_)) if (entry.idx.inList(ix_))
return (idx); return idx;
else else
{ {
/* Insert icode index in list */ /* Insert icode index in list */
entry.idx.push_back(ix_); entry.idx.push_back(ix_);
return (idx); return idx;
} }
} }
} }
/* Not in the table, create new identifier */ /* 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_); id_arr.back().idx.push_back(ix_);
return (id_arr.size() - 1); return (id_arr.size() - 1);
} }
/** Returns an identifier conditional expression node of type TYPE_LONG or /** \returns an identifier conditional expression node of type TYPE_LONG or TYPE_WORD_SIGN */
* TYPE_WORD_SIGN */
AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_) AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_)
{ {
return AstIdent::idID(retVal,this,ix_); return AstIdent::idID(retVal,this,ix_);
@ -222,15 +222,15 @@ int LOCAL_ID::newLongGlb(int16_t seg, int16_t offH, int16_t offL,hlType t)
for (idx = 0; idx < id_arr.size(); idx++) for (idx = 0; idx < id_arr.size(); idx++)
{ {
if (/*(locSym->id[idx].type == t) and Not checking type */ if (/*(locSym->id[idx].type == t) and Not checking type */
(id_arr[idx].id.longGlb.seg == seg) and (id_arr[idx].id.longGlb.seg == seg) and
(id_arr[idx].id.longGlb.offH == offH) and (id_arr[idx].id.longGlb.offH == offH) and
(id_arr[idx].id.longGlb.offL == offL)) (id_arr[idx].id.longGlb.offL == offL))
return (idx); return (idx);
} }
printf("%d",t); printf("%d",t);
/* Not in the table, create new identifier */ /* Not in the table, create new identifier */
id_arr.push_back(ID(t, LONGGLB_TYPE(seg,offH,offL))); id_arr.emplace_back(t, LONGGLB_TYPE(seg,offH,offL));
return (id_arr.size() - 1); return id_arr.size() - 1;
} }
@ -240,23 +240,20 @@ 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. */ * 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) 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 */ /* 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 */ if (/*(locSym->id[idx].type == t) and Not checking type */
(id_arr[idx].id.longGlb.seg == seg) and (id_arr[idx].id.longGlb.seg == seg) and
(id_arr[idx].id.longGlb.offH == offH) and (id_arr[idx].id.longGlb.offH == offH) and
(id_arr[idx].id.longGlb.offL == offL) and (id_arr[idx].id.longGlb.offL == offL) and
(id_arr[idx].id.longGlb.regi == regi)) (id_arr[idx].id.longGlb.regi == regi))
return (idx); return (idx);
} }
/* Not in the table, create new identifier */ /* Not in the table, create new identifier */
id_arr.push_back(ID(t,LONGGLB_TYPE(seg,offH,offL,regi))); id_arr.emplace_back(t,LONGGLB_TYPE(seg,offH,offL,regi));
idx = id_arr.size() - 1; return id_arr.size() - 1;
return (idx);
} }
@ -272,8 +269,8 @@ int LOCAL_ID::newLongStk(hlType t, int offH, int offL)
if(id_arr[idx].loc!=STK_FRAME) if(id_arr[idx].loc!=STK_FRAME)
continue; continue;
if ((id_arr[idx].type == t) and if ((id_arr[idx].type == t) and
(id_arr[idx].longStkId().offH == offH) and (id_arr[idx].longStkId().offH == offH) and
(id_arr[idx].longStkId().offL == offL)) (id_arr[idx].longStkId().offL == offL))
return (idx); return (idx);
} }
@ -282,7 +279,7 @@ int LOCAL_ID::newLongStk(hlType t, int offH, int offL)
flagByteWordId (offL); flagByteWordId (offL);
/* Create new identifier */ /* 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); return (id_arr.size() - 1);
} }
@ -294,7 +291,7 @@ int LOCAL_ID::newLong(opLoc sd, iICODE pIcode, hlFirst f, iICODE ix,operDu du, L
{ {
size_t idx = ~0; //WARNING: clients of this method might propagate this bogus value! size_t idx = ~0; //WARNING: clients of this method might propagate this bogus value!
const LLOperand *pmH, *pmL; const LLOperand *pmH, *pmL;
LLInst &p_ll(*pIcode->ll()); LLInst &p_ll(*pIcode->ll());
if (f == LOW_FIRST) if (f == LOW_FIRST)
{ {
pmL = p_ll.get(sd); pmL = p_ll.get(sd);
@ -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 */ else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */
printf ("long not supported, idx and no off\n"); 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; pmLdst = &atOffset.m_dst;
pmHsrc = &pIcode->ll()->src(); pmHsrc = &pIcode->ll()->src();
pmLsrc = &atOffset.src(); pmLsrc = &atOffset.src();
// if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off)) // if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off))
// { // {
// asgn.lhs = AstIdent::LongIdx (i); // asgn.lhs = AstIdent::LongIdx (i);
// if ( not pIcode->ll()->testFlags(NO_SRC) ) // if ( not pIcode->ll()->testFlags(NO_SRC) )
// { // {
// asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset); // asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset);
// } // }
// return true; // return true;
// } // }
// else if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off)) // 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.lhs = AstIdent::Long (&pProc->localId, DST, pIcode, HIGH_FIRST, pIcode,eDEF, atOffset);
// asgn.rhs = AstIdent::LongIdx (i); // asgn.rhs = AstIdent::LongIdx (i);
// return true; // return true;
// } // }
if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off)) if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
{ {
@ -403,7 +400,7 @@ bool checkLongEq (LONG_STKID_TYPE longId, iICODE pIcode, int i, Function * pProc
* pProc : ptr to current procedure record * pProc : ptr to current procedure record
* rhs, lhs : return expressions if successful. */ * rhs, lhs : return expressions if successful. */
bool checkLongRegEq (LONGID_TYPE longId, iICODE pIcode, int i, bool checkLongRegEq (LONGID_TYPE longId, iICODE pIcode, int i,
Function * pProc, Assignment &asgn, LLInst &atOffset) Function * pProc, Assignment &asgn, LLInst &atOffset)
{ {
/* pointers to LOW_LEVEL icodes */ /* pointers to LOW_LEVEL icodes */
const LLOperand *pmHdst, *pmLdst, *pmHsrc, *pmLsrc; const LLOperand *pmHdst, *pmLdst, *pmHsrc, *pmLsrc;
@ -431,33 +428,26 @@ bool checkLongRegEq (LONGID_TYPE longId, iICODE pIcode, int i,
return false; return false;
} }
/* Given an index into the local identifier table for a long register /* Given an index into the local identifier table for a long register
* variable, determines whether regi is the high or low part, and returns * variable, determines whether regi is the high or low part, and returns
* the other part */ * the other part */
eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl) eReg LOCAL_ID::getPairedRegisterAt(int idx,eReg regi) const
{ {
ID *id; eReg res=rUNDEF; // Cristina: please check this!
const ID *id = &id_arr[idx];
id = &locTbl->id_arr[idx]; if (id->isLongRegisterPair())
if ((id->loc == REG_FRAME) and ((id->type == TYPE_LONG_SIGN) or
(id->type == TYPE_LONG_UNSIGN)))
{ {
if (id->longId().h() == regi) res = id->getPairedRegister(regi);
return (id->longId().l());
else if (id->longId().l() == regi)
return (id->longId().h());
} }
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 * the local identifier table. If so, macros for these registers are
* placed in the local identifier table, as these registers belong to a * placed in the local identifier table, as these registers belong to a
* long register identifier. */ * long register identifier. */
void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name) void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name)
{ {
for (ID &rid : id_arr) for (ID &rid : id_arr)
@ -473,9 +463,9 @@ void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name)
if (rid.id.regi == regL) if (rid.id.regi == regL)
{ {
strcpy (rid.macro, "LO"); strcpy (rid.macro, "LO");
} }
else // if (rid.id.regi == regH) else // if (rid.id.regi == regH)
{ {
strcpy (rid.macro, "HI"); strcpy (rid.macro, "HI");
} }
} }

View File

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

View File

@ -2,40 +2,30 @@
* dcc project procedure list builder * dcc project procedure list builder
* (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann * (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
****************************************************************************/ ****************************************************************************/
#include "parser.h"
#include "dcc.h" #include "dcc.h"
#include "project.h" #include "project.h"
#include "CallGraph.h" #include "CallGraph.h"
#include "msvc_fixes.h" #include "msvc_fixes.h"
#include "chklib.h"
#include "FollowControlFlow.h"
#include <inttypes.h>
#include <string.h>
#include <stdlib.h> /* For exit() */
#include <sstream>
#include <stdio.h>
#include <algorithm>
#include <deque>
#include <QMap> #include <QMap>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <inttypes.h>
//TODO: The OS service resolution should be done iteratively: #include <cstring>
// for every unprocessed INT instruction, that calls OS service that does not terminate execution #include <cstdlib> /* For exit() */
// mark INT as non-termination instruction #include <cstdio>
// follow execution flow from next instruction #include <sstream>
// recheck OS services #include <algorithm>
#include <deque>
using namespace std; using namespace std;
//static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate); //static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
static void setBits(int16_t type, uint32_t start, uint32_t len); static void setBits(int16_t type, uint32_t start, uint32_t len);
static void process_MOV(LLInst &ll, STATE * pstate); static void process_MOV(LLInst &ll, STATE * pstate);
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph); static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
static bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate); void interactDis(Function * initProc, int ic);
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag); extern uint32_t SynthLab;
//void interactDis(Function * initProc, int ic);
/* Returns the size of the string pointed by sym and delimited by delim. /* Returns the size of the string pointed by sym and delimited by delim.
* Size includes delimiter. */ * Size includes delimiter. */
@ -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); const uint8_t *end_ptr=std::find(sym,sym+(prog.cbImage-(till_end)),delim);
return end_ptr-sym+1; return end_ptr-sym+1;
} }
ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
static std::vector<ICODE> rewrite_DIV(LLInst *ll, ICODE &_Icode)
{ {
ICODE synth_mov = ICODE(); // MOV rTMP, reg /* MOV rTMP, reg */
ICODE synth_mod = ICODE(); // MOD
synth_mov.type = LOW_LEVEL_ICODE; ICODE eIcode = ICODE();
synth_mov.ll()->set(iMOV,0,rTMP);
eIcode.type = LOW_LEVEL_ICODE;
eIcode.ll()->set(iMOV,0,rTMP);
if (ll->testFlags(B) ) if (ll->testFlags(B) )
{ {
synth_mov.ll()->setFlags( B ); eIcode.ll()->setFlags( B );
synth_mov.ll()->replaceSrc(rAX); eIcode.ll()->replaceSrc(rAX);
} }
else /* implicit dx:ax */ else /* implicit dx:ax */
{ {
synth_mov.ll()->setFlags( IM_SRC ); eIcode.ll()->setFlags( IM_SRC );
synth_mov.setRegDU( rDX, eUSE); eIcode.setRegDU( rDX, eUSE);
} }
synth_mov.setRegDU( rAX, eUSE); eIcode.setRegDU( rAX, eUSE);
synth_mov.setRegDU( rTMP, eDEF); eIcode.setRegDU( rTMP, eDEF);
synth_mov.ll()->setFlags( SYNTHETIC ); eIcode.ll()->setFlags( SYNTHETIC );
/* eIcode.ll()->label = Project::get()->SynthLab++; */ /* eIcode.ll()->label = SynthLab++; */
synth_mov.ll()->label = _Icode.ll()->label; eIcode.ll()->label = _Icode.ll()->label;
Icode.addIcode(&eIcode);
/* iDIV, iIDIV */
Icode.addIcode(&_Icode);
/* iMOD */ /* iMOD */
synth_mod.type = LOW_LEVEL_ICODE; eIcode = ICODE();
synth_mod.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST); eIcode.type = LOW_LEVEL_ICODE;
synth_mod.ll()->replaceSrc(_Icode.ll()->src()); eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
synth_mod.du = _Icode.du; eIcode.ll()->replaceSrc(_Icode.ll()->src());
synth_mod.ll()->label = Project::get()->SynthLab++; eIcode.du = _Icode.du;
return { eIcode.ll()->label = SynthLab++;
synth_mov, return Icode.addIcode(&eIcode);
_Icode,
synth_mod
};
} }
static std::vector<ICODE> rewrite_XCHG(LLInst *ll,ICODE &_Icode) ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
{ {
/* MOV rTMP, regDst */ /* MOV rTMP, regDst */
ICODE mov_tmp_dst; ICODE eIcode;
mov_tmp_dst.type = LOW_LEVEL_ICODE; eIcode.type = LOW_LEVEL_ICODE;
mov_tmp_dst.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst); eIcode.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
mov_tmp_dst.setRegDU( rTMP, eDEF); eIcode.setRegDU( rTMP, eDEF);
if(mov_tmp_dst.ll()->src().getReg2()) if(eIcode.ll()->src().getReg2())
{ {
eReg srcreg=mov_tmp_dst.ll()->src().getReg2(); eReg srcreg=eIcode.ll()->src().getReg2();
mov_tmp_dst.setRegDU( srcreg, eUSE); eIcode.setRegDU( srcreg, eUSE);
if((srcreg>=rAL) and (srcreg<=rBH)) 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 */ /* MOV regDst, regSrc */
ICODE mov_dst_src = _Icode; // copy all XCHG things, but set opcode to iMOV and mark it as synthetic insn ll->set(iMOV,SYNTHETIC|ll->getFlag());
mov_dst_src.ll()->set(iMOV,SYNTHETIC|ll->getFlag()); Icode.addIcode(&_Icode);
ll->setOpcode(iXCHG); /* for next case */
/* MOV regSrc, rTMP */ /* MOV regSrc, rTMP */
eIcode = ICODE();
ICODE mov_src_tmp; eIcode.type = LOW_LEVEL_ICODE;
mov_src_tmp.type = LOW_LEVEL_ICODE; eIcode.ll()->set(iMOV,SYNTHETIC);
mov_src_tmp.ll()->set(iMOV,SYNTHETIC); eIcode.ll()->replaceDst(ll->src());
mov_src_tmp.ll()->replaceDst(ll->src()); if(eIcode.ll()->m_dst.regi)
if(mov_src_tmp.ll()->m_dst.regi)
{ {
if((mov_src_tmp.ll()->m_dst.regi>=rAL) and (mov_src_tmp.ll()->m_dst.regi<=rBH)) if((eIcode.ll()->m_dst.regi>=rAL) and (eIcode.ll()->m_dst.regi<=rBH))
mov_src_tmp.ll()->setFlags( B ); eIcode.ll()->setFlags( B );
mov_src_tmp.setRegDU( mov_src_tmp.ll()->m_dst.regi, eDEF); eIcode.setRegDU( eIcode.ll()->m_dst.regi, eDEF);
} }
mov_src_tmp.ll()->replaceSrc(rTMP); eIcode.ll()->replaceSrc(rTMP);
mov_src_tmp.setRegDU( rTMP, eUSE); eIcode.setRegDU( rTMP, eUSE);
mov_src_tmp.ll()->label = Project::get()->SynthLab++; eIcode.ll()->label = SynthLab++;
return { return Icode.addIcode(&eIcode);
mov_tmp_dst,
mov_dst_src,
mov_src_tmp
};
}
/**
* @brief resolveOSServices
* @param ll
* @param pstate
* @return true if given OS service will terminate the program
*/
//TODO: convert into Command class
static bool resolveOSServices(LLInst *ll, STATE *pstate)
{
PROG &prog(Project::get()->prog);
SYMTAB &global_symbol_table(Project::get()->symtab);
bool terminates=false;
if(pstate->isKnown(rAX))
assert(pstate->isKnown(rAH));
if (ll->src().getImm2() == 0x21 and pstate->isKnown(rAH))
{
int funcNum = pstate->r[rAH];
int operand;
int size;
/* Save function number */
ll->m_dst.off = (int16_t)funcNum;
//Icode.GetIcode(Icode.GetNumIcodes() - 1)->
/* Program termination: int21h, fn 00h, 31h, 4Ch */
terminates = (bool)(funcNum == 0x00 or funcNum == 0x31 or funcNum == 0x4C);
/* String functions: int21h, fn 09h */
/* offset goes into DX */
if (pstate->isKnown(rDX))
if (funcNum == 0x09)
{
operand = ((uint32_t)(uint16_t)pstate->r[rDS]<<4) + (uint32_t)(uint16_t)pstate->r[rDX];
size = prog.fCOM ?
strSize (&prog.image()[operand], '$') :
strSize (&prog.image()[operand], '$'); // + 0x100
global_symbol_table.updateSymType (operand, TypeContainer(TYPE_STR, size));
}
}
else if ((ll->src().getImm2() == 0x2F) and pstate->isKnown(rAH))
{
ll->m_dst.off = pstate->r[rAH];
}
else /* Program termination: int20h, int27h */
terminates = (ll->src().getImm2() == 0x20 or ll->src().getImm2() == 0x27);
return terminates;
} }
/** FollowCtrl - Given an initial procedure, state information and symbol table /** FollowCtrl - Given an initial procedure, state information and symbol table
* builds a list of procedures reachable from the initial procedure * builds a list of procedures reachable from the initial procedure
* using a depth first search. */ * using a depth first search. */
void 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); PROG &prog(Project::get()->prog);
ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */ ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
SYM * psym; SYM * psym;
uint32_t offset; uint32_t offset;
eErrorId err; eErrorId err;
bool done = false; bool done = false;
SYMTAB &global_symbol_table(Project::get()->symtab);
if (func.name.contains("chkstk")) if (name.contains("chkstk"))
{ {
// Danger! Dcc will likely fall over in this code. // Danger! Dcc will likely fall over in this code.
// So we act as though we have done with this proc // So we act as though we have done with this proc
// pProc->flg &= ~TERMINATES; // Not sure about this // pProc->flg &= ~TERMINATES; // Not sure about this
done = true;
// And mark it as a library function, so structure() won't choke on it // And mark it as a library function, so structure() won't choke on it
func.flg |= PROC_ISLIB; flg |= PROC_ISLIB;
return; return;
} }
if (option.VeryVerbose) 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 ) while (not done )
@ -207,37 +145,31 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
break; break;
LLInst *ll = _Icode.ll(); LLInst *ll = _Icode.ll();
pstate->IP += (uint32_t)ll->numBytes; pstate->IP += (uint32_t)ll->numBytes;
setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes); setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes);
func.process_operands(_Icode,pstate); process_operands(_Icode,pstate);
/* Keep track of interesting instruction flags in procedure */ /* 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 */ /* Check if this instruction has already been parsed */
iICODE labLoc = func.Icode.labelSrch(ll->label); iICODE labLoc = Icode.labelSrch(ll->label);
if (func.Icode.end()!=labLoc) if (Icode.end()!=labLoc)
{ /* Synthetic jump */ { /* Synthetic jump */
_Icode.type = LOW_LEVEL_ICODE; _Icode.type = LOW_LEVEL_ICODE;
ll->set(iJMP,I | SYNTHETIC | NO_OPS); ll->set(iJMP,I | SYNTHETIC | NO_OPS);
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel())); ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
ll->label = Project::get()->SynthLab++; ll->label = SynthLab++;
} }
/* Copy Icode to Proc */ /* Copy Icode to Proc */
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV)) { if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV))
std::vector<ICODE> translated = rewrite_DIV(ll,_Icode); pIcode = translate_DIV(ll, _Icode);
for(const ICODE &ic : translated) else if (_Icode.ll()->getOpcode() == iXCHG)
pIcode = func.Icode.addIcode(&ic); pIcode = translate_XCHG(ll, _Icode);
} else
else if (_Icode.ll()->getOpcode() == iXCHG) { pIcode = Icode.addIcode(&_Icode);
std::vector<ICODE> translated = rewrite_XCHG(ll,_Icode);
for(const ICODE &ic : translated)
pIcode = func.Icode.addIcode(&ic);
}
else {
pIcode = func.Icode.addIcode(&_Icode);
}
switch (ll->getOpcode()) { switch (ll->getOpcode()) {
/*** Conditional jumps ***/ /*** Conditional jumps ***/
@ -249,49 +181,51 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
case iJCXZ: case iJCXZ:
{ {
STATE StCopy; STATE StCopy;
int ip = func.Icode.size()-1; /* Index of this jump */ uint32_t lastIp = pstate->IP - 2;
ICODE &prev(*(++func.Icode.rbegin())); /* Previous icode */ int ip = Icode.size()-1; /* Index of this jump */
ICODE &prev(*(++Icode.rbegin())); /* Previous icode */
bool fBranch = false; bool fBranch = false;
pstate->JCond.regi = 0; pstate->JCond.regi = 0;
/* This sets up range check for indexed JMPs hopefully /* This sets up range check for indexed JMPs hopefully
* Handles JA/JAE for fall through and JB/JBE on branch * Handles JA/JAE for fall through and JB/JBE on branch
*/ */
if (ip > 0 and prev.ll()->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(); pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2();
if (ll->match(iJA) or ll->match(iJBE) ) if (ll->match(iJA) or ll->match(iJBE) )
pstate->JCond.immed++; pstate->JCond.immed++;
if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA) if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA)
pstate->JCond.regi = prev.ll()->m_dst.regi; pstate->JCond.regi = prev.ll()->m_dst.regi;
fBranch = (ll->getOpcode() == iJB or ll->getOpcode() == iJBE); fBranch = (bool) (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
} }
StCopy = *pstate; StCopy = *pstate;
//printf("From %X condJump to %X\n", lastIp, pstate->IP);
/* Straight line code */ /* Straight line code */
project->addCommand(func.shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ? this->FollowCtrl (pcallGraph, &StCopy); // recurrent ?
if (fBranch) /* Do branching code */ if (fBranch) /* Do branching code */
{ {
pstate->JCond.regi = prev.ll()->m_dst.regi; pstate->JCond.regi = prev.ll()->m_dst.regi;
} }
/* Next icode. Note: not the same as GetLastIcode() because of the call to FollowCtrl() */ /* Next icode. Note: not the same as GetLastIcode() because of the call
pIcode = func.Icode.GetIcode(ip); to FollowCtrl() */
/* do the jump path */ pIcode = Icode.GetIcode(ip);
done = process_JMP(func.shared_from_this(),*pIcode, pstate, pcallGraph); } /* Fall through to do the jump path */
break;
}
/*** Jumps ***/ /*** Jumps ***/
case iJMP: case iJMP:
case iJMPF: /* Returns true if we've run into a loop */ case iJMPF: /* Returns true if we've run into a loop */
done = process_JMP (func.shared_from_this(),*pIcode, pstate, pcallGraph); done = process_JMP (*pIcode, pstate, pcallGraph);
break; break;
/*** Calls ***/ /*** Calls ***/
case iCALL: case iCALL:
case iCALLF: case iCALLF:
done = process_CALL(func.shared_from_this(),*pIcode, pcallGraph, pstate); done = process_CALL (*pIcode, pcallGraph, pstate);
pstate->kill(rBX); pstate->kill(rBX);
pstate->kill(rCX); pstate->kill(rCX);
break; break;
@ -299,17 +233,46 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
/*** Returns ***/ /*** Returns ***/
case iRET: case iRET:
case iRETF: case iRETF:
func.flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR; this->flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
func.flg &= ~TERMINATES; /* Fall through */
done = true;
break;
case iIRET: case iIRET:
func.flg &= ~TERMINATES; this->flg &= ~TERMINATES;
done = true; done = true;
break; break;
case iINT: 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) if (done)
pIcode->ll()->setFlags(TERMINATES); pIcode->ll()->setFlags(TERMINATES);
break; break;
@ -317,10 +280,16 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
case iMOV: case iMOV:
process_MOV(*pIcode->ll(), pstate); process_MOV(*pIcode->ll(), pstate);
break; break;
/* case iXCHG:
process_MOV (pIcode, pstate);
break; **** HERE ***/
case iSHL: case iSHL:
if (pstate->JCond.regi == ll->m_dst.regi) if (pstate->JCond.regi == ll->m_dst.regi)
{ {
if (ll->srcIsImmed() and ll->src().getImm2() == 1) if ((ll->testFlags(I)) and ll->src().getImm2() == 1)
pstate->JCond.immed *= 2; pstate->JCond.immed *= 2;
else else
pstate->JCond.regi = 0; pstate->JCond.regi = 0;
@ -337,7 +306,7 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
/* and (Icode.ll()->flg & SEG_IMMED) */ ) /* and (Icode.ll()->flg & SEG_IMMED) */ )
{ {
offset = LH(&prog.image()[psym->label]); offset = LH(&prog.image()[psym->label]);
pstate->setState( (ll->getOpcode() == iLDS)? rDS : rES, pstate->setState( (ll->getOpcode() == iLDS)? rDS: rES,
LH(&prog.image()[psym->label + 2])); LH(&prog.image()[psym->label + 2]));
pstate->setState( ll->m_dst.regi, (int16_t)offset); pstate->setState( ll->m_dst.regi, (int16_t)offset);
psym->type = TYPE_PTR; psym->type = TYPE_PTR;
@ -347,12 +316,12 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
} }
if (err) { if (err) {
func.flg &= ~TERMINATES; this->flg &= ~TERMINATES;
if (err == INVALID_386OP or err == INVALID_OPCODE) if (err == INVALID_386OP or err == INVALID_OPCODE)
{ {
fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label); fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label);
func.flg |= PROC_BADINST; this->flg |= PROC_BADINST;
} }
else if (err == IP_OUT_OF_RANGE) else if (err == IP_OUT_OF_RANGE)
fatalError (err, _Icode.ll()->label); fatalError (err, _Icode.ll()->label);
@ -376,7 +345,34 @@ void Function::extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &ta
table.finish = table.start + 2; 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); PROG &prog(Project::get()->prog);
// mov cx,NUM_CASES // 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] // jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP}; static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(func->Icode.size()<8) if(Icode.size()<8)
return false; 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; return false;
if(pIcode.ll()->src().regi != INDEX_BX) { if(pIcode.ll()->src().regi != INDEX_BX) {
return false; return false;
@ -403,7 +399,7 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
// find address-wise predecessors of the icode // find address-wise predecessors of the icode
std::deque<ICODE *> matched; std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap; QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : func->Icode) { for(ICODE & ic : Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic; addrmap[ic.ll()->GetLlLabel()] = &ic;
} }
auto iter = addrmap.find(pIcode.ll()->GetLlLabel()); auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -416,11 +412,11 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
// pattern starts at the last jmp // pattern starts at the last jmp
ICODE *load_num_cases = matched[0]; ICODE *load_num_cases = matched[0];
ICODE *load_jump_table_addr = matched[1]; ICODE *load_jump_table_addr = matched[1];
// ICODE *read_case_entry_insn = matched[2]; ICODE *read_case_entry_insn = matched[2];
// ICODE *cmp_case_val_insn = matched[3]; ICODE *cmp_case_val_insn = matched[3];
// ICODE *exit_loop_insn = matched[4]; ICODE *exit_loop_insn = matched[4];
// ICODE *add_bx_insn = matched[5]; ICODE *add_bx_insn = matched[5];
// ICODE *loop_insn = matched[6]; ICODE *loop_insn = matched[6];
ICODE *default_jmp = matched[7]; ICODE *default_jmp = matched[7];
ICODE *last_jmp = matched[8]; ICODE *last_jmp = matched[8];
for(int i=0; i<8; ++i) { for(int i=0; i<8; ++i) {
@ -453,12 +449,16 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
STATE StCopy = *pstate; STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*2 + i*2; uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
Project::get()->addCommand(func,new FollowControlFlow(StCopy)); iICODE last_current_insn = (++Icode.rbegin()).base();
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i)); 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; 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); PROG &prog(Project::get()->prog);
// mov cx,NUM_CASES // 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] // jmp word ptr [bx+2*NUM_CASES]
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP}; static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
if(func->Icode.size()<12) if(Icode.size()<12)
return false; 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; return false;
if(pIcode.ll()->src().regi != INDEX_BX) { if(pIcode.ll()->src().regi != INDEX_BX) {
return false; return false;
@ -489,7 +489,7 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
// find address-wise predecessors of the icode // find address-wise predecessors of the icode
std::deque<ICODE *> matched; std::deque<ICODE *> matched;
QMap<uint32_t,ICODE *> addrmap; QMap<uint32_t,ICODE *> addrmap;
for(ICODE & ic : func->Icode) { for(ICODE & ic : Icode) {
addrmap[ic.ll()->GetLlLabel()] = &ic; addrmap[ic.ll()->GetLlLabel()] = &ic;
} }
auto iter = addrmap.find(pIcode.ll()->GetLlLabel()); auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
@ -535,19 +535,54 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
STATE StCopy = *pstate; STATE StCopy = *pstate;
uint32_t jump_target_location = table_addr + num_cases*4 + i*2; uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location); StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
Project::get()->addCommand(func,new FollowControlFlow(StCopy)); iICODE last_current_insn = (++Icode.rbegin()).base();
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i)); 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; return true;
} }
/* Look for switch() stmt. idiom of the form bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */ {
static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *pstate) {
const static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
uint32_t seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
ICODE _Icode;
uint32_t 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 */ /* Ensure we have a uint16_t offset & valid seg */
if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and
@ -557,9 +592,8 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
pIcode.ll()->src().regi == INDEX_BX)) pIcode.ll()->src().regi == INDEX_BX))
{ {
uint32_t offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off; offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
uint32_t endTable;
uint32_t i;
/* Firstly look for a leading range check of the form:- /* Firstly look for a leading range check of the form:-
* CMP {BX | SI | DI}, immed * CMP {BX | SI | DI}, immed
* JA | JAE | JB | JBE * JA | JAE | JB | JBE
@ -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 /* Now do some heuristic pruning. Look for ptrs. into the table
* and for addresses that don't appear to point to valid code. * and for addresses that don't appear to point to valid code.
*/ */
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) 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) if (target < endTable and target >= offTable)
endTable = target; endTable = target;
else if (target >= (uint32_t)prog.cbImage) 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) 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 */ /* Be wary of 00 00 as code - it's probably data */
ICODE _Icode; if (not (prog.image()[target] or prog.image()[target+1]) or
if (not (prog.image()[target] or prog.image()[target+1]) or scan(target, _Icode)!=NO_ERR) scan(target, _Icode))
endTable = i; endTable = i;
} }
@ -611,56 +645,37 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
setBits(BM_DATA, offTable, endTable - offTable); setBits(BM_DATA, offTable, endTable - offTable);
pIcode.ll()->setFlags(SWITCH); pIcode.ll()->setFlags(SWITCH);
//pIcode.ll()->caseTbl2.numEntries = (endTable - offTable) / 2;
uint32_t k;
for (i = offTable, k = 0; i < endTable; i += 2) for (i = offTable, k = 0; i < endTable; i += 2)
{ {
StCopy = *pstate; StCopy = *pstate;
StCopy.IP = cs + LH(&prog.image()[i]); StCopy.IP = cs + LH(&prog.image()[i]);
Project::get()->addCommand(func,new FollowControlFlow(StCopy)); iICODE last_current_insn = (++Icode.rbegin()).base();
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,k++)); //ip = Icode.size();
FollowCtrl (pcallGraph, &StCopy);
++last_current_insn;
last_current_insn->ll()->caseEntry = k++;
last_current_insn->ll()->setFlags(CASE);
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
} }
return true; return true;
} }
} }
return false; if(decodeIndirectJMP(pIcode,pstate,pcallGraph)) {
}
/* process_JMP - Handles JMPs, returns true if we should end recursion */
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
{
PROG &prog(Project::get()->prog);
if (pIcode.ll()->srcIsImmed())
{
if (pIcode.ll()->getOpcode() == iJMPF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
pstate->IP = pIcode.ll()->src().getImm2();
int64_t i = pIcode.ll()->src().getImm2();
if (i < 0)
{
exit(1);
}
/* Return true if jump target is already parsed */
return func->Icode.alreadyDecoded(i);
}
/* We've got an indirect JMP */
if(decodeIndirectJMP0(func,pIcode,pstate)) {
return true; return true;
} }
if(decodeIndirectJMP(func,pIcode,pstate)) { if(decodeIndirectJMP2(pIcode,pstate,pcallGraph)) {
return true;
}
if(decodeIndirectJMP2(func,pIcode,pstate)) {
return true; return true;
} }
/* Can't do anything with this jump */ /* Can't do anything with this jump */
func->flg |= PROC_IJMP; flg |= PROC_IJMP;
func->flg &= ~TERMINATES; flg &= ~TERMINATES;
// TODO: consider adding a new user-interactive command ResolveControlFlowFailure ? interactDis(this, this->Icode.size()-1);
interactDis(func, func->Icode.size()-1);
return true; 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 * programmer expected it to come back - otherwise surely a JMP would
* have been used. */ * 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); 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; uint32_t off;
/* For Indirect Calls, find the function address */ /* For Indirect Calls, find the function address */
bool indirect = false; bool indirect = false;
//pIcode.ll()->immed.proc.proc=fakeproc; //pIcode.ll()->immed.proc.proc=fakeproc;
if ( not pIcode.ll()->srcIsImmed() ) if ( not pIcode.ll()->testFlags(I) )
{ {
/* Not immediate, i.e. indirect call */ /* 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) if (pIcode.ll()->getOpcode() == iCALLF)
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4); tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4);
else else
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)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()->replaceSrc(LLOperand::CreateImm2( tgtAddr ) );
pIcode.ll()->setFlags(I); pIcode.ll()->setFlags(I);
indirect = true; indirect = true;
} }
/* Process CALL. Function address is located in pIcode.ll()->immed.op */ /* Process CALL. Function address is located in pIcode.ll()->immed.op */
if (pIcode.ll()->srcIsImmed()) if (pIcode.ll()->testFlags(I))
{ {
/* Search procedure list for one with appropriate entry point */ /* 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 */ /* 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); Function &x(*iter);
if(project.m_pattern_locator) x.procEntry = pIcode.ll()->src().getImm2();
project.m_pattern_locator->LibCheck(x); LibCheck(x);
if (x.flg & PROC_ISLIB) if (x.flg & PROC_ISLIB)
{ {
/* A library function. No need to do any more to it */ /* A library function. No need to do any more to it */
pcallGraph->insertCallGraph (func, iter); pcallGraph->insertCallGraph (this, iter);
//iter = (++pProcList.rbegin()).base(); //iter = (++pProcList.rbegin()).base();
last_insn.ll()->src().proc.proc = &x; last_insn.ll()->src().proc.proc = &x;
return false; return false;
@ -767,27 +783,38 @@ bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGrap
x.depth = x.depth + 1; x.depth = x.depth + 1;
x.flg |= TERMINATES; x.flg |= TERMINATES;
/* Save machine state in localState, load up IP and CS.*/
localState = *pstate;
pstate->IP = pIcode.ll()->src().getImm2(); pstate->IP = pIcode.ll()->src().getImm2();
if (pIcode.ll()->getOpcode() == iCALLF) if (pIcode.ll()->getOpcode() == iCALLF)
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3)); pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
x.state = *pstate; x.state = *pstate;
/* Insert new procedure in call graph */ /* Insert new procedure in call graph */
pcallGraph->insertCallGraph (func, iter); - pcallGraph->insertCallGraph (this, iter);
//printf("From %X CALL to %X\n", lastIp, pstate->IP);
/* Process new procedure */ /* 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 else
Project::get()->callGraph->insertCallGraph (func, iter); Project::get()->callGraph->insertCallGraph (this, iter);
last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc
/* return ((p->flg & TERMINATES) != 0); */ /* return ((p->flg & TERMINATES) != 0); */
} }
return false; // Cristina, please check!! return false; // Cristina, please check!!
} }
@ -800,7 +827,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
uint8_t srcReg = ll.src().regi; uint8_t srcReg = ll.src().regi;
if (dstReg > 0 and dstReg < INDEX_BX_SI) if (dstReg > 0 and dstReg < INDEX_BX_SI)
{ {
if (ll.srcIsImmed()) if (ll.testFlags(I))
pstate->setState( dstReg, (int16_t)ll.src().getImm2()); pstate->setState( dstReg, (int16_t)ll.src().getImm2());
else if (srcReg == 0) /* direct memory offset */ else if (srcReg == 0) /* direct memory offset */
{ {
@ -857,7 +884,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]); pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]);
if(psym->size>1) if(psym->size>1)
{ {
pstate->setMemoryByte(psym->label,uint8_t(pstate->r[srcReg]>>8)); pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]>>8);
//prog.image()[psym->label+1] = (uint8_t)(pstate->r[srcReg] >> 8); //prog.image()[psym->label+1] = (uint8_t)(pstate->r[srcReg] >> 8);
} }
psym->duVal.setFlags(eDuVal::DEF); psym->duVal.setFlags(eDuVal::DEF);
@ -905,8 +932,8 @@ void STKFRAME::updateFrameOff ( int16_t off, int _size, uint16_t duFlag)
} }
/* Save maximum argument offset */ /* Save maximum argument offset */
if ((uint32_t)this->m_maxOff < (off + (uint32_t)_size)) if ((uint32_t)this->maxOff < (off + (uint32_t)_size))
this->m_maxOff = off + (int16_t)_size; this->maxOff = off + (int16_t)_size;
} }
@ -1005,7 +1032,7 @@ static void setBits(int16_t type, uint32_t start, uint32_t len)
for (i = start + len - 1; i >= start; i--) for (i = start + len - 1; i >= start; i--)
{ {
prog.map[i >> 2] |= type << ((i & 3) << 1); prog.map[i >> 2] |= type << ((i & 3) << 1);
if (i == 0) break; // Fixes inf loop! if (i == 0) break; // Fixes inf loop!
} }
} }
} }
@ -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->regi == INDEX_BP) /* indexed on bp */
{ {
if (pm->off >= 2) { if (pm->off >= 2)
pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE); pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE);
}
else if (pm->off < 0) else if (pm->off < 0)
pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0); pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
} }
@ -1062,7 +1088,7 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
} }
/* Use of register */ /* Use of register */
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed()))) else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I))))
pIcode.du.use.addReg(pm->regi); 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 */ /* 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)); assert(not pIcode.ll()->match(iPUSH));
pIcode.du1.addDef(pm->regi); 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 sseg = (ll_ins.src().seg)? ll_ins.src().seg: rDS;
int cb = pIcode.ll()->testFlags(B) ? 1: 2; int cb = pIcode.ll()->testFlags(B) ? 1: 2;
//x86_op_t *im= pIcode.insn.x86_get_imm(); //x86_op_t *im= pIcode.insn.x86_get_imm();
bool Imm = (pIcode.ll()->srcIsImmed()); bool Imm = (pIcode.ll()->testFlags(I));
switch (pIcode.ll()->getOpcode()) { switch (pIcode.ll()->getOpcode()) {
case iAND: case iOR: case iXOR: case iAND: case iOR: case iXOR:
@ -1166,8 +1192,8 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
case iXCHG: case iXCHG:
/* This instruction is replaced by 3 instructions, only need /* This instruction is replaced by 3 instructions, only need
* to define the src operand and use the destination operand * to define the src operand and use the destination operand
* in the mean time.*/ * in the mean time. */
use(SRC, pIcode, this, pstate, cb); use(SRC, pIcode, this, pstate, cb);
def(DST, pIcode, this, pstate, cb); def(DST, pIcode, this, pstate, cb);
break; break;
@ -1265,9 +1291,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
use(SRC, pIcode, this, pstate, cb); use(SRC, pIcode, this, pstate, cb);
break; break;
case iLOOP: case iLOOP: case iLOOPE: case iLOOPNE:
case iLOOPE:
case iLOOPNE:
pIcode.du.def.addReg(rCX); pIcode.du.def.addReg(rCX);
pIcode.du1.addDef(rCX); pIcode.du1.addDef(rCX);
case iJCXZ: case iJCXZ:
@ -1322,8 +1346,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
pIcode.du.use.addReg(rDX).addReg(sseg); pIcode.du.use.addReg(rDX).addReg(sseg);
break; break;
case iIN: case iIN: case iOUT:
case iOUT:
def(DST, pIcode, this, pstate, cb); def(DST, pIcode, this, pstate, cb);
if (not Imm) 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 <cstring>
#include <cassert> #include <cassert>
extern Project g_proj;
/* Static indentation buffer */ /* Static indentation buffer */
static constexpr int indSize=81; /* size of indentation buffer; max 20 */ static constexpr int indSize=81; /* size of indentation buffer; max 20 */
static char indentBuf[indSize] = static char indentBuf[indSize] =
@ -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 /* Inserts an outEdge at the current callGraph pointer if the newProc does
* not exist. */ * not exist. */
void CALL_GRAPH::insertArc (PtrFunction newProc) void CALL_GRAPH::insertArc (ilFunction newProc)
{ {
@ -43,23 +44,23 @@ void CALL_GRAPH::insertArc (PtrFunction newProc)
/* Inserts a (caller, callee) arc in the call graph tree. */ /* Inserts a (caller, callee) arc in the call graph tree. */
bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee) bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
{ {
if (proc == caller) if (proc == caller)
{ {
insertArc (callee); insertArc (callee);
return true; return true;
} }
for (CALL_GRAPH *edg : outEdges) for (CALL_GRAPH *edg : outEdges)
if (edg->insertCallGraph (caller, callee)) if (edg->insertCallGraph (caller, callee))
return true; return true;
return false; return false;
} }
//bool CALL_GRAPH::insertCallGraph(PtrFunction &caller, PtrFunction &callee) bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee)
//{ {
// return insertCallGraph(caller,callee); return insertCallGraph(Project::get()->funcIter(caller),callee);
//} }
/* Displays the current node of the call graph, and invokes recursively on /* Displays the current node of the call graph, and invokes recursively on
@ -87,7 +88,7 @@ void CALL_GRAPH::write()
/* Updates the argument table by including the register(s) (ie. lhs of /* Updates the argument table by including the register(s) (ie. lhs of
* picode) and the actual expression (ie. rhs of picode). * picode) and the actual expression (ie. rhs of picode).
* Note: register(s) are only included once in the table. */ * 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; AstIdent *lhs;
STKFRAME * call_args_stackframe, *target_stackframe; STKFRAME * call_args_stackframe, *target_stackframe;
@ -97,16 +98,16 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
condId type; condId type;
Function * tproc; Function * tproc;
eReg regL = rUNDEF; eReg regL = rUNDEF;
eReg regH; /* Registers involved in arguments */ eReg regH; /* Registers involved in arguments */
/* Flag ticode as having register arguments */ /* Flag ticode as having register arguments */
tproc = ticode->hl()->call.proc; tproc = ticode.hl()->call.proc;
tproc->flg |= REG_ARGS; tproc->flg |= REG_ARGS;
/* Get registers and index into target procedure's local list */ /* 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; 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); RegisterNode *lhs_reg = dynamic_cast<RegisterNode *>(lhs);
assert(lhs); assert(lhs);
type = lhs->ident.type(); type = lhs->ident.type();
@ -187,13 +188,13 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
/* Do ps (actual arguments) */ /* Do ps (actual arguments) */
STKSYM newsym; STKSYM newsym;
newsym.setArgName(call_args_stackframe->size()); newsym.setArgName(call_args_stackframe->size());
newsym.actual = picode->hl()->asgn.m_rhs; newsym.actual = picode.hl()->asgn.m_rhs;
newsym.regs = lhs; newsym.regs = lhs;
/* Mask off high and low register(s) in picode */ /* Mask off high and low register(s) in picode */
switch (type) { switch (type) {
case REGISTER: case REGISTER:
id = &id_arr[lhs_reg->regiIdx]; 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) if (id->id.regi < rAL)
newsym.type = TYPE_WORD_SIGN; newsym.type = TYPE_WORD_SIGN;
else else
@ -201,8 +202,8 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
break; break;
case LONG_VAR: case LONG_VAR:
id = &id_arr[lhs->ident.idNode.longIdx]; id = &id_arr[lhs->ident.idNode.longIdx];
picode->du.def.clrReg(id->longId().h()); picode.du.def.clrReg(id->longId().h());
picode->du.def.clrReg(id->longId().l()); picode.du.def.clrReg(id->longId().l());
newsym.type = TYPE_LONG_SIGN; newsym.type = TYPE_LONG_SIGN;
break; break;
default: default:
@ -245,7 +246,7 @@ bool CallType::newStkArg(Expr *exp, llIcode opcode, Function * pproc)
/* Places the actual argument exp in the position given by pos in the /* Places the actual argument exp in the position given by pos in the
* argument list of picode. */ * argument list of picode. */
void CallType::placeStkArg (Expr *exp, int pos) void CallType::placeStkArg (Expr *exp, int pos)
{ {
(*args)[pos].actual = exp; (*args)[pos].actual = exp;
@ -289,7 +290,7 @@ Expr *Function::adjustActArgType (Expr *_exp, hlType forType)
case TYPE_STR: case TYPE_STR:
switch (actType) { switch (actType) {
case TYPE_CONST: case TYPE_CONST:
/* It's an offset into image where a string is found. Point to the string. */ /* It's an offset into image where a string is found. Point to the string. */
{ {
Constant *c=dynamic_cast<Constant *>(expr); Constant *c=dynamic_cast<Constant *>(expr);
assert(c); assert(c);

View File

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

View File

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

View File

@ -1,4 +1,4 @@
/** /*****************************************************************************
* dcc project scanner module * dcc project scanner module
* Implements a simple state driven scanner to convert 8086 machine code into * Implements a simple state driven scanner to convert 8086 machine code into
* I-code * I-code
@ -19,7 +19,6 @@
#define S_EXT 0x000200 /* sign extend */ #define S_EXT 0x000200 /* sign extend */
#define OP386 0x000400 /* 386 op-code */ #define OP386 0x000400 /* 386 op-code */
#define NSP 0x000800 /* NOT_HLL if SP is src or dst */ #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 rm(int i);
static void modrm(int i); static void modrm(int i);
@ -51,15 +50,15 @@ static void none1(int i);
static void none2(int i); static void none2(int i);
static void checkInt(int i); static void checkInt(int i);
#define iZERO (llIcode)0 // For neatness
#define IC llIcode #define IC llIcode
static struct { struct StateTabelEntry {
void (*state1)(int); void (*state1)(int);
void (*state2)(int); void (*state2)(int);
uint32_t flg; uint32_t flg;
llIcode opcode; llIcode opcode;
} stateTable[] = { };
static const StateTabelEntry stateTable[] = {
{ modrm, none2, B , iADD }, /* 00 */ { modrm, none2, B , iADD }, /* 00 */
{ modrm, none2, 0 , iADD }, /* 01 */ { modrm, none2, 0 , iADD }, /* 01 */
{ modrm, none2, TO_REG | B , iADD }, /* 02 */ { modrm, none2, TO_REG | B , iADD }, /* 02 */
@ -69,258 +68,258 @@ static struct {
{ segop, none2, NO_SRC , iPUSH }, /* 06 */ { segop, none2, NO_SRC , iPUSH }, /* 06 */
{ segop, none2, NO_SRC , iPOP }, /* 07 */ { segop, none2, NO_SRC , iPOP }, /* 07 */
{ modrm, none2, B , iOR }, /* 08 */ { modrm, none2, B , iOR }, /* 08 */
{ modrm, none2, NSP , iOR }, /* 09 */ { modrm, none2, NSP , iOR }, /* 09 */
{ modrm, none2, TO_REG | B , iOR }, /* 0A */ { modrm, none2, TO_REG | B , iOR }, /* 0A */
{ modrm, none2, TO_REG | NSP , iOR }, /* 0B */ { modrm, none2, TO_REG | NSP , iOR }, /* 0B */
{ data1, axImp, B , iOR }, /* 0C */ { data1, axImp, B , iOR }, /* 0C */
{ data2, axImp, 0 , iOR }, /* 0D */ { data2, axImp, 0 , iOR }, /* 0D */
{ segop, none2, NO_SRC , iPUSH }, /* 0E */ { segop, none2, NO_SRC , iPUSH }, /* 0E */
{ none1, none2, OP386 , iZERO }, /* 0F */ { none1, none2, OP386 , iINVALID }, /* 0F */
{ modrm, none2, B , iADC }, /* 10 */ { modrm, none2, B , iADC }, /* 10 */
{ modrm, none2, NSP , iADC }, /* 11 */ { modrm, none2, NSP , iADC }, /* 11 */
{ modrm, none2, TO_REG | B , iADC }, /* 12 */ { modrm, none2, TO_REG | B , iADC }, /* 12 */
{ modrm, none2, TO_REG | NSP , iADC }, /* 13 */ { modrm, none2, TO_REG | NSP , iADC }, /* 13 */
{ data1, axImp, B , iADC }, /* 14 */ { data1, axImp, B , iADC }, /* 14 */
{ data2, axImp, 0 , iADC }, /* 15 */ { data2, axImp, 0 , iADC }, /* 15 */
{ segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */ { segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */
{ segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */ { segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */
{ modrm, none2, B , iSBB }, /* 18 */ { modrm, none2, B , iSBB }, /* 18 */
{ modrm, none2, NSP , iSBB }, /* 19 */ { modrm, none2, NSP , iSBB }, /* 19 */
{ modrm, none2, TO_REG | B , iSBB }, /* 1A */ { modrm, none2, TO_REG | B , iSBB }, /* 1A */
{ modrm, none2, TO_REG | NSP , iSBB }, /* 1B */ { modrm, none2, TO_REG | NSP , iSBB }, /* 1B */
{ data1, axImp, B , iSBB }, /* 1C */ { data1, axImp, B , iSBB }, /* 1C */
{ data2, axImp, 0 , iSBB }, /* 1D */ { data2, axImp, 0 , iSBB }, /* 1D */
{ segop, none2, NO_SRC , iPUSH }, /* 1E */ { segop, none2, NO_SRC , iPUSH }, /* 1E */
{ segop, none2, NO_SRC , iPOP }, /* 1F */ { segop, none2, NO_SRC , iPOP }, /* 1F */
{ modrm, none2, B , iAND }, /* 20 */ { modrm, none2, B , iAND }, /* 20 */
{ modrm, none2, NSP , iAND }, /* 21 */ { modrm, none2, NSP , iAND }, /* 21 */
{ modrm, none2, TO_REG | B , iAND }, /* 22 */ { modrm, none2, TO_REG | B , iAND }, /* 22 */
{ modrm, none2, TO_REG | NSP , iAND }, /* 23 */ { modrm, none2, TO_REG | NSP , iAND }, /* 23 */
{ data1, axImp, B , iAND }, /* 24 */ { data1, axImp, B , iAND }, /* 24 */
{ data2, axImp, 0 , iAND }, /* 25 */ { data2, axImp, 0 , iAND }, /* 25 */
{ prefix, none2, 0 , (IC)rES}, /* 26 */ { prefix, none2, 0 , (IC)rES}, /* 26 */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */ { none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */
{ modrm, none2, B , iSUB }, /* 28 */ { modrm, none2, B , iSUB }, /* 28 */
{ modrm, none2, 0 , iSUB }, /* 29 */ { modrm, none2, 0 , iSUB }, /* 29 */
{ modrm, none2, TO_REG | B , iSUB }, /* 2A */ { modrm, none2, TO_REG | B , iSUB }, /* 2A */
{ modrm, none2, TO_REG , iSUB }, /* 2B */ { modrm, none2, TO_REG , iSUB }, /* 2B */
{ data1, axImp, B , iSUB }, /* 2C */ { data1, axImp, B , iSUB }, /* 2C */
{ data2, axImp, 0 , iSUB }, /* 2D */ { data2, axImp, 0 , iSUB }, /* 2D */
{ prefix, none2, 0 , (IC)rCS}, /* 2E */ { prefix, none2, 0 , (IC)rCS}, /* 2E */
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */ { none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */
{ modrm, none2, B , iXOR }, /* 30 */ { modrm, none2, B , iXOR }, /* 30 */
{ modrm, none2, NSP , iXOR }, /* 31 */ { modrm, none2, NSP , iXOR }, /* 31 */
{ modrm, none2, TO_REG | B , iXOR }, /* 32 */ { modrm, none2, TO_REG | B , iXOR }, /* 32 */
{ modrm, none2, TO_REG | NSP , iXOR }, /* 33 */ { modrm, none2, TO_REG | NSP , iXOR }, /* 33 */
{ data1, axImp, B , iXOR }, /* 34 */ { data1, axImp, B , iXOR }, /* 34 */
{ data2, axImp, 0 , iXOR }, /* 35 */ { data2, axImp, 0 , iXOR }, /* 35 */
{ prefix, none2, 0 , (IC)rSS}, /* 36 */ { prefix, none2, 0 , (IC)rSS}, /* 36 */
{ none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */ { none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */
{ modrm, none2, B , iCMP }, /* 38 */ { modrm, none2, B , iCMP }, /* 38 */
{ modrm, none2, NSP , iCMP }, /* 39 */ { modrm, none2, NSP , iCMP }, /* 39 */
{ modrm, none2, TO_REG | B , iCMP }, /* 3A */ { modrm, none2, TO_REG | B , iCMP }, /* 3A */
{ modrm, none2, TO_REG | NSP , iCMP }, /* 3B */ { modrm, none2, TO_REG | NSP , iCMP }, /* 3B */
{ data1, axImp, B , iCMP }, /* 3C */ { data1, axImp, B , iCMP }, /* 3C */
{ data2, axImp, 0 , iCMP }, /* 3D */ { data2, axImp, 0 , iCMP }, /* 3D */
{ prefix, none2, 0 , (IC)rDS}, /* 3E */ { prefix, none2, 0 , (IC)rDS}, /* 3E */
{ none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */ { none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */
{ regop, none2, 0 , iINC }, /* 40 */ { regop, none2, 0 , iINC }, /* 40 */
{ regop, none2, 0 , iINC }, /* 41 */ { regop, none2, 0 , iINC }, /* 41 */
{ regop, none2, 0 , iINC }, /* 42 */ { regop, none2, 0 , iINC }, /* 42 */
{ regop, none2, 0 , iINC }, /* 43 */ { regop, none2, 0 , iINC }, /* 43 */
{ regop, none2, NOT_HLL , iINC }, /* 44 */ { regop, none2, NOT_HLL , iINC }, /* 44 */
{ regop, none2, 0 , iINC }, /* 45 */ { regop, none2, 0 , iINC }, /* 45 */
{ regop, none2, 0 , iINC }, /* 46 */ { regop, none2, 0 , iINC }, /* 46 */
{ regop, none2, 0 , iINC }, /* 47 */ { regop, none2, 0 , iINC }, /* 47 */
{ regop, none2, 0 , iDEC }, /* 48 */ { regop, none2, 0 , iDEC }, /* 48 */
{ regop, none2, 0 , iDEC }, /* 49 */ { regop, none2, 0 , iDEC }, /* 49 */
{ regop, none2, 0 , iDEC }, /* 4A */ { regop, none2, 0 , iDEC }, /* 4A */
{ regop, none2, 0 , iDEC }, /* 4B */ { regop, none2, 0 , iDEC }, /* 4B */
{ regop, none2, NOT_HLL , iDEC }, /* 4C */ { regop, none2, NOT_HLL , iDEC }, /* 4C */
{ regop, none2, 0 , iDEC }, /* 4D */ { regop, none2, 0 , iDEC }, /* 4D */
{ regop, none2, 0 , iDEC }, /* 4E */ { regop, none2, 0 , iDEC }, /* 4E */
{ regop, none2, 0 , iDEC }, /* 4F */ { regop, none2, 0 , iDEC }, /* 4F */
{ regop, none2, NO_SRC , iPUSH }, /* 50 */ { regop, none2, NO_SRC , iPUSH }, /* 50 */
{ regop, none2, NO_SRC , iPUSH }, /* 51 */ { regop, none2, NO_SRC , iPUSH }, /* 51 */
{ regop, none2, NO_SRC , iPUSH }, /* 52 */ { regop, none2, NO_SRC , iPUSH }, /* 52 */
{ regop, none2, NO_SRC , iPUSH }, /* 53 */ { regop, none2, NO_SRC , iPUSH }, /* 53 */
{ regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */ { regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */
{ regop, none2, NO_SRC , iPUSH }, /* 55 */ { regop, none2, NO_SRC , iPUSH }, /* 55 */
{ regop, none2, NO_SRC , iPUSH }, /* 56 */ { regop, none2, NO_SRC , iPUSH }, /* 56 */
{ regop, none2, NO_SRC , iPUSH }, /* 57 */ { regop, none2, NO_SRC , iPUSH }, /* 57 */
{ regop, none2, NO_SRC , iPOP }, /* 58 */ { regop, none2, NO_SRC , iPOP }, /* 58 */
{ regop, none2, NO_SRC , iPOP }, /* 59 */ { regop, none2, NO_SRC , iPOP }, /* 59 */
{ regop, none2, NO_SRC , iPOP }, /* 5A */ { regop, none2, NO_SRC , iPOP }, /* 5A */
{ regop, none2, NO_SRC , iPOP }, /* 5B */ { regop, none2, NO_SRC , iPOP }, /* 5B */
{ regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */ { regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */
{ regop, none2, NO_SRC , iPOP }, /* 5D */ { regop, none2, NO_SRC , iPOP }, /* 5D */
{ regop, none2, NO_SRC , iPOP }, /* 5E */ { regop, none2, NO_SRC , iPOP }, /* 5E */
{ regop, none2, NO_SRC , iPOP }, /* 5F */ { regop, none2, NO_SRC , iPOP }, /* 5F */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */ { none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */
{ none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */ { none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */
{ memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */ { memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */
{ none1, none2, OP386 , iZERO }, /* 63 */ { none1, none2, OP386 , iINVALID }, /* 63 */
{ none1, none2, OP386 , iZERO }, /* 64 */ { none1, none2, OP386 , iINVALID }, /* 64 */
{ none1, none2, OP386 , iZERO }, /* 65 */ { none1, none2, OP386 , iINVALID }, /* 65 */
{ none1, none2, OP386 , iZERO }, /* 66 */ { none1, none2, OP386 , iINVALID }, /* 66 */
{ none1, none2, OP386 , iZERO }, /* 67 */ { none1, none2, OP386 , iINVALID }, /* 67 */
{ data2, none2, NO_SRC , iPUSH }, /* 68 */ { data2, none2, NO_SRC , iPUSH }, /* 68 */
{ modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */ { modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */
{ data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */ { data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */
{ modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */ { modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */
{ strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */ { strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */
{ strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */ { strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */
{ strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */ { strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */
{ strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */ { strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */
{ dispS, none2, NOT_HLL , iJO }, /* 70 */ { dispS, none2, NOT_HLL , iJO }, /* 70 */
{ dispS, none2, NOT_HLL , iJNO }, /* 71 */ { dispS, none2, NOT_HLL , iJNO }, /* 71 */
{ dispS, none2, 0 , iJB }, /* 72 */ { dispS, none2, 0 , iJB }, /* 72 */
{ dispS, none2, 0 , iJAE }, /* 73 */ { dispS, none2, 0 , iJAE }, /* 73 */
{ dispS, none2, 0 , iJE }, /* 74 */ { dispS, none2, 0 , iJE }, /* 74 */
{ dispS, none2, 0 , iJNE }, /* 75 */ { dispS, none2, 0 , iJNE }, /* 75 */
{ dispS, none2, 0 , iJBE }, /* 76 */ { dispS, none2, 0 , iJBE }, /* 76 */
{ dispS, none2, 0 , iJA }, /* 77 */ { dispS, none2, 0 , iJA }, /* 77 */
{ dispS, none2, 0 , iJS }, /* 78 */ { dispS, none2, 0 , iJS }, /* 78 */
{ dispS, none2, 0 , iJNS }, /* 79 */ { dispS, none2, 0 , iJNS }, /* 79 */
{ dispS, none2, NOT_HLL , iJP }, /* 7A */ { dispS, none2, NOT_HLL , iJP }, /* 7A */
{ dispS, none2, NOT_HLL , iJNP }, /* 7B */ { dispS, none2, NOT_HLL , iJNP }, /* 7B */
{ dispS, none2, 0 , iJL }, /* 7C */ { dispS, none2, 0 , iJL }, /* 7C */
{ dispS, none2, 0 , iJGE }, /* 7D */ { dispS, none2, 0 , iJGE }, /* 7D */
{ dispS, none2, 0 , iJLE }, /* 7E */ { dispS, none2, 0 , iJLE }, /* 7E */
{ dispS, none2, 0 , iJG }, /* 7F */ { dispS, none2, 0 , iJG }, /* 7F */
{ immed, data1, B , iZERO }, /* 80 */ { immed, data1, B , iINVALID }, /* 80 */
{ immed, data2, NSP , iZERO }, /* 81 */ { immed, data2, NSP , iINVALID }, /* 81 */
{ immed, data1, B , iZERO }, /* 82 */ /* ?? */ { immed, data1, B , iINVALID }, /* 82 */ /* ?? */
{ immed, data1, NSP | S_EXT , iZERO }, /* 83 */ { immed, data1, NSP | S_EXT , iINVALID }, /* 83 */
{ modrm, none2, TO_REG | B , iTEST }, /* 84 */ { modrm, none2, TO_REG | B , iTEST }, /* 84 */
{ modrm, none2, TO_REG | NSP , iTEST }, /* 85 */ { modrm, none2, TO_REG | NSP , iTEST }, /* 85 */
{ modrm, none2, TO_REG | B , iXCHG }, /* 86 */ { modrm, none2, TO_REG | B , iXCHG }, /* 86 */
{ modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */ { modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */
{ modrm, none2, B , iMOV }, /* 88 */ { modrm, none2, B , iMOV }, /* 88 */
{ modrm, none2, 0 , iMOV }, /* 89 */ { modrm, none2, 0 , iMOV }, /* 89 */
{ modrm, none2, TO_REG | B , iMOV }, /* 8A */ { modrm, none2, TO_REG | B , iMOV }, /* 8A */
{ modrm, none2, TO_REG , iMOV }, /* 8B */ { modrm, none2, TO_REG , iMOV }, /* 8B */
{ segrm, none2, NSP , iMOV }, /* 8C */ { segrm, none2, NSP , iMOV }, /* 8C */
{ memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */ { memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */
{ segrm, none2, TO_REG | NSP , iMOV }, /* 8E */ { segrm, none2, TO_REG | NSP , iMOV }, /* 8E */
{ memReg0, none2, NO_SRC , iPOP }, /* 8F */ { memReg0, none2, NO_SRC , iPOP }, /* 8F */
{ none1, none2, NO_OPS , iNOP }, /* 90 */ { none1, none2, NO_OPS , iNOP }, /* 90 */
{ regop, axImp, 0 , iXCHG }, /* 91 */ { regop, axImp, 0 , iXCHG }, /* 91 */
{ regop, axImp, 0 , iXCHG }, /* 92 */ { regop, axImp, 0 , iXCHG }, /* 92 */
{ regop, axImp, 0 , iXCHG }, /* 93 */ { regop, axImp, 0 , iXCHG }, /* 93 */
{ regop, axImp, NOT_HLL , iXCHG }, /* 94 */ { regop, axImp, NOT_HLL , iXCHG }, /* 94 */
{ regop, axImp, 0 , iXCHG }, /* 95 */ { regop, axImp, 0 , iXCHG }, /* 95 */
{ regop, axImp, 0 , iXCHG }, /* 96 */ { regop, axImp, 0 , iXCHG }, /* 96 */
{ regop, axImp, 0 , iXCHG }, /* 97 */ { regop, axImp, 0 , iXCHG }, /* 97 */
{ alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */ { alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */
{axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */ {axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */
{ dispF, none2, TO_REG , iCALLF }, /* 9A */ // TO_REG set to use SRC when processing setAddress { dispF, none2, TO_REG , iCALLF }, /* 9A */ // TO_REG set to use SRC when processing setAddress
{ none1, none2, FLOAT_OP| NO_OPS , iWAIT }, /* 9B */ { none1, none2, FLOAT_OP| NO_OPS , iWAIT }, /* 9B */
{ none1, none2, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */ { none1, none2, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */
{ none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */ { none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */
{ none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */ { none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */
{ none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */ { none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */
{ dispM, axImp, B , iMOV }, /* A0 */ { dispM, axImp, B , iMOV }, /* A0 */
{ dispM, axImp, 0 , iMOV }, /* A1 */ { dispM, axImp, 0 , iMOV }, /* A1 */
{ dispM, axImp, TO_REG | B , iMOV }, /* A2 */ { dispM, axImp, TO_REG | B , iMOV }, /* A2 */
{ dispM, axImp, TO_REG , iMOV }, /* A3 */ { dispM, axImp, TO_REG , iMOV }, /* A3 */
{ strop, memImp, B | IM_OPS , iMOVS }, /* A4 */ { strop, memImp, B | IM_OPS , iMOVS }, /* A4 */
{ strop, memImp, IM_OPS , iMOVS }, /* A5 */ { strop, memImp, IM_OPS , iMOVS }, /* A5 */
{ strop, memImp, B | IM_OPS , iCMPS }, /* A6 */ { strop, memImp, B | IM_OPS , iCMPS }, /* A6 */
{ strop, memImp, IM_OPS , iCMPS }, /* A7 */ { strop, memImp, IM_OPS , iCMPS }, /* A7 */
{ data1, axImp, B , iTEST }, /* A8 */ { data1, axImp, B , iTEST }, /* A8 */
{ data2, axImp, 0 , iTEST }, /* A9 */ { data2, axImp, 0 , iTEST }, /* A9 */
{ strop, memImp, B | IM_OPS , iSTOS }, /* AA */ { strop, memImp, B | IM_OPS , iSTOS }, /* AA */
{ strop, memImp, IM_OPS , iSTOS }, /* AB */ { strop, memImp, IM_OPS , iSTOS }, /* AB */
{ strop, memImp, B | IM_OPS , iLODS }, /* AC */ { strop, memImp, B | IM_OPS , iLODS }, /* AC */
{ strop, memImp, IM_OPS , iLODS }, /* AD */ { strop, memImp, IM_OPS , iLODS }, /* AD */
{ strop, memImp, B | IM_OPS , iSCAS }, /* AE */ { strop, memImp, B | IM_OPS , iSCAS }, /* AE */
{ strop, memImp, IM_OPS , iSCAS }, /* AF */ { strop, memImp, IM_OPS , iSCAS }, /* AF */
{ regop, data1, B , iMOV }, /* B0 */ { regop, data1, B , iMOV }, /* B0 */
{ regop, data1, B , iMOV }, /* B1 */ { regop, data1, B , iMOV }, /* B1 */
{ regop, data1, B , iMOV }, /* B2 */ { regop, data1, B , iMOV }, /* B2 */
{ regop, data1, B , iMOV }, /* B3 */ { regop, data1, B , iMOV }, /* B3 */
{ regop, data1, B , iMOV }, /* B4 */ { regop, data1, B , iMOV }, /* B4 */
{ regop, data1, B , iMOV }, /* B5 */ { regop, data1, B , iMOV }, /* B5 */
{ regop, data1, B , iMOV }, /* B6 */ { regop, data1, B , iMOV }, /* B6 */
{ regop, data1, B , iMOV }, /* B7 */ { regop, data1, B , iMOV }, /* B7 */
{ regop, data2, 0 , iMOV }, /* B8 */ { regop, data2, 0 , iMOV }, /* B8 */
{ regop, data2, 0 , iMOV }, /* B9 */ { regop, data2, 0 , iMOV }, /* B9 */
{ regop, data2, 0 , iMOV }, /* BA */ { regop, data2, 0 , iMOV }, /* BA */
{ regop, data2, 0 , iMOV }, /* BB */ { regop, data2, 0 , iMOV }, /* BB */
{ regop, data2, NOT_HLL , iMOV }, /* BC */ { regop, data2, NOT_HLL , iMOV }, /* BC */
{ regop, data2, 0 , iMOV }, /* BD */ { regop, data2, 0 , iMOV }, /* BD */
{ regop, data2, 0 , iMOV }, /* BE */ { regop, data2, 0 , iMOV }, /* BE */
{ regop, data2, 0 , iMOV }, /* BF */ { regop, data2, 0 , iMOV }, /* BF */
{ shift, data1, B , iZERO }, /* C0 */ { shift, data1, B , iINVALID }, /* C0 */
{ shift, data1, NSP | SRC_B , iZERO }, /* C1 */ { shift, data1, NSP | SRC_B , iINVALID }, /* C1 */
{ data2, none2, 0 , iRET }, /* C2 */ { data2, none2, 0 , iRET }, /* C2 */
{ none1, none2, NO_OPS , iRET }, /* C3 */ { none1, none2, NO_OPS , iRET }, /* C3 */
{ memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */ { memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */
{ memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */ { memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */
{ memReg0, data1, B , iMOV }, /* C6 */ { memReg0, data1, B , iMOV }, /* C6 */
{ memReg0, data2, 0 , iMOV }, /* C7 */ { memReg0, data2, 0 , iMOV }, /* C7 */
{ data2, data1, 0 , iENTER}, /* C8 */ { data2, data1, 0 , iENTER}, /* C8 */
{ none1, none2, NO_OPS , iLEAVE}, /* C9 */ { none1, none2, NO_OPS , iLEAVE}, /* C9 */
{ data2, none2, 0 , iRETF }, /* CA */ { data2, none2, 0 , iRETF }, /* CA */
{ none1, none2, NO_OPS , iRETF }, /* CB */ { none1, none2, NO_OPS , iRETF }, /* CB */
{ const3, none2, NOT_HLL , iINT }, /* CC */ { const3, none2, NOT_HLL , iINT }, /* CC */
{ data1,checkInt, NOT_HLL , iINT }, /* CD */ { data1,checkInt, NOT_HLL , iINT }, /* CD */
{ none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */ { none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */
{ none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */ { none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */
{ shift, const1, B , iZERO }, /* D0 */ { shift, const1, B , iINVALID }, /* D0 */
{ shift, const1, SRC_B , iZERO }, /* D1 */ { shift, const1, SRC_B , iINVALID }, /* D1 */
{ shift, none1, B , iZERO }, /* D2 */ { shift, none1, B , iINVALID }, /* D2 */
{ shift, none1, SRC_B , iZERO }, /* D3 */ { shift, none1, SRC_B , iINVALID }, /* D3 */
{ data1, axImp, NOT_HLL , iAAM }, /* D4 */ { data1, axImp, NOT_HLL , iAAM }, /* D4 */
{ data1, axImp, NOT_HLL , iAAD }, /* D5 */ { data1, axImp, NOT_HLL , iAAD }, /* D5 */
{ none1, none2, 0 , iZERO }, /* D6 */ { none1, none2, 0 , iINVALID }, /* D6 */
{ memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */ { memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */
{ escop, none2, FLOAT_OP , iESC }, /* D8 */ { escop, none2, FLOAT_OP , iESC }, /* D8 */
{ escop, none2, FLOAT_OP , iESC }, /* D9 */ { escop, none2, FLOAT_OP , iESC }, /* D9 */
{ escop, none2, FLOAT_OP , iESC }, /* DA */ { escop, none2, FLOAT_OP , iESC }, /* DA */
{ escop, none2, FLOAT_OP , iESC }, /* DB */ { escop, none2, FLOAT_OP , iESC }, /* DB */
{ escop, none2, FLOAT_OP , iESC }, /* DC */ { escop, none2, FLOAT_OP , iESC }, /* DC */
{ escop, none2, FLOAT_OP , iESC }, /* DD */ { escop, none2, FLOAT_OP , iESC }, /* DD */
{ escop, none2, FLOAT_OP , iESC }, /* DE */ { escop, none2, FLOAT_OP , iESC }, /* DE */
{ escop, none2, FLOAT_OP , iESC }, /* Df */ { escop, none2, FLOAT_OP , iESC }, /* Df */
{ dispS, none2, 0 , iLOOPNE}, /* E0 */ { dispS, none2, 0 , iLOOPNE}, /* E0 */
{ dispS, none2, 0 , iLOOPE}, /* E1 */ { dispS, none2, 0 , iLOOPE}, /* E1 */
{ dispS, none2, 0 , iLOOP }, /* E2 */ { dispS, none2, 0 , iLOOP }, /* E2 */
{ dispS, none2, 0 , iJCXZ }, /* E3 */ { dispS, none2, 0 , iJCXZ }, /* E3 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */ { data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */
{ data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */ { data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */
{ data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */ { data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */
{ data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */ { data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */
{ dispN, none2, 0 , iCALL }, /* E8 */ { dispN, none2, 0 , iCALL }, /* E8 */
{ dispN, none2, 0 , iJMP }, /* E9 */ { dispN, none2, 0 , iJMP }, /* E9 */
{ dispF, none2, 0 , iJMPF }, /* EA */ { dispF, none2, 0 , iJMPF }, /* EA */
{ dispS, none2, 0 , iJMP }, /* EB */ { dispS, none2, 0 , iJMP }, /* EB */
{ none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */ { none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */
{ none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */ { none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */ { none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */
{ none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */ { none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */
{ none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */ { none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */
{ none1, none2, 0 , iZERO }, /* F1 */ { none1, none2, 0 , iINVALID }, /* F1 */
{ prefix, none2, 0 , iREPNE}, /* F2 */ { prefix, none2, 0 , iREPNE}, /* F2 */
{ prefix, none2, 0 , iREPE }, /* F3 */ { prefix, none2, 0 , iREPE }, /* F3 */
{ none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */ { none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */
{ none1, none2, NO_OPS , iCMC }, /* F5 */ { none1, none2, NO_OPS , iCMC }, /* F5 */
{ arith, none1, B , iZERO }, /* F6 */ { arith, none1, B , iINVALID }, /* F6 */
{ arith, none1, NSP , iZERO }, /* F7 */ { arith, none1, NSP , iINVALID }, /* F7 */
{ none1, none2, NO_OPS , iCLC }, /* F8 */ { none1, none2, NO_OPS , iCLC }, /* F8 */
{ none1, none2, NO_OPS , iSTC }, /* F9 */ { none1, none2, NO_OPS , iSTC }, /* F9 */
{ none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */ { none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */
{ none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */ { none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */
{ none1, none2, NO_OPS , iCLD }, /* FC */ { none1, none2, NO_OPS , iCLD }, /* FC */
{ none1, none2, NO_OPS , iSTD }, /* FD */ { none1, none2, NO_OPS , iSTD }, /* FD */
{ trans, none1, B , iZERO }, /* FE */ { trans, none1, B , iINVALID }, /* FE */
{ trans, none1, NSP , iZERO } /* FF */ { trans, none1, NSP , iINVALID } /* FF */
} ; } ;
static uint16_t SegPrefix, RepPrefix; static uint16_t SegPrefix, RepPrefix;
static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */ static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */
static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */ static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */
static void decodeBranchTgt(x86_insn_t &insn) static void decodeBranchTgt(x86_insn_t &insn)
@ -338,7 +337,7 @@ static void decodeBranchTgt(x86_insn_t &insn)
pIcode->ll()->replaceSrc((uint32_t)addr); pIcode->ll()->replaceSrc((uint32_t)addr);
pIcode->ll()->setFlags(I); pIcode->ll()->setFlags(I);
// PROG &prog(Project::get()->prog); // PROG &prog(Project::get()->prog);
// long off = (short)getWord(); /* Signed displacement */ // long off = (short)getWord(); /* Signed displacement */
// assert(addr==(uint32_t)(off + (unsigned)(pInst - prog.image()))); // assert(addr==(uint32_t)(off + (unsigned)(pInst - prog.image())));
} }
@ -538,7 +537,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
int op; int op;
p = ICODE(); p = ICODE();
p.type = LOW_LEVEL_ICODE; p.type = LOW_LEVEL_ICODE;
p.ll()->label = ip; /* ip is absolute offset into image*/ p.ll()->label = ip; /* ip is absolute offset into image*/
if (ip >= (uint32_t)prog.cbImage) if (ip >= (uint32_t)prog.cbImage)
{ {
return (IP_OUT_OF_RANGE); return (IP_OUT_OF_RANGE);
@ -557,13 +556,13 @@ eErrorId scan(uint32_t ip, ICODE &p)
do do
{ {
op = *pInst++; /* First state - trivial */ op = *pInst++; /* First state - trivial */
/* Convert to Icode.opcode */ /* Convert to Icode.opcode */
p.ll()->set(stateTable[op].opcode,stateTable[op].flg & ICODEMASK); p.ll()->set(stateTable[op].opcode,stateTable[op].flg & ICODEMASK);
(*stateTable[op].state1)(op); /* Second state */ (*stateTable[op].state1)(op); /* Second state */
(*stateTable[op].state2)(op); /* Third state */ (*stateTable[op].state2)(op); /* Third state */
} while (stateTable[op].state1 == prefix); /* Loop if prefix */ } while (stateTable[op].state1 == prefix); /* Loop if prefix */
if(p.insn.group == x86_insn_t::insn_controlflow) if(p.insn.group == x86_insn_t::insn_controlflow)
{ {
if(p.insn.x86_get_branch_target()) if(p.insn.x86_get_branch_target())
@ -571,7 +570,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
} }
// LLOperand conv = convertOperand(*p.insn.get_dest()); // LLOperand conv = convertOperand(*p.insn.get_dest());
// assert(conv==p.ll()->dst); // assert(conv==p.ll()->dst);
if (p.ll()->getOpcode()) if (p.ll()->getOpcode()!=iINVALID)
{ {
/* Save bytes of image used */ /* Save bytes of image used */
p.ll()->numBytes = (uint8_t)((pInst - prog.image()) - ip); 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) static bool relocItem(const uint8_t *p)
{ {
PROG &prog(Project::get()->prog); PROG &prog(Project::get()->prog);
uint32_t off = p - prog.image(); 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) if (prog.relocTable[i] == off)
return true; return true;
return false; return false;
@ -620,33 +620,33 @@ static int signex(uint8_t b)
return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s); return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s);
} }
/** /****************************************************************************
* \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. * icode, based on fdst and the TO_REG flag.
* \note fdst == true is for the r/m part of the field (dest, unless TO_REG) * Note: fdst == true is for the r/m part of the field (dest, unless TO_REG)
* fdst == false is for reg part of the field * fdst == false is for reg part of the field
***************************************************************************/ ***************************************************************************/
static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off) static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off)
{ {
/* If not to register (i.e. to r/m), and talking about r/m, then this is dest */ /* If not to register (i.e. to r/m), and talking about r/m, then this is dest */
LLOperand *pm = (! 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 /* Set segment. A later procedure (lookupAddr in proclist.c) will
* provide the value of this segment in the field segValue. * provide the value of this segment in the field segValue.
*/ */
if (seg) /* segment override */ if (seg) /* segment override */
{ {
pm->seg = pm->segOver = (eReg)seg; pm->seg = pm->segOver = (eReg)seg;
} }
else else
{ /* no override, check indexed register */ { /* no override, check indexed register */
if ((reg >= INDEX_BX_SI) and (reg == INDEX_BP_SI or reg == INDEX_BP_DI or reg == INDEX_BP)) if ((reg >= INDEX_BX_SI) and (reg == INDEX_BP_SI or reg == INDEX_BP_DI or reg == INDEX_BP))
{ {
pm->seg = rSS; /* indexed on bp */ pm->seg = rSS; /* indexed on bp */
} }
else else
{ {
pm->seg = rDS; /* any other indexed reg */ pm->seg = rDS; /* any other indexed reg */
} }
} }
@ -673,7 +673,7 @@ static void rm(int i)
uint8_t rm = *pInst++ & 7; uint8_t rm = *pInst++ & 7;
switch (mod) { switch (mod) {
case 0: /* No disp unless rm == 6 */ case 0: /* No disp unless rm == 6 */
if (rm == 6) { if (rm == 6) {
setAddress(i, true, SegPrefix, 0, getWord()); setAddress(i, true, SegPrefix, 0, getWord());
pIcode->ll()->setFlags(WORD_OFF); pIcode->ll()->setFlags(WORD_OFF);
@ -682,16 +682,16 @@ static void rm(int i)
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, 0); setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, 0);
break; break;
case 1: /* 1 uint8_t disp */ case 1: /* 1 uint8_t disp */
setAddress(i, true, SegPrefix, rm+INDEX_BX_SI, (uint16_t)signex(*pInst++)); setAddress(i, true, SegPrefix, rm+INDEX_BX_SI, (uint16_t)signex(*pInst++));
break; break;
case 2: /* 2 uint8_t disp */ case 2: /* 2 uint8_t disp */
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, getWord()); setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, getWord());
pIcode->ll()->setFlags(WORD_OFF); pIcode->ll()->setFlags(WORD_OFF);
break; break;
case 3: /* reg */ case 3: /* reg */
setAddress(i, true, 0, rm + rAX, 0); setAddress(i, true, 0, rm + rAX, 0);
break; break;
} }
@ -717,7 +717,7 @@ static void modrm(int i)
****************************************************************************/ ****************************************************************************/
static void segrm(int i) static void segrm(int i)
{ {
int reg = REG(*pInst) + rES; int reg = REG(*pInst) + rES;
if (reg > rDS or (reg == rCS and (stateTable[i].flg & TO_REG))) if (reg > rDS or (reg == rCS and (stateTable[i].flg & TO_REG)))
pIcode->ll()->setOpcode((llIcode)0); // setCBW because it has that index pIcode->ll()->setOpcode((llIcode)0); // setCBW because it has that index
@ -786,7 +786,7 @@ static void memImp(int i)
static void memOnly(int ) static void memOnly(int )
{ {
if ((*pInst & 0xC0) == 0xC0) 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) static void memReg0(int i)
{ {
if (REG(*pInst) or (*pInst & 0xC0) == 0xC0) if (REG(*pInst) or (*pInst & 0xC0) == 0xC0)
pIcode->ll()->setOpcode((llIcode)0); pIcode->ll()->setOpcode(iINVALID);
else else
rm(i); rm(i);
} }
@ -825,7 +825,7 @@ static void shift(int i)
static llIcode shiftTable[8] = static llIcode shiftTable[8] =
{ {
(llIcode)iROL, (llIcode)iROR, (llIcode)iRCL, (llIcode)iRCR, (llIcode)iROL, (llIcode)iROR, (llIcode)iRCL, (llIcode)iRCR,
(llIcode)iSHL, (llIcode)iSHR, (llIcode)0, (llIcode)iSAR}; (llIcode)iSHL, (llIcode)iSHR, (llIcode)0, (llIcode)iSAR};
pIcode->ll()->setOpcode(shiftTable[REG(*pInst)]); pIcode->ll()->setOpcode(shiftTable[REG(*pInst)]);
rm(i); rm(i);
@ -840,8 +840,8 @@ static void trans(int i)
{ {
static llIcode transTable[8] = static llIcode transTable[8] =
{ {
(llIcode)iINC, iDEC, (llIcode)iCALL, (llIcode)iCALLF, iINC, iDEC, iCALL, iCALLF,
(llIcode)iJMP, (llIcode)iJMPF,(llIcode)iPUSH, (llIcode)0 iJMP, iJMPF,iPUSH, (llIcode)0
}; };
LLInst *ll = pIcode->ll(); LLInst *ll = pIcode->ll();
// if(transTable[REG(*pInst)]==iPUSH) { // if(transTable[REG(*pInst)]==iPUSH) {
@ -867,8 +867,8 @@ static void arith(int i)
uint8_t opcode; uint8_t opcode;
static llIcode arithTable[8] = static llIcode arithTable[8] =
{ {
iTEST, (llIcode)0, iNOT, iNEG, iTEST, iINVALID, iNOT, iNEG,
iMUL , iIMUL, iDIV, iIDIV iMUL , iIMUL, iDIV, iIDIV
}; };
opcode = arithTable[REG(*pInst)]; opcode = arithTable[REG(*pInst)];
pIcode->ll()->setOpcode((llIcode)opcode); pIcode->ll()->setOpcode((llIcode)opcode);
@ -883,7 +883,7 @@ static void arith(int i)
else if (not (opcode == iNOT or opcode == iNEG)) else if (not (opcode == iNOT or opcode == iNEG))
{ {
pIcode->ll()->replaceSrc( pIcode->ll()->m_dst ); pIcode->ll()->replaceSrc( pIcode->ll()->m_dst );
setAddress(i, true, 0, rAX, 0); /* dst = AX */ setAddress(i, true, 0, rAX, 0); /* dst = AX */
} }
else if (opcode == iNEG or opcode == iNOT) else if (opcode == iNEG or opcode == iNOT)
pIcode->ll()->setFlags(NO_SRC); pIcode->ll()->setFlags(NO_SRC);
@ -918,7 +918,7 @@ static void data2(int )
* but this field is being used as the number of bytes to allocate * but this field is being used as the number of bytes to allocate
* on the stack. The procedure level is stored in the immediate * on the stack. The procedure level is stored in the immediate
* field. There is no source operand; therefore, the flag flg is * field. There is no source operand; therefore, the flag flg is
* set to NO_OPS. */ * set to NO_OPS. */
if (pIcode->ll()->getOpcode() == iENTER) if (pIcode->ll()->getOpcode() == iENTER)
{ {
pIcode->ll()->m_dst.off = getWord(); pIcode->ll()->m_dst.off = getWord();
@ -959,7 +959,7 @@ static void dispN(int )
***************************************************************************/ ***************************************************************************/
static void dispS(int ) static void dispS(int )
{ {
/*long off =*/ signex(*pInst++); /* Signed displacement */ /*long off =*/ signex(*pInst++); /* Signed displacement */
// decodeBranchTgt(); // decodeBranchTgt();
} }
@ -984,7 +984,7 @@ static void dispF(int i)
****************************************************************************/ ****************************************************************************/
static void prefix(int ) 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(); RepPrefix = pIcode->ll()->getOpcode();
else else
SegPrefix = pIcode->ll()->getOpcode(); SegPrefix = pIcode->ll()->getOpcode();
@ -992,7 +992,7 @@ static void prefix(int )
inline void BumpOpcode(LLInst &ll) 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 ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type
ll.setOpcode(ic); ll.setOpcode(ic);
} }
@ -1068,7 +1068,7 @@ static void none1(int )
****************************************************************************/ ****************************************************************************/
static void none2(int ) static void none2(int )
{ {
if ( pIcode->ll()->srcIsImmed() ) if ( pIcode->ll()->testFlags(I) )
pIcode->ll()->setFlags(NO_OPS); 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 <cassert>
#include <stdio.h> #include <stdio.h>
#include <CallGraph.h> #include <CallGraph.h>
extern Project g_proj;
//static void displayCFG(Function * pProc); //static void displayCFG(Function * pProc);
//static void displayDfs(BB * pBB); //static void displayDfs(BB * pBB);
@ -31,7 +32,7 @@ void Function::buildCFG(Disassembler &ds)
if (option.asm2) if (option.asm2)
{ {
ds.disassem(this->shared_from_this()); // Print 2nd pass assembler listing ds.disassem(this); // Print 2nd pass assembler listing
return; return;
} }
@ -45,9 +46,10 @@ void Function::controlFlowAnalysis()
{ {
if (flg & PROC_ISLIB) if (flg & PROC_ISLIB)
return; /* Ignore library functions */ return; /* Ignore library functions */
derSeq *derivedG=nullptr;
/* Make cfg reducible and build derived sequences */ /* Make cfg reducible and build derived sequences */
derSeq *derivedG = checkReducibility(); derivedG=checkReducibility();
if (option.VeryVerbose) if (option.VeryVerbose)
derivedG->display(); derivedG->display();
@ -78,13 +80,13 @@ void udm(void)
Disassembler ds(2); Disassembler ds(2);
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter) for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
{ {
Function &f(**iter); Function &f(*iter);
if(option.CustomEntryPoint) { if(option.CustomEntryPoint) {
if(f.procEntry!=option.CustomEntryPoint) { if(f.procEntry!=option.CustomEntryPoint) {
continue; continue;
} }
} }
f.buildCFG(ds); iter->buildCFG(ds);
} }
if (option.asm2) if (option.asm2)
return; return;
@ -95,8 +97,8 @@ void udm(void)
* substitution algorithm */ * substitution algorithm */
LivenessSet live_regs; LivenessSet live_regs;
if(option.CustomEntryPoint) { if(option.CustomEntryPoint) {
PtrFunction iter = proj->findByEntry(option.CustomEntryPoint); ilFunction iter = proj->findByEntry(option.CustomEntryPoint);
if(iter==nullptr) { if(iter==proj->pProcList.end()) {
qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16); qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16);
return; return;
} }
@ -107,12 +109,12 @@ void udm(void)
proj->callGraph->proc = iter; proj->callGraph->proc = iter;
return; return;
} }
proj->pProcList.front()->dataFlow (live_regs); proj->pProcList.front().dataFlow (live_regs);
/* Control flow analysis - structuring algorithm */ /* Control flow analysis - structuring algorithm */
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter) for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
{ {
(*iter)->controlFlowAnalysis(); iter->controlFlowAnalysis();
} }
} }

View File

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

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