Compare commits
11 Commits
experiment
...
qt5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b58f315c98 | ||
|
|
7687c2b7d2 | ||
|
|
0abbce6f4e | ||
|
|
8ffdf657ec | ||
|
|
2232a76033 | ||
|
|
d6af9c1555 | ||
|
|
d7acc8cd4d | ||
|
|
a5f1d17e83 | ||
|
|
29efcd5be1 | ||
|
|
4656db9484 | ||
|
|
b33d7239e5 |
2
3rd_party/libdisasm/libdis.h
vendored
2
3rd_party/libdisasm/libdis.h
vendored
@ -626,7 +626,7 @@ public:
|
||||
/* the instruction proper */
|
||||
enum x86_insn_prefix prefix; /* prefixes ORed together */
|
||||
char prefix_string[MAX_PREFIX_STR]; /* prefixes [might be truncated] */
|
||||
char mnemonic[MAX_MNEM_STR+1];
|
||||
char mnemonic[MAX_MNEM_STR];
|
||||
x86_oplist_t *operands; /* list of explicit/implicit operands */
|
||||
size_t operand_count; /* total number of operands */
|
||||
size_t explicit_count; /* number of explicit operands */
|
||||
|
||||
124
CMakeLists.txt
124
CMakeLists.txt
@ -1,6 +1,10 @@
|
||||
PROJECT(dcc_original)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
find_package(Qt5Core)
|
||||
|
||||
OPTION(dcc_build_tests "Enable unit tests." OFF)
|
||||
#SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
|
||||
ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS -D__UNIX__ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS)
|
||||
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
@ -14,25 +18,15 @@ ENDIF()
|
||||
SET(CMAKE_CXX_STANDARD 11)
|
||||
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMakeScripts;${CMAKE_MODULE_PATH})
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
find_package(Qt5Core)
|
||||
find_package(Qt5Widgets)
|
||||
find_package(Boost)
|
||||
|
||||
OPTION(dcc_build_tests "Enable unit tests." OFF)
|
||||
include(cotire)
|
||||
FIND_PACKAGE(Boost)
|
||||
IF(dcc_build_tests)
|
||||
enable_testing()
|
||||
find_package(Qt5Test)
|
||||
#FIND_PACKAGE(GMock)
|
||||
enable_testing()
|
||||
FIND_PACKAGE(GMock)
|
||||
ENDIF()
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${PROJECT_SOURCE_DIR}
|
||||
3rd_party/libdisasm
|
||||
include
|
||||
include/idioms
|
||||
@ -40,7 +34,109 @@ INCLUDE_DIRECTORIES(
|
||||
${Boost_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
|
||||
ADD_SUBDIRECTORY(3rd_party)
|
||||
ADD_SUBDIRECTORY(common)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
|
||||
|
||||
set(dcc_LIB_SOURCES
|
||||
src/CallConvention.cpp
|
||||
src/ast.cpp
|
||||
src/backend.cpp
|
||||
src/bundle.cpp
|
||||
src/chklib.cpp
|
||||
src/comwrite.cpp
|
||||
src/control.cpp
|
||||
src/dataflow.cpp
|
||||
src/disassem.cpp
|
||||
src/DccFrontend.cpp
|
||||
src/error.cpp
|
||||
src/fixwild.cpp
|
||||
src/graph.cpp
|
||||
src/hlicode.cpp
|
||||
src/hltype.cpp
|
||||
src/machine_x86.cpp
|
||||
src/icode.cpp
|
||||
src/RegisterNode
|
||||
src/idioms.cpp
|
||||
src/idioms/idiom1.cpp
|
||||
src/idioms/arith_idioms.cpp
|
||||
src/idioms/call_idioms.cpp
|
||||
src/idioms/epilogue_idioms.cpp
|
||||
src/idioms/mov_idioms.cpp
|
||||
src/idioms/neg_idioms.cpp
|
||||
src/idioms/shift_idioms.cpp
|
||||
src/idioms/xor_idioms.cpp
|
||||
src/locident.cpp
|
||||
src/liveness_set.cpp
|
||||
src/parser.cpp
|
||||
src/procs.cpp
|
||||
src/project.cpp
|
||||
src/Procedure.cpp
|
||||
src/proplong.cpp
|
||||
src/reducible.cpp
|
||||
src/scanner.cpp
|
||||
src/symtab.cpp
|
||||
src/udm.cpp
|
||||
src/BasicBlock.cpp
|
||||
src/dcc_interface.cpp
|
||||
)
|
||||
set(dcc_SOURCES
|
||||
src/dcc.cpp
|
||||
)
|
||||
set(dcc_HEADERS
|
||||
include/ast.h
|
||||
include/bundle.h
|
||||
include/BinaryImage.h
|
||||
include/DccFrontend.h
|
||||
include/Enums.h
|
||||
include/dcc.h
|
||||
include/disassem.h
|
||||
include/dosdcc.h
|
||||
include/error.h
|
||||
include/graph.h
|
||||
include/hlicode.h
|
||||
include/machine_x86.h
|
||||
include/icode.h
|
||||
include/idioms/idiom.h
|
||||
include/idioms/idiom1.h
|
||||
include/idioms/arith_idioms.h
|
||||
include/idioms/call_idioms.h
|
||||
include/idioms/epilogue_idioms.h
|
||||
include/idioms/mov_idioms.h
|
||||
include/idioms/neg_idioms.h
|
||||
include/idioms/shift_idioms.h
|
||||
include/idioms/xor_idioms.h
|
||||
include/locident.h
|
||||
include/CallConvention.h
|
||||
include/project.h
|
||||
include/scanner.h
|
||||
include/state.h
|
||||
include/symtab.h
|
||||
include/types.h
|
||||
include/Procedure.h
|
||||
include/StackFrame.h
|
||||
include/BasicBlock.h
|
||||
include/dcc_interface.h
|
||||
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Source FILES ${dcc_SOURCES})
|
||||
SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
|
||||
|
||||
ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS})
|
||||
qt5_use_modules(dcc_lib Core)
|
||||
#cotire(dcc_lib)
|
||||
|
||||
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_HEADERS})
|
||||
ADD_DEPENDENCIES(dcc_original dcc_lib)
|
||||
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s)
|
||||
qt5_use_modules(dcc_original Core)
|
||||
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD 11)
|
||||
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
#ADD_SUBDIRECTORY(gui)
|
||||
if(dcc_build_tests)
|
||||
ADD_SUBDIRECTORY(src)
|
||||
endif()
|
||||
|
||||
|
||||
@ -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
339
LICENSE
Normal 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.
|
||||
@ -6,6 +6,8 @@ To reflect those fixes, I've edited the original readme a bit.
|
||||
dcc Distribution
|
||||
================
|
||||
|
||||
[](https://gitter.im/nemerle/dcc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
The code provided in this distribution is (C) by their authors:
|
||||
- Cristina Cifuentes (most of dcc code)
|
||||
- Mike van Emmerik (signatures and prototype code)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
/** Perfect hashing function library. Contains functions to generate perfect
|
||||
hashing functions */
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
mkdir -p tests/outputs
|
||||
makedir -p tests/outputs
|
||||
./test_use_all.sh
|
||||
./regression_tester.rb ./dcc_original -s -c 2>stderr >stdout; diff -wB tests/prev/ tests/outputs/
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "graph.h"
|
||||
//#include "icode.h"
|
||||
/* Basic block (BB) node definition */
|
||||
class Function;
|
||||
struct Function;
|
||||
class CIcodeRec;
|
||||
struct BB;
|
||||
struct LOCAL_ID;
|
||||
@ -27,7 +27,7 @@ struct TYPEADR_TYPE
|
||||
};
|
||||
struct BB
|
||||
{
|
||||
friend class Function;
|
||||
friend struct Function;
|
||||
private:
|
||||
BB(const BB&);
|
||||
BB() : nodeType(0),traversed(DFS_NONE),
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
#include <vector>
|
||||
struct PROG /* Loaded program image parameters */
|
||||
{
|
||||
int16_t initCS=0;
|
||||
int16_t initIP=0; /* These are initial load values */
|
||||
int16_t initSS=0; /* Probably not of great interest */
|
||||
uint16_t initCS=0;
|
||||
uint16_t initIP=0; /* These are initial load values */
|
||||
uint16_t initSS=0; /* Probably not of great interest */
|
||||
uint16_t initSP=0;
|
||||
bool fCOM=false; /* Flag set if COM program (else EXE)*/
|
||||
int cReloc=0; /* No. of relocation table entries */
|
||||
@ -14,8 +14,10 @@ struct PROG /* Loaded program image parameters */
|
||||
int cProcs=0; /* Number of procedures so far */
|
||||
int offMain=0; /* The offset of the main() proc */
|
||||
uint16_t segMain=0; /* The segment of the main() proc */
|
||||
bool bSigs=false; /* True if signatures loaded */
|
||||
int cbImage=0; /* Length of image in bytes */
|
||||
uint8_t * Imagez=nullptr; /* Allocated by loader to hold entire program image */
|
||||
int addressingMode=0;
|
||||
public:
|
||||
const uint8_t *image() const {return Imagez;}
|
||||
void displayLoadInfo();
|
||||
|
||||
@ -1,41 +1,33 @@
|
||||
#pragma once
|
||||
#include "ast.h"
|
||||
|
||||
#ifdef PASCAL
|
||||
#undef PASCAL
|
||||
#endif
|
||||
class QTextStream;
|
||||
|
||||
struct CConv {
|
||||
enum CC_Type {
|
||||
UNKNOWN=0,
|
||||
C,
|
||||
PASCAL
|
||||
enum Type {
|
||||
eUnknown=0,
|
||||
eCdecl,
|
||||
ePascal
|
||||
};
|
||||
virtual void processHLI(Function *func, Expr *_exp, iICODE picode)=0;
|
||||
//! given return and argument types fill Function's STKFRAME and return locations
|
||||
virtual void calculateStackLayout(Function *func)=0;
|
||||
virtual void writeComments(QTextStream &)=0;
|
||||
static CConv * create(CC_Type v);
|
||||
static CConv * create(Type v);
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
struct C_CallingConvention : public CConv {
|
||||
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
|
||||
virtual void writeComments(QTextStream &) override;
|
||||
void calculateStackLayout(Function *func) override;
|
||||
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
|
||||
virtual void writeComments(QTextStream &);
|
||||
|
||||
private:
|
||||
int processCArg(Function *callee, Function *pProc, ICODE *picode, size_t numArgs);
|
||||
};
|
||||
struct Pascal_CallingConvention : public CConv {
|
||||
virtual void processHLI(Function *func, Expr *_exp, iICODE picode) override;
|
||||
virtual void writeComments(QTextStream &) override;
|
||||
void calculateStackLayout(Function *func) override;
|
||||
virtual void processHLI(Function *func, Expr *_exp, iICODE picode);
|
||||
virtual void writeComments(QTextStream &);
|
||||
};
|
||||
struct Unknown_CallingConvention : public CConv {
|
||||
void processHLI(Function *func, Expr *_exp, iICODE picode) override {}
|
||||
void calculateStackLayout(Function *func) override;
|
||||
virtual void writeComments(QTextStream &) override;
|
||||
void processHLI(Function *func, Expr *_exp, iICODE picode) {}
|
||||
virtual void writeComments(QTextStream &);
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/* CALL GRAPH NODE */
|
||||
struct CALL_GRAPH
|
||||
{
|
||||
PtrFunction proc; /* Pointer to procedure in pProcList */
|
||||
ilFunction proc; /* Pointer to procedure in pProcList */
|
||||
std::vector<CALL_GRAPH *> outEdges; /* array of out edges */
|
||||
public:
|
||||
void write();
|
||||
@ -12,8 +12,8 @@ public:
|
||||
}
|
||||
public:
|
||||
void writeNodeCallGraph(int indIdx);
|
||||
bool insertCallGraph(PtrFunction caller, PtrFunction callee);
|
||||
//bool insertCallGraph(PtrFunction caller, PtrFunction callee);
|
||||
void insertArc(PtrFunction newProc);
|
||||
bool insertCallGraph(ilFunction caller, ilFunction callee);
|
||||
bool insertCallGraph(Function *caller, ilFunction callee);
|
||||
void insertArc(ilFunction newProc);
|
||||
};
|
||||
//extern CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
#pragma once
|
||||
#include <QtCore/QObject>
|
||||
#include "src/Command.h"
|
||||
#include "project.h"
|
||||
|
||||
#include <QObject>
|
||||
class Project;
|
||||
class DccFrontend : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
void LoadImage();
|
||||
void parse(Project &proj);
|
||||
std::string m_fname;
|
||||
public:
|
||||
explicit DccFrontend(QObject *parent = 0);
|
||||
bool FrontEnd(); /* frontend.c */
|
||||
@ -17,28 +15,3 @@ signals:
|
||||
|
||||
public slots:
|
||||
};
|
||||
|
||||
struct MachineStateInitialization : public Command {
|
||||
|
||||
MachineStateInitialization() : Command("Initialize simulated machine state",eProject) {}
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
|
||||
struct FindMain : public Command {
|
||||
FindMain() : Command("Locate the main entry point",eProject) {}
|
||||
bool execute(CommandContext *ctx);
|
||||
};
|
||||
|
||||
struct CreateFunction : public Command {
|
||||
QString m_name;
|
||||
SegOffAddr m_addr;
|
||||
FunctionType *m_type;
|
||||
CreateFunction(QString name,SegOffAddr address,FunctionType *f) : Command("Create function",eProject),
|
||||
m_name(name),
|
||||
m_addr(address),
|
||||
m_type(f)
|
||||
{}
|
||||
QString instanceDescription() const override;
|
||||
|
||||
bool execute(CommandContext *ctx) override;
|
||||
};
|
||||
|
||||
@ -99,7 +99,7 @@ enum icodeType
|
||||
/* LOW_LEVEL icode opcodes */
|
||||
enum llIcode
|
||||
{
|
||||
//iINVALID,
|
||||
iINVALID=-1,
|
||||
iCBW, /* 0 */
|
||||
iAAA,
|
||||
iAAD,
|
||||
@ -263,8 +263,7 @@ enum hlType
|
||||
TYPE_STR, /* string */
|
||||
TYPE_CONST, /* constant (any type) */
|
||||
TYPE_FLOAT, /* floating point */
|
||||
TYPE_DOUBLE, /* double precision float */
|
||||
TYPE_FUNC
|
||||
TYPE_DOUBLE /* double precision float */
|
||||
};
|
||||
|
||||
/* Operand is defined, used or both flag */
|
||||
|
||||
@ -6,8 +6,6 @@
|
||||
#include "StackFrame.h"
|
||||
#include "CallConvention.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <QtCore/QString>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
@ -19,71 +17,42 @@ class QTextStream;
|
||||
struct CALL_GRAPH;
|
||||
struct Expr;
|
||||
struct Disassembler;
|
||||
class Function;
|
||||
struct Function;
|
||||
struct CALL_GRAPH;
|
||||
struct PROG;
|
||||
struct IStructuredTextTarget;
|
||||
|
||||
struct Function;
|
||||
|
||||
/* Procedure FLAGS */
|
||||
enum PROC_FLAGS
|
||||
{
|
||||
PROC_BADINST=0x00000100, /* Proc contains invalid or 386 instruction */
|
||||
PROC_IJMP =0x00000200, /* Proc incomplete due to indirect jmp */
|
||||
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
|
||||
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
|
||||
PROC_NEAR =0x00010000, /* Proc exits with near return */
|
||||
PROC_FAR =0x00020000, /* Proc exits with far return */
|
||||
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
|
||||
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
|
||||
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
|
||||
REG_ARGS =0x01000000, /* Proc has registers as arguments */
|
||||
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
|
||||
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
|
||||
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 */
|
||||
PROC_BADINST=0x00000100,/* Proc contains invalid or 386 instruction */
|
||||
PROC_IJMP =0x00000200,/* Proc incomplete due to indirect jmp */
|
||||
PROC_ICALL =0x00000400, /* Proc incomplete due to indirect call */
|
||||
PROC_HLL =0x00001000, /* Proc is likely to be from a HLL */
|
||||
// CALL_PASCAL =0x00002000, /* Proc uses Pascal calling convention */
|
||||
// CALL_C =0x00004000, /* Proc uses C calling convention */
|
||||
// CALL_UNKNOWN=0x00008000, /* Proc uses unknown calling convention */
|
||||
PROC_NEAR =0x00010000, /* Proc exits with near return */
|
||||
PROC_FAR =0x00020000, /* Proc exits with far return */
|
||||
GRAPH_IRRED =0x00100000, /* Proc generates an irreducible graph */
|
||||
SI_REGVAR =0x00200000, /* SI is used as a stack variable */
|
||||
DI_REGVAR =0x00400000, /* DI is used as a stack variable */
|
||||
PROC_IS_FUNC=0x00800000, /* Proc is a function */
|
||||
REG_ARGS =0x01000000, /* Proc has registers as arguments */
|
||||
// PROC_VARARG =0x02000000, /* Proc has variable arguments */
|
||||
PROC_OUTPUT =0x04000000, /* C for this proc has been output */
|
||||
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 {
|
||||
hlType dcc_type;
|
||||
};
|
||||
struct FunctionType : public Type
|
||||
struct FunctionType
|
||||
{
|
||||
CConv * m_call_conv;
|
||||
std::vector<Type> ContainedTys;
|
||||
ID retVal; /* Return value - identifier */
|
||||
bool m_vararg=false;
|
||||
unsigned getNumParams() const { return ContainedTys.size(); }
|
||||
bool isVarArg() const {return m_vararg;}
|
||||
void setReturnType(hlType t) {
|
||||
retVal.type = t;
|
||||
}
|
||||
void setReturnLocation(const LONGID_TYPE &v) {
|
||||
retVal.loc = REG_FRAME;
|
||||
retVal.longId() = v;
|
||||
}
|
||||
void setReturnLocation(eReg reg) {
|
||||
retVal.loc = REG_FRAME;
|
||||
retVal.id.regi = reg;
|
||||
}
|
||||
hlType getReturnType() const { return retVal.type; }
|
||||
void addArgument(hlType hl) {
|
||||
ContainedTys.push_back(Type {hl});
|
||||
}
|
||||
void clearArguments() { ContainedTys.clear(); }
|
||||
|
||||
void setCallingConvention(CConv::CC_Type cc);
|
||||
|
||||
static FunctionType *get(Type result,std::vector<Type> params, bool vararg_func) {
|
||||
FunctionType * res = new FunctionType;
|
||||
res->setReturnType(result.dcc_type);
|
||||
std::swap(res->ContainedTys,params);
|
||||
res->m_vararg = vararg_func;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
struct Assignment
|
||||
{
|
||||
@ -119,17 +88,7 @@ public:
|
||||
}
|
||||
void push_back(BB *v) { m_listBB.push_back(v);}
|
||||
};
|
||||
typedef std::shared_ptr<Function> PtrFunction;
|
||||
enum DecompilationStep : uint32_t {
|
||||
eNotDecoded, // no processing done yet
|
||||
eDisassemblyInProgress,
|
||||
eDissassembled, // low level disassembly done
|
||||
//eLocatedImpureRefs,
|
||||
//eStackTracing, // tracing stack depth across function calls
|
||||
|
||||
};
|
||||
|
||||
class Function : public std::enable_shared_from_this<Function>
|
||||
struct Function
|
||||
{
|
||||
typedef std::list<BB *> BasicBlockListType;
|
||||
// BasicBlock iterators...
|
||||
@ -137,26 +96,25 @@ class Function : public std::enable_shared_from_this<Function>
|
||||
typedef BasicBlockListType::const_iterator const_iterator;
|
||||
protected:
|
||||
BasicBlockListType BasicBlocks; ///< The basic blocks
|
||||
Function(FunctionType *ty) : nStep(eNotDecoded),procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
Function(FunctionType */*ty*/) : procEntry(0),depth(0),flg(0),cbParam(0),m_dfsLast(0),numBBs(0),
|
||||
hasCase(false),liveAnal(0)
|
||||
{
|
||||
type = ty;
|
||||
if(!ty) // No type was provided, create it
|
||||
type = new FunctionType;
|
||||
callingConv(CConv::UNKNOWN);
|
||||
type = new FunctionType;
|
||||
callingConv(CConv::eUnknown);
|
||||
}
|
||||
|
||||
public:
|
||||
DecompilationStep nStep; // decompilation step number for this function
|
||||
FunctionType * type;
|
||||
CConv * m_call_conv;
|
||||
uint32_t procEntry; /* label number */
|
||||
QString name; /* Meaningful name for this proc */
|
||||
STATE state; /* Entry state */
|
||||
int depth; /* Depth at which we found it - for printing */
|
||||
uint32_t flg; /* Combination of Icode & Proc flags */
|
||||
int16_t cbParam; /* Probable no. of bytes of parameters */
|
||||
STKFRAME args; /* Array of arguments */
|
||||
LOCAL_ID localId; /* Local identifiers */
|
||||
int depth; /* Depth at which we found it - for printing */
|
||||
uint32_t flg; /* Combination of Icode & Proc flags */
|
||||
int16_t cbParam; /* Probable no. of bytes of parameters */
|
||||
STKFRAME args; /* Array of arguments */
|
||||
LOCAL_ID localId; /* Local identifiers */
|
||||
ID retVal; /* Return value - identifier */
|
||||
|
||||
/* Icodes and control flow graph */
|
||||
CIcodeRec Icode; /* Object with ICODE records */
|
||||
@ -170,31 +128,26 @@ public:
|
||||
/* For interprocedural live analysis */
|
||||
LivenessSet liveIn; /* Registers used before defined */
|
||||
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() {
|
||||
delete type;
|
||||
}
|
||||
public:
|
||||
static PtrFunction Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
|
||||
static Function *Create(FunctionType *ty=0,int /*Linkage*/=0,const QString &nm="",void */*module*/=0)
|
||||
{
|
||||
PtrFunction r(new Function(ty));
|
||||
Function *r=new Function(ty);
|
||||
r->name = nm;
|
||||
return r;
|
||||
}
|
||||
hlType getReturnType() const {
|
||||
return getFunctionType()->getReturnType();
|
||||
}
|
||||
FunctionType *getFunctionType() const {
|
||||
return type;
|
||||
}
|
||||
CConv *callingConv() const { return type->m_call_conv;}
|
||||
void callingConv(CConv::CC_Type v);
|
||||
CConv *callingConv() const { return m_call_conv;}
|
||||
void callingConv(CConv::Type v);
|
||||
|
||||
// bool anyFlagsSet(uint32_t t) { return (flg&t)!=0;}
|
||||
bool hasRegArgs() const { return (flg & REG_ARGS)!=0;}
|
||||
void markDoNotDecompile() { flg |= PROC_ISLIB; }
|
||||
bool doNotDecompile() const { return isLibrary(); }
|
||||
bool isLibrary() const { return (flg & PROC_ISLIB)!=0;}
|
||||
void compoundCond();
|
||||
void writeProcComments();
|
||||
@ -208,7 +161,10 @@ public:
|
||||
void createCFG();
|
||||
void markImpure();
|
||||
void findImmedDom();
|
||||
void FollowCtrl(CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void process_operands(ICODE &pIcode, STATE *pstate);
|
||||
bool process_JMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool process_CALL(ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
void freeCFG();
|
||||
void codeGen(QIODevice & fs);
|
||||
void mergeFallThrough(BB *pBB);
|
||||
@ -218,7 +174,6 @@ public:
|
||||
void controlFlowAnalysis();
|
||||
void newRegArg(iICODE picode, iICODE ticode);
|
||||
void writeProcComments(QTextStream & ostr);
|
||||
void toStructuredText(IStructuredTextTarget *out,int level);
|
||||
|
||||
void displayCFG();
|
||||
void displayStats();
|
||||
@ -228,10 +183,11 @@ public:
|
||||
Expr * adjustActArgType(Expr *_exp, hlType forType);
|
||||
QString writeCall(Function *tproc, STKFRAME &args, int *numLoc);
|
||||
void processDosInt(STATE *pstate, PROG &prog, bool done);
|
||||
|
||||
void switchState(DecompilationStep s);
|
||||
ICODE *translate_DIV(LLInst *ll, ICODE &_Icode);
|
||||
ICODE *translate_XCHG(LLInst *ll, ICODE &_Icode);
|
||||
protected:
|
||||
void extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &table);
|
||||
bool followAllTableEntries(JumpTable &table, uint32_t cs, ICODE &pIcode, CALL_GRAPH *pcallGraph, STATE *pstate);
|
||||
bool removeInEdge_Flag_and_ProcessLatch(BB *pbb, BB *a, BB *b);
|
||||
bool Case_X_and_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
bool Case_X_or_Y(BB* pbb, BB* thenBB, BB* elseBB);
|
||||
@ -258,8 +214,12 @@ protected:
|
||||
void genLiveKtes();
|
||||
bool findDerivedSeq(derSeq &derivedGi);
|
||||
bool nextOrderGraph(derSeq &derivedGi);
|
||||
void addOutEdgesForConditionalJump(BB *pBB, int next_ip, LLInst *ll);
|
||||
void addOutEdgesForConditionalJump(BB* pBB, int next_ip, LLInst *ll);
|
||||
|
||||
private:
|
||||
bool decodeIndirectJMP(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
bool decodeIndirectJMP2(ICODE &pIcode, STATE *pstate, CALL_GRAPH *pcallGraph);
|
||||
};
|
||||
typedef std::list<PtrFunction> FunctionListType;
|
||||
typedef std::list<Function> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef lFunction::iterator ilFunction;
|
||||
|
||||
@ -10,11 +10,11 @@ struct STKFRAME : public SymbolTableCommon<STKSYM>
|
||||
//std::vector<STKSYM> sym;
|
||||
//STKSYM * sym; /* Symbols */
|
||||
int16_t m_minOff; /* Initial offset in stack frame*/
|
||||
int16_t m_maxOff; /* Maximum offset in stack frame*/
|
||||
int16_t maxOff; /* Maximum offset in stack frame*/
|
||||
int cb; /* Number of bytes in arguments */
|
||||
int numArgs; /* No. of arguments in the table*/
|
||||
void adjustForArgType(size_t numArg_, hlType actType_);
|
||||
STKFRAME() : m_minOff(0),m_maxOff(0),cb(0),numArgs(0)
|
||||
STKFRAME() : m_minOff(0),maxOff(0),cb(0),numArgs(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ static const condOp condOpJCond[12] = {LESS, LESS_EQUAL, GREATER_EQUAL, GREATER,
|
||||
EQUAL, NOT_EQUAL, LESS, GREATER_EQUAL,
|
||||
LESS_EQUAL, GREATER, GREATER_EQUAL, LESS};
|
||||
struct AstIdent;
|
||||
class Function;
|
||||
struct Function;
|
||||
struct STKFRAME;
|
||||
struct LOCAL_ID;
|
||||
struct ICODE;
|
||||
@ -221,9 +221,6 @@ struct AstIdent : public UnaryOperator
|
||||
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);
|
||||
virtual Expr *insertSubTreeLongReg(Expr *_expr, int longIdx);
|
||||
virtual bool xClear(rICODE range_to_check, iICODE lastBBinst, const LOCAL_ID &locId);
|
||||
protected:
|
||||
eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl);
|
||||
|
||||
};
|
||||
struct GlobalVariable : public AstIdent
|
||||
{
|
||||
@ -241,7 +238,7 @@ struct GlobalVariable : public AstIdent
|
||||
struct GlobalVariableIdx : public AstIdent
|
||||
{
|
||||
bool valid;
|
||||
int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */
|
||||
int idxGlbIdx; /* idx into localId, GLOB_VAR_IDX */
|
||||
|
||||
virtual Expr *clone() const
|
||||
{
|
||||
@ -255,9 +252,9 @@ struct GlobalVariableIdx : public AstIdent
|
||||
struct Constant : public AstIdent
|
||||
{
|
||||
struct _kte
|
||||
{ /* for CONSTANT only */
|
||||
uint32_t kte; /* value of the constant */
|
||||
uint8_t size; /* #bytes size constant */
|
||||
{ /* for CONSTANT only */
|
||||
uint32_t kte; /* value of the constant */
|
||||
uint8_t size; /* #bytes size constant */
|
||||
} kte;
|
||||
|
||||
Constant(uint32_t _kte, uint8_t size)
|
||||
@ -272,11 +269,11 @@ struct Constant : public AstIdent
|
||||
}
|
||||
QString walkCondExpr(Function *pProc, int *numLoc) const;
|
||||
int hlTypeSize(Function *pproc) const;
|
||||
hlType expType(Function *pproc) const;
|
||||
hlType expType(Function *pproc) const { return TYPE_CONST; }
|
||||
};
|
||||
struct FuncNode : public AstIdent
|
||||
{
|
||||
struct _call { /* for FUNCTION only */
|
||||
struct _call { /* for FUNCTION only */
|
||||
Function *proc;
|
||||
STKFRAME *args;
|
||||
} call;
|
||||
@ -297,8 +294,8 @@ struct FuncNode : public AstIdent
|
||||
struct RegisterNode : public AstIdent
|
||||
{
|
||||
const LOCAL_ID *m_syms;
|
||||
regType regiType; /* for REGISTER only */
|
||||
int regiIdx; /* index into localId, REGISTER */
|
||||
regType regiType; /* for REGISTER only */
|
||||
int regiIdx; /* index into localId, REGISTER */
|
||||
|
||||
virtual Expr *insertSubTreeReg(Expr *_expr, eReg regi, const LOCAL_ID *locsym);
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ public:
|
||||
};
|
||||
|
||||
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 writeBundle (QIODevice & ios, bundle procCode);
|
||||
|
||||
@ -22,31 +22,31 @@
|
||||
#include "BasicBlock.h"
|
||||
class Project;
|
||||
/* 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 ****/
|
||||
|
||||
extern QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||
extern QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||
|
||||
typedef struct { /* Command line option flags */
|
||||
unsigned verbose : 1;
|
||||
unsigned VeryVerbose : 1;
|
||||
unsigned asm1 : 1; /* Early disassembly listing */
|
||||
unsigned asm2 : 1; /* Disassembly listing after restruct */
|
||||
unsigned Map : 1;
|
||||
unsigned Stats : 1;
|
||||
unsigned Interact : 1; /* Interactive mode */
|
||||
unsigned Calls : 1; /* Follow register indirect calls */
|
||||
QString filename; /* The input filename */
|
||||
/** Command line option flags */
|
||||
struct OPTION
|
||||
{
|
||||
bool verbose;
|
||||
bool VeryVerbose;
|
||||
bool asm1; /* Early disassembly listing */
|
||||
bool asm2; /* Disassembly listing after restruct */
|
||||
bool Map;
|
||||
bool Stats;
|
||||
bool Interact; /* Interactive mode */
|
||||
bool Calls; /* Follow register indirect calls */
|
||||
QString filename; /* The input filename */
|
||||
uint32_t CustomEntryPoint;
|
||||
} OPTION;
|
||||
};
|
||||
|
||||
extern OPTION option; /* Command line options */
|
||||
|
||||
#include "BinaryImage.h"
|
||||
|
||||
|
||||
|
||||
/* Memory map states */
|
||||
enum eAreaType
|
||||
{
|
||||
@ -59,13 +59,13 @@ enum eAreaType
|
||||
/* Intermediate instructions statistics */
|
||||
struct STATS
|
||||
{
|
||||
int numBBbef; /* number of basic blocks initially */
|
||||
int numBBaft; /* number of basic blocks at the end */
|
||||
int nOrder; /* n-th order */
|
||||
int numLLIcode; /* number of low-level Icode instructions */
|
||||
int numHLIcode; /* number of high-level Icode instructions */
|
||||
int totalLL; /* total number of low-level Icode insts */
|
||||
int totalHL; /* total number of high-level Icod insts */
|
||||
int numBBbef; /* number of basic blocks initially */
|
||||
int numBBaft; /* number of basic blocks at the end */
|
||||
int nOrder; /* n-th order */
|
||||
int numLLIcode; /* number of low-level Icode instructions */
|
||||
int numHLIcode; /* number of high-level Icode instructions */
|
||||
int totalLL; /* total number of low-level Icode insts */
|
||||
int totalHL; /* total number of high-level Icod insts */
|
||||
};
|
||||
|
||||
extern STATS stats; /* Icode statistics */
|
||||
@ -76,17 +76,18 @@ extern STATS stats; /* Icode statistics */
|
||||
void udm(void); /* udm.c */
|
||||
void freeCFG(BB * cfg); /* 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 */
|
||||
eErrorId scan(uint32_t ip, ICODE &p); /* scanner.c */
|
||||
void parse (CALL_GRAPH * *); /* parser.c */
|
||||
|
||||
extern int strSize (const uint8_t *, char); /* parser.c */
|
||||
void interactDis(const PtrFunction &, int initIC); /* disassem.c */
|
||||
//void disassem(int pass, Function * pProc); /* disassem.c */
|
||||
void interactDis(Function *, int initIC); /* disassem.c */
|
||||
bool JmpInst(llIcode opcode); /* idioms.c */
|
||||
queue::iterator appendQueue(queue &Q, BB *node); /* reducible.c */
|
||||
|
||||
bool SetupLibCheck(QString pattern_file_id); /* chklib.c */
|
||||
bool SetupLibCheck(void); /* chklib.c */
|
||||
void CleanupLibCheck(void); /* chklib.c */
|
||||
bool LibCheck(Function &p); /* chklib.c */
|
||||
|
||||
@ -99,7 +100,5 @@ QString writeJcondInv(HLTYPE, Function *, int *);
|
||||
/* Exported funcions from locident.c */
|
||||
bool checkLongEq(LONG_STKID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &atOffset);
|
||||
bool checkLongRegEq(LONGID_TYPE, iICODE, int, Function *, Assignment &asgn, LLInst &);
|
||||
eReg otherLongRegi(eReg, int, LOCAL_ID *);
|
||||
|
||||
|
||||
extern const char *indentStr(int level);
|
||||
|
||||
@ -4,11 +4,21 @@
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QDir>
|
||||
|
||||
class IStructuredTextTarget;
|
||||
class IXmlTarget;
|
||||
|
||||
struct IDcc {
|
||||
static IDcc *get();
|
||||
virtual bool load(QString name)=0; // load and preprocess -> find entry point
|
||||
virtual void BaseInit()=0;
|
||||
virtual void Init(QObject *tgt)=0;
|
||||
virtual lFunction::iterator GetFirstFuncHandle()=0;
|
||||
virtual lFunction::iterator GetCurFuncHandle()=0;
|
||||
virtual void analysis_Once()=0;
|
||||
virtual void load(QString name)=0; // load and preprocess -> find entry point
|
||||
virtual void prtout_asm(IXmlTarget *,int level=0)=0;
|
||||
virtual void prtout_cpp(IXmlTarget *,int level=0)=0;
|
||||
virtual size_t getFuncCount()=0;
|
||||
virtual const lFunction &validFunctions() const =0;
|
||||
virtual void SetCurFunc_by_Name(QString )=0;
|
||||
virtual QDir installDir()=0;
|
||||
virtual QDir dataDir(QString kind)=0;
|
||||
};
|
||||
|
||||
@ -7,22 +7,19 @@
|
||||
#pragma once
|
||||
#include "bundle.h"
|
||||
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
struct LLInst;
|
||||
class Function;
|
||||
typedef std::shared_ptr<Function> PtrFunction;
|
||||
|
||||
struct Function;
|
||||
struct Disassembler
|
||||
{
|
||||
protected:
|
||||
int pass=0;
|
||||
int g_lab=0;
|
||||
QIODevice *m_disassembly_target=nullptr;
|
||||
int pass;
|
||||
int g_lab;
|
||||
//bundle &cCode;
|
||||
QIODevice *m_disassembly_target;
|
||||
QTextStream m_fp;
|
||||
std::vector<std::string> m_decls;
|
||||
std::vector<std::string> m_code;
|
||||
@ -30,29 +27,30 @@ protected:
|
||||
public:
|
||||
Disassembler(int _p) : pass(_p)
|
||||
{
|
||||
g_lab=0;
|
||||
}
|
||||
|
||||
void disassem(PtrFunction ppProc);
|
||||
void disassem(PtrFunction ppProc, int i);
|
||||
public:
|
||||
void disassem(Function *ppProc);
|
||||
void disassem(Function *ppProc, int i);
|
||||
void dis1Line(LLInst &inst, int loc_ip, int pass);
|
||||
};
|
||||
/* Definitions for extended keys (first key is zero) */
|
||||
|
||||
#define EXT 0x100 /* "Extended" flag */
|
||||
#define EXT 0x100 /* "Extended" flag */
|
||||
|
||||
#ifdef __UNIX__
|
||||
#define KEY_DOWN EXT+'B'
|
||||
#define KEY_LEFT EXT+'D'
|
||||
#define KEY_UP EXT+'A'
|
||||
#define KEY_RIGHT EXT+'C'
|
||||
#define KEY_NPAGE EXT+'J' /* Enter correct value! */
|
||||
#define KEY_PPAGE EXT+'K' /* Another guess! */
|
||||
#define KEY_DOWN EXT+'B'
|
||||
#define KEY_LEFT EXT+'D'
|
||||
#define KEY_UP EXT+'A'
|
||||
#define KEY_RIGHT EXT+'C'
|
||||
#define KEY_NPAGE EXT+'J' /* Enter correct value! */
|
||||
#define KEY_PPAGE EXT+'K' /* Another guess! */
|
||||
#endif
|
||||
|
||||
/* "Attributes" */
|
||||
#define A_NORMAL 'N' /* For Dos/Unix */
|
||||
#define A_REVERSE 'I'
|
||||
#define A_BOLD 'B'
|
||||
#define A_NORMAL 'N' /* For Dos/Unix */
|
||||
#define A_REVERSE 'I'
|
||||
#define A_BOLD 'B'
|
||||
|
||||
#define LINES 24
|
||||
#define COLS 80
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <stdint.h>
|
||||
#include <list>
|
||||
|
||||
class Function;
|
||||
struct Function;
|
||||
/* Types of basic block nodes */
|
||||
/* Real basic blocks: type defined according to their out-edges */
|
||||
enum eBBKind
|
||||
@ -51,16 +51,16 @@ enum eNodeHeaderType
|
||||
|
||||
/* Uninitialized values for certain fields */
|
||||
#define NO_NODE MAX /* node has no associated node */
|
||||
#define NO_DOM MAX /* node has no dominator */
|
||||
#define UN_INIT MAX /* uninitialized variable */
|
||||
#define NO_DOM MAX /* node has no dominator */
|
||||
#define UN_INIT MAX /* uninitialized variable */
|
||||
|
||||
#define THEN 0 /* then edge */
|
||||
#define ELSE 1 /* else edge */
|
||||
|
||||
/* Basic Block (BB) flags */
|
||||
|
||||
#define INVALID_BB 0x0001 /* BB is not valid any more */
|
||||
#define IS_LATCH_NODE 0x0002 /* BB is the latching node of a loop */
|
||||
#define INVALID_BB 0x0001 /* BB is not valid any more */
|
||||
#define IS_LATCH_NODE 0x0002 /* BB is the latching node of a loop */
|
||||
|
||||
struct BB;
|
||||
/* Interval structure */
|
||||
|
||||
321
include/icode.h
321
include/icode.h
@ -7,7 +7,7 @@
|
||||
#include "BinaryImage.h"
|
||||
#include "libdis.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 <boost/range/iterator_range.hpp>
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
struct LOCAL_ID;
|
||||
struct BB;
|
||||
class Function;
|
||||
struct Function;
|
||||
struct STKFRAME;
|
||||
class CIcodeRec;
|
||||
struct ICODE;
|
||||
@ -128,7 +128,7 @@ struct DU
|
||||
};
|
||||
|
||||
/* 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;
|
||||
@ -165,8 +165,8 @@ struct AssignType : public HlTypeSupport
|
||||
/* for HLI_ASSIGN */
|
||||
protected:
|
||||
public:
|
||||
Expr *m_lhs;
|
||||
Expr *m_rhs;
|
||||
Expr * m_lhs;
|
||||
Expr * m_rhs;
|
||||
AssignType() {}
|
||||
Expr *lhs() const {return m_lhs;}
|
||||
void lhs(Expr *l);
|
||||
@ -176,8 +176,8 @@ public:
|
||||
struct ExpType : public HlTypeSupport
|
||||
{
|
||||
/* for HLI_JCOND, HLI_RET, HLI_PUSH, HLI_POP*/
|
||||
Expr *v;
|
||||
ExpType() : v(0) {}
|
||||
Expr * v;
|
||||
ExpType() : v(nullptr) {}
|
||||
bool removeRegFromLong(eReg regi, LOCAL_ID *locId)
|
||||
{
|
||||
v=performLongRemoval(regi,locId,v);
|
||||
@ -243,20 +243,20 @@ public:
|
||||
/* LOW_LEVEL icode operand record */
|
||||
struct LLOperand
|
||||
{
|
||||
eReg seg; /* CS, DS, ES, SS */
|
||||
eReg segOver; /* CS, DS, ES, SS if segment override */
|
||||
int16_t segValue; /* Value of segment seg during analysis */
|
||||
eReg regi; /* 0 < regs < INDEXBASE <= index modes */
|
||||
int16_t off; /* memory address offset */
|
||||
uint32_t opz; /* idx of immed src op */
|
||||
bool immed;
|
||||
bool is_offset; // set by jumps
|
||||
bool is_compound;
|
||||
size_t width;
|
||||
/* Source operand if (flg & I) */
|
||||
struct { /* Call & # actual arg bytes */
|
||||
eReg seg; /* CS, DS, ES, SS */
|
||||
eReg segOver; /* CS, DS, ES, SS if segment override */
|
||||
int16_t segValue; /* Value of segment seg during analysis */
|
||||
eReg regi; /* 0 < regs < INDEXBASE <= index modes */
|
||||
int16_t off; /* memory address offset */
|
||||
uint32_t opz; /* idx of immed src op */
|
||||
bool immed;
|
||||
bool is_offset; // set by jumps
|
||||
bool is_compound;
|
||||
size_t width;
|
||||
//union {/* Source operand if (flg & I) */
|
||||
struct { /* Call & # actual arg bytes */
|
||||
Function *proc; /* pointer to target proc (for CALL(F))*/
|
||||
int cb; /* # actual arg bytes */
|
||||
int cb; /* # actual arg bytes */
|
||||
} proc;
|
||||
LLOperand() : seg(rUNDEF),segOver(rUNDEF),segValue(0),regi(rUNDEF),off(0),
|
||||
opz(0),immed(0),is_offset(false),is_compound(0),width(0)
|
||||
@ -300,11 +300,11 @@ struct LLOperand
|
||||
Op.regi = (eReg)Val;
|
||||
return Op;
|
||||
}
|
||||
bool isSet() const
|
||||
bool isSet()
|
||||
{
|
||||
return not (*this == LLOperand());
|
||||
}
|
||||
void addProcInformation(int param_count, CConv::CC_Type call_conv);
|
||||
void addProcInformation(int param_count, CConv::Type call_conv);
|
||||
bool isImmediate() const { return immed;}
|
||||
void setImmediate(bool x) { immed=x;}
|
||||
bool compound() const {return is_compound;} // dx:ax pair
|
||||
@ -313,126 +313,131 @@ struct LLOperand
|
||||
struct LLInst
|
||||
{
|
||||
protected:
|
||||
uint32_t m_opcode; // Low level opcode identifier
|
||||
uint32_t flg; /* icode flags */
|
||||
LLOperand m_src; /* source operand */
|
||||
llIcode m_opcode; // Low level opcode identifier
|
||||
uint32_t flg; /* icode flags */
|
||||
LLOperand m_src; /* source operand */
|
||||
public:
|
||||
int codeIdx; /* Index into cCode.code */
|
||||
uint8_t numBytes; /* Number of bytes this instr */
|
||||
uint32_t label; /* offset in image (20-bit adr) */
|
||||
LLOperand m_dst; /* destination operand */
|
||||
DU flagDU; /* def/use of flags */
|
||||
int caseEntry;
|
||||
int codeIdx; /* Index into cCode.code */
|
||||
uint8_t numBytes; /* Number of bytes this instr */
|
||||
uint32_t label; /* offset in image (20-bit adr) */
|
||||
LLOperand m_dst; /* destination operand */
|
||||
DU flagDU; /* def/use of flags */
|
||||
int caseEntry;
|
||||
std::vector<uint32_t> caseTbl2;
|
||||
int hllLabNum; /* label # for hll codegen */
|
||||
int hllLabNum; /* label # for hll codegen */
|
||||
|
||||
uint32_t getOpcode() const { return m_opcode;}
|
||||
void setOpcode(uint32_t op) { m_opcode=op; }
|
||||
bool conditionalJump()
|
||||
{
|
||||
return (getOpcode() >= iJB) and (getOpcode() < iJCXZ);
|
||||
}
|
||||
bool testFlags(uint32_t x) const { return (flg & x)!=0;}
|
||||
void setFlags(uint32_t flag) {flg |= flag;}
|
||||
void clrFlags(uint32_t flag);
|
||||
uint32_t getFlag() const {return flg;}
|
||||
uint32_t GetLlLabel() const { return label;}
|
||||
llIcode getOpcode() const { return m_opcode;}
|
||||
void setOpcode(uint32_t op) { m_opcode=(llIcode)op; }
|
||||
bool conditionalJump()
|
||||
{
|
||||
return (getOpcode() >= iJB) and (getOpcode() < iJCXZ);
|
||||
}
|
||||
bool testFlags(uint32_t x) const { return (flg & x)!=0;}
|
||||
void setFlags(uint32_t flag) {flg |= flag;}
|
||||
void clrFlags(uint32_t flag)
|
||||
{
|
||||
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 isJmpInst();
|
||||
HLTYPE createCall();
|
||||
LLInst(ICODE *container) : flg(0),codeIdx(0),numBytes(0),m_link(container)
|
||||
{
|
||||
setOpcode(0);
|
||||
}
|
||||
const LLOperand & dst() const { return m_dst; }
|
||||
LLOperand & dst() { return m_dst; }
|
||||
const LLOperand & src() const { return m_src; }
|
||||
LLOperand & src() { return m_src; }
|
||||
void replaceSrc(const LLOperand &with) { m_src = with; }
|
||||
void replaceSrc(eReg r) { m_src = LLOperand::CreateReg2(r); }
|
||||
void replaceSrc(int64_t r) { m_src = LLOperand::CreateImm2(r); }
|
||||
void replaceDst(const LLOperand &with) { m_dst = with; }
|
||||
bool srcIsImmed() const { return (flg & I)!=0; }
|
||||
condId idType(opLoc sd) const;
|
||||
bool match(llIcode op)
|
||||
{
|
||||
return (getOpcode()==op);
|
||||
}
|
||||
bool matchWithRegDst(llIcode op)
|
||||
{
|
||||
return (getOpcode()==op) and m_dst.isReg();
|
||||
}
|
||||
bool match(llIcode op,eReg dest)
|
||||
{
|
||||
return (getOpcode()==op)&&m_dst.regi==dest;
|
||||
}
|
||||
bool match(llIcode op,eReg dest,uint32_t flgs)
|
||||
{
|
||||
return (getOpcode()==op) and (m_dst.regi==dest) and testFlags(flgs);
|
||||
}
|
||||
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; }
|
||||
LLOperand * get(opLoc sd) { return (sd == SRC) ? &src() : &m_dst; }
|
||||
|
||||
ICODE * m_link;
|
||||
};
|
||||
struct ADDRESS {
|
||||
|
||||
};
|
||||
struct BinaryArea {
|
||||
ADDRESS start;
|
||||
ADDRESS fin;
|
||||
};
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
|
||||
/* Icode definition: LOW_LEVEL and HIGH_LEVEL */
|
||||
struct ICODE
|
||||
@ -440,7 +445,7 @@ struct ICODE
|
||||
// use llvm names at least
|
||||
typedef BB MachineBasicBlock;
|
||||
protected:
|
||||
LLInst *m_ll;
|
||||
LLInst m_ll;
|
||||
HLTYPE m_hl;
|
||||
MachineBasicBlock * Parent; /* BB to which this icode belongs */
|
||||
bool invalid; /* Has no HIGH_LEVEL equivalent */
|
||||
@ -543,8 +548,8 @@ public:
|
||||
DU1 du1; /* du chain 1 */
|
||||
int loc_ip; // used by CICodeRec to number ICODEs
|
||||
|
||||
LLInst * ll() { return m_ll;}
|
||||
const LLInst * ll() const { return m_ll;}
|
||||
LLInst * ll() { return &m_ll;}
|
||||
const LLInst * ll() const { return &m_ll;}
|
||||
|
||||
HLTYPE * hlU() {
|
||||
// assert(type==HIGH_LEVEL);
|
||||
@ -584,46 +589,8 @@ public:
|
||||
{
|
||||
return hlU()->call.newStkArg(exp,opcode,pproc);
|
||||
}
|
||||
ICODE() :Parent(0),invalid(false),type(NOT_SCANNED_ICODE),loc_ip(0)
|
||||
ICODE() : m_ll(this),Parent(0),invalid(false),type(NOT_SCANNED_ICODE),loc_ip(0)
|
||||
{
|
||||
m_ll = new LLInst(this);
|
||||
}
|
||||
~ICODE() {
|
||||
delete m_ll;
|
||||
}
|
||||
ICODE(const ICODE &v) {
|
||||
m_ll = new LLInst(*v.m_ll);
|
||||
m_hl = v.m_hl;
|
||||
Parent = v.Parent;
|
||||
insn = v.insn;
|
||||
type = v.type;
|
||||
du = v.du;
|
||||
du1 = v.du1;
|
||||
loc_ip = v.loc_ip;
|
||||
|
||||
}
|
||||
ICODE & operator=(const ICODE &v) {
|
||||
delete m_ll;
|
||||
m_ll = v.m_ll;
|
||||
m_hl = v.m_hl;
|
||||
Parent = v.Parent;
|
||||
insn = v.insn;
|
||||
type = v.type;
|
||||
du = v.du;
|
||||
du1 = v.du1;
|
||||
loc_ip = v.loc_ip;
|
||||
return *this;
|
||||
}
|
||||
ICODE & operator=(ICODE &&v) {
|
||||
std::swap(m_ll,v.m_ll);
|
||||
std::swap(m_hl,v.m_hl);
|
||||
std::swap(Parent , v.Parent);
|
||||
std::swap(insn , v.insn);
|
||||
std::swap(type , v.type);
|
||||
std::swap(du , v.du);
|
||||
std::swap(du1 , v.du1);
|
||||
std::swap(loc_ip , v.loc_ip);
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
const MachineBasicBlock* getParent() const { return Parent; }
|
||||
@ -644,9 +611,9 @@ public:
|
||||
class CIcodeRec : public std::list<ICODE>
|
||||
{
|
||||
public:
|
||||
CIcodeRec(); // Constructor
|
||||
CIcodeRec(); // Constructor
|
||||
|
||||
ICODE * addIcode(const ICODE * pIcode);
|
||||
ICODE * addIcode(ICODE *pIcode);
|
||||
void SetInBB(rCODE &rang, BB* pnewBB);
|
||||
bool labelSrch(uint32_t target, uint32_t &pIndex);
|
||||
iterator labelSrch(uint32_t target);
|
||||
|
||||
@ -28,7 +28,7 @@ struct LLInst;
|
||||
typedef std::list<ICODE>::iterator iICODE;
|
||||
struct IDX_ARRAY : public std::vector<iICODE>
|
||||
{
|
||||
bool inList(iICODE idx)
|
||||
bool inList(iICODE idx) const
|
||||
{
|
||||
return std::find(begin(),end(),idx)!=end();
|
||||
}
|
||||
@ -36,32 +36,32 @@ struct IDX_ARRAY : public std::vector<iICODE>
|
||||
|
||||
enum frameType
|
||||
{
|
||||
STK_FRAME, /* For stack vars */
|
||||
REG_FRAME, /* For register variables */
|
||||
GLB_FRAME /* For globals */
|
||||
STK_FRAME, /* For stack vars */
|
||||
REG_FRAME, /* For register variables */
|
||||
GLB_FRAME /* For globals */
|
||||
};
|
||||
|
||||
struct BWGLB_TYPE
|
||||
{
|
||||
int16_t seg; /* segment value */
|
||||
int16_t off; /* offset */
|
||||
eReg regi; /* optional indexed register */
|
||||
int16_t seg; /* segment value */
|
||||
int16_t off; /* offset */
|
||||
eReg regi; /* optional indexed register */
|
||||
} ;
|
||||
|
||||
|
||||
/* For TYPE_LONG_(UN)SIGN on the stack */
|
||||
struct LONG_STKID_TYPE
|
||||
{
|
||||
int offH; /* high offset from BP */
|
||||
int offL; /* low offset from BP */
|
||||
int offH; /* high offset from BP */
|
||||
int offL; /* low offset from BP */
|
||||
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
|
||||
{
|
||||
protected:
|
||||
eReg m_h; /* high register */
|
||||
eReg m_l; /* low register */
|
||||
eReg m_h; /* high register */
|
||||
eReg m_l; /* low register */
|
||||
public:
|
||||
void set(eReg highpart,eReg lowpart)
|
||||
{
|
||||
@ -75,7 +75,7 @@ public:
|
||||
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 offH; /* offset high */
|
||||
@ -93,28 +93,30 @@ struct LONGGLB_TYPE /* For TYPE_LONG_(UN)SIGN globals */
|
||||
struct ID
|
||||
{
|
||||
protected:
|
||||
LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */
|
||||
LONGID_TYPE m_longId; /* For TYPE_LONG_(UN)SIGN registers */
|
||||
public:
|
||||
hlType type; /* Probable type */
|
||||
bool illegal; /* Boolean: not a valid field any more */
|
||||
//std::vector<iICODE> idx;
|
||||
IDX_ARRAY idx; /* Index into icode array (REG_FRAME only) */
|
||||
frameType loc; /* Frame location */
|
||||
bool illegal; /* Boolean: not a valid field any more */
|
||||
bool hasMacro; /* Identifier requires a macro */
|
||||
char macro[10]; /* Macro for this identifier */
|
||||
QString name; /* Identifier's name */
|
||||
union ID_UNION { /* Different types of identifiers */
|
||||
friend struct ID;
|
||||
protected:
|
||||
LONG_STKID_TYPE longStkId; /* For TYPE_LONG_(UN)SIGN on the stack */
|
||||
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 */
|
||||
uint8_t regOff; /* register offset (if any) */
|
||||
int off; /* offset from BP */
|
||||
int off; /* offset from BP */
|
||||
} 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;
|
||||
struct { /* For TYPE_LONG_(UN)SIGN constants */
|
||||
uint32_t h; /* high uint16_t */
|
||||
uint32_t l; /* low uint16_t */
|
||||
struct { /* For TYPE_LONG_(UN)SIGN constants */
|
||||
uint32_t h; /* high uint16_t */
|
||||
uint32_t l; /* low uint16_t */
|
||||
} longKte;
|
||||
ID_UNION() { /*new (&longStkId) LONG_STKID_TYPE();*/}
|
||||
} id;
|
||||
@ -140,6 +142,8 @@ public:
|
||||
sprintf (buf, "loc%d", i);
|
||||
name=buf;
|
||||
}
|
||||
bool isLongRegisterPair() const { return (loc == REG_FRAME) and isLong();}
|
||||
eReg getPairedRegister(eReg first) const;
|
||||
};
|
||||
|
||||
struct LOCAL_ID
|
||||
@ -167,10 +171,11 @@ public:
|
||||
void flagByteWordId(int off);
|
||||
void propLongId(uint8_t regL, uint8_t regH, const QString & name);
|
||||
size_t csym() const {return id_arr.size();}
|
||||
void newRegArg(iICODE picode, iICODE ticode) const;
|
||||
void processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode, bool isLong) const;
|
||||
void forwardSubs(Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode, int &numHlIcodes) const;
|
||||
void newRegArg(ICODE & picode, ICODE & ticode) const;
|
||||
void processTargetIcode(ICODE & picode, int &numHlIcodes, ICODE & ticode, bool isLong) const;
|
||||
void forwardSubs(Expr *lhs, Expr *rhs, ICODE & picode, ICODE & ticode, int &numHlIcodes) const;
|
||||
AstIdent *createId(const ID *retVal, iICODE ix_);
|
||||
eReg getPairedRegisterAt(int idx,eReg first) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,174 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "symtab.h"
|
||||
#include "BinaryImage.h"
|
||||
#include "Procedure.h"
|
||||
#include "state.h"
|
||||
#include "src/Command.h"
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
#include <list>
|
||||
#include <boost/icl/interval.hpp>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <boost/icl/split_interval_map.hpp>
|
||||
#include <QtCore/QString>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include "symtab.h"
|
||||
#include "BinaryImage.h"
|
||||
#include "Procedure.h"
|
||||
class QString;
|
||||
class SourceMachine;
|
||||
struct CALL_GRAPH;
|
||||
struct DosLoader;
|
||||
struct SegOffAddr {
|
||||
uint16_t seg;
|
||||
uint32_t addr;
|
||||
};
|
||||
enum CompilerVendor {
|
||||
eUnknownVendor=0,
|
||||
eBorland,
|
||||
eMicrosoft,
|
||||
eLogitech,
|
||||
};
|
||||
enum CompilerLanguage {
|
||||
eUnknownLanguage=0,
|
||||
eAnsiCorCPP,
|
||||
ePascal,
|
||||
eModula2
|
||||
};
|
||||
enum CompilerMemoryModel {
|
||||
eUnknownMemoryModel=0,
|
||||
eTiny,
|
||||
eSmall,
|
||||
eCompact,
|
||||
eMedium,
|
||||
eLarge
|
||||
};
|
||||
struct LoaderMetadata {
|
||||
CompilerVendor compiler_vendor;
|
||||
CompilerLanguage compiler_language;
|
||||
CompilerMemoryModel compiler_memory_model;
|
||||
int compiler_version;
|
||||
QString compilerId() const {
|
||||
switch(compiler_vendor) {
|
||||
case eBorland:
|
||||
switch(compiler_language) {
|
||||
case eUnknownLanguage:
|
||||
return QString("bx") + codeModelChar();
|
||||
case eAnsiCorCPP:
|
||||
return QString("b%1%2").arg(compiler_version).arg(codeModelChar());
|
||||
case ePascal:
|
||||
return QString("tp%1").arg(compiler_version);
|
||||
default:
|
||||
return "xxx";
|
||||
}
|
||||
case eMicrosoft:
|
||||
assert(compiler_language==eAnsiCorCPP);
|
||||
return QString("m%1%2").arg(compiler_version).arg(codeModelChar());
|
||||
case eLogitech:
|
||||
assert(compiler_language==eModula2);
|
||||
return QString("l%1%2").arg(compiler_version).arg(codeModelChar());
|
||||
case eUnknownVendor:
|
||||
return "xxx";
|
||||
}
|
||||
return "xxx";
|
||||
}
|
||||
QChar codeModelChar() const {
|
||||
switch(compiler_memory_model) {
|
||||
case eUnknownMemoryModel: return 'x';
|
||||
case eTiny: return 't';
|
||||
case eSmall: return 's';
|
||||
case eCompact: return 'c';
|
||||
case eMedium: return 'm';
|
||||
case eLarge: return 'l';
|
||||
}
|
||||
return 'x';
|
||||
}
|
||||
};
|
||||
class Project : public QObject
|
||||
class IProject
|
||||
{
|
||||
Q_OBJECT
|
||||
virtual PROG *binary()=0;
|
||||
virtual const QString & project_name() const =0;
|
||||
virtual const QString & binary_path() const =0;
|
||||
};
|
||||
class Project : public IProject
|
||||
{
|
||||
static Project *s_instance;
|
||||
QString m_fname;
|
||||
QString m_project_name;
|
||||
QString m_output_path;
|
||||
public:
|
||||
DosLoader * m_selected_loader;
|
||||
bool m_metadata_available=false;
|
||||
LoaderMetadata m_loader_data;
|
||||
uint32_t SynthLab; //!< Last snthetic lab idx
|
||||
SYMTAB symtab; //!< Global symbol table
|
||||
FunctionListType pProcList; //!< List of located functions
|
||||
CALL_GRAPH * callGraph; //!< Pointer to the head of the call graph
|
||||
STATE m_entry_state; //!< Machine state at program load
|
||||
|
||||
PROG prog; /* Loaded program image parameters */
|
||||
CommandStream m_project_command_stream;
|
||||
std::unordered_map<PtrFunction,CommandStream> m_function_streams;
|
||||
typedef std::list<Function> FunctionListType;
|
||||
typedef FunctionListType lFunction;
|
||||
typedef FunctionListType::iterator ilFunction;
|
||||
|
||||
bool m_error_state;
|
||||
struct PatternLocator *m_pattern_locator;
|
||||
public:
|
||||
// prevent Project instance copying
|
||||
SYMTAB symtab; /* Global symbol table */
|
||||
FunctionListType pProcList;
|
||||
CALL_GRAPH * callGraph; /* Pointer to the head of the call graph */
|
||||
PROG prog; /* Loaded program image parameters */
|
||||
// no copies
|
||||
Project(const Project&) = delete;
|
||||
const Project & operator=(const Project & l) =delete;
|
||||
// only moves
|
||||
Project(); // default constructor,
|
||||
|
||||
public:
|
||||
void create(const QString &a);
|
||||
|
||||
bool addLoadCommands(QString fname);
|
||||
void processAllCommands();
|
||||
void resetCommandsAndErrorState();
|
||||
|
||||
|
||||
bool load();
|
||||
const QString & output_path() const {return m_output_path;}
|
||||
const QString & project_name() const {return m_project_name;}
|
||||
const QString & binary_path() const {return m_fname;}
|
||||
QString output_name(const char *ext);
|
||||
ilFunction funcIter(Function *to_find);
|
||||
PtrFunction findByEntry(uint32_t entry);
|
||||
PtrFunction findByName(const QString &name);
|
||||
PtrFunction createFunction(FunctionType *f, const QString & name, SegOffAddr addr);
|
||||
ilFunction funcIter(Function *to_find);
|
||||
ilFunction findByEntry(uint32_t entry);
|
||||
ilFunction createFunction(FunctionType *f, const QString & name);
|
||||
bool valid(ilFunction iter);
|
||||
|
||||
int getSymIdxByAdd(uint32_t adr);
|
||||
int getSymIdxByAddr(uint32_t adr);
|
||||
bool validSymIdx(size_t idx);
|
||||
size_t symbolSize(size_t idx);
|
||||
hlType symbolType(size_t idx);
|
||||
const QString & symbolName(size_t idx);
|
||||
const SYM & getSymByIdx(size_t idx) const;
|
||||
|
||||
LoaderMetadata &getLoaderMetadata() { assert(m_metadata_available); return m_loader_data; }
|
||||
void setLoaderMetadata(LoaderMetadata d) { m_loader_data = d; m_metadata_available=true;}
|
||||
static Project * get();
|
||||
PROG * binary() {return &prog;}
|
||||
SourceMachine *machine();
|
||||
|
||||
const FunctionListType &functions() const { return pProcList; }
|
||||
FunctionListType &functions() { return pProcList; }
|
||||
|
||||
bool addCommand(Command *cmd);
|
||||
bool addCommand(PtrFunction f, Command *cmd); // Add function level command
|
||||
bool hasCommands(const PtrFunction &f);
|
||||
CommandStream *functionCommands(const PtrFunction &f);
|
||||
void dumpAllErrors();
|
||||
void setLoader(DosLoader *ins);
|
||||
void processCommands(int count=1);
|
||||
void processFunctionCommands(const PtrFunction & func, int count);
|
||||
public slots:
|
||||
void onCommandStreamFinished(bool state);
|
||||
signals:
|
||||
void newFunctionCreated(PtrFunction);
|
||||
void functionUpdate(const PtrFunction &);
|
||||
void loaderSelected();
|
||||
void commandListChanged();
|
||||
protected:
|
||||
void initialize();
|
||||
void writeGlobSymTable();
|
||||
|
||||
protected:
|
||||
static Project * s_instance;
|
||||
QString m_fname;
|
||||
QString m_project_name;
|
||||
QString m_output_path;
|
||||
CommandContext m_command_ctx;
|
||||
|
||||
};
|
||||
//extern Project g_proj;
|
||||
|
||||
@ -3,22 +3,21 @@
|
||||
* (C) Cristina Cifuentes, Mike van Emmerik
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
#include "machine_x86.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
#include "machine_x86.h"
|
||||
|
||||
/* STATE TABLE */
|
||||
struct STATE
|
||||
{
|
||||
uint32_t IP; /* Offset into Image */
|
||||
int16_t r[INDEX_BX_SI]; /* Register values */
|
||||
uint32_t IP; /* Offset into Image */
|
||||
uint16_t r[INDEX_BX_SI]; /* Value of segs and AX */
|
||||
bool f[INDEX_BX_SI]; /* True if r[.] has a value */
|
||||
struct
|
||||
{ /* For case stmt indexed reg */
|
||||
uint8_t regi; /* Last conditional jump */
|
||||
int16_t immed; /* Contents of the previous register */
|
||||
} JCond;
|
||||
{ /* For case stmt indexed reg */
|
||||
uint8_t regi; /* Last conditional jump */
|
||||
int16_t immed; /* Contents of the previous register */
|
||||
} JCond;
|
||||
void setState(uint16_t reg, int16_t value);
|
||||
void checkStartup();
|
||||
bool isKnown(eReg v) {return f[v];}
|
||||
|
||||
@ -9,11 +9,7 @@
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
class QTextStream;
|
||||
|
||||
struct Expr;
|
||||
struct AstIdent;
|
||||
struct TypeContainer;
|
||||
@ -22,10 +18,10 @@ struct TypeContainer;
|
||||
/* * * * * * * * * * * * * * * * * */
|
||||
struct SymbolCommon
|
||||
{
|
||||
QString name; /* New name for this variable/symbol/argument */
|
||||
int size; /* Size/maximum size */
|
||||
QString name; /* New name for this variable/symbol/argument */
|
||||
int size; /* Size/maximum size */
|
||||
hlType type; /* probable type */
|
||||
eDuVal duVal; /* DEF, USE, VAL */
|
||||
eDuVal duVal; /* DEF, USE, VAL */
|
||||
SymbolCommon() : size(0),type(TYPE_UNKNOWN)
|
||||
{}
|
||||
};
|
||||
@ -43,14 +39,13 @@ struct SYM : public SymbolCommon
|
||||
struct STKSYM : public SymbolCommon
|
||||
{
|
||||
typedef int16_t tLabel;
|
||||
Expr * actual=0; /* Expression tree of actual parameter */
|
||||
AstIdent * regs=0; /* For register arguments only */
|
||||
Expr * actual=0; /* Expression tree of actual parameter */
|
||||
AstIdent * regs=0; /* For register arguments only */
|
||||
tLabel label=0; /* Immediate off from BP (+:args, -:params) */
|
||||
uint8_t regOff=0; /* Offset is a register (e.g. SI, DI) */
|
||||
bool hasMacro=false; /* This type needs a macro */
|
||||
QString macro; /* Macro name */
|
||||
bool invalid=false; /* Boolean: invalid entry in formal arg list*/
|
||||
int arrayMembers=1; // for local variables if >1 marks this stack symbol as an array
|
||||
bool hasMacro=false; /* This type needs a macro */
|
||||
QString macro; /* Macro name */
|
||||
bool invalid=false; /* Boolean: invalid entry in formal arg list*/
|
||||
void setArgName(int i)
|
||||
{
|
||||
char buf[32];
|
||||
@ -86,7 +81,7 @@ public:
|
||||
void updateSymType(uint32_t symbol, const TypeContainer &tc);
|
||||
SYM *updateGlobSym(uint32_t operand, int size, uint16_t duFlag, bool &inserted_new);
|
||||
};
|
||||
class Function;
|
||||
struct Function;
|
||||
struct SYMTABLE
|
||||
{
|
||||
std::string pSymName; /* Ptr to symbolic name or comment */
|
||||
@ -106,9 +101,9 @@ struct SYMTABLE
|
||||
enum tableType /* The table types */
|
||||
{
|
||||
Label=0, /* The label table */
|
||||
Comment, /* The comment table */
|
||||
NUM_TABLE_TYPES /* Number of entries: must be last */
|
||||
Comment /* The comment table */
|
||||
};
|
||||
constexpr int NUM_TABLE_TYPES = int(Comment)+1; /* Number of entries: must be last */
|
||||
|
||||
void createSymTables(void);
|
||||
void destroySymTables(void);
|
||||
|
||||
@ -105,8 +105,6 @@ struct TypeContainer
|
||||
return 4;
|
||||
case TYPE_FLOAT:
|
||||
return 4;
|
||||
case TYPE_PTR:
|
||||
return 2;
|
||||
default:
|
||||
return ~0;
|
||||
}
|
||||
|
||||
BIN
sigs/dccb3l.sig
BIN
sigs/dccb3l.sig
Binary file not shown.
BIN
sigs/dccb3s.SIG
BIN
sigs/dccb3s.SIG
Binary file not shown.
@ -1,6 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint32_t LinearAddress;
|
||||
#define INVALID_ADDR Address(~0U)
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -28,7 +28,7 @@ BB *BB::Create(const rCODE &r,eBBKind _nodeType, Function *parent)
|
||||
{
|
||||
BB* pnewBB;
|
||||
pnewBB = new BB;
|
||||
pnewBB->nodeType = _nodeType; /* Initialise */
|
||||
pnewBB->nodeType = _nodeType; /* Initialise */
|
||||
pnewBB->immedDom = NO_DOM;
|
||||
pnewBB->loopHead = pnewBB->caseHead = pnewBB->caseTail =
|
||||
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);
|
||||
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++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int follow; /* ifFollow */
|
||||
BB * succ, *latch; /* Successor and latching node */
|
||||
ICODE * picode; /* Pointer to HLI_JCOND instruction */
|
||||
QString l; /* Pointer to HLI_JCOND expression */
|
||||
bool emptyThen, /* THEN clause is empty */
|
||||
repCond; /* Repeat condition for while() */
|
||||
int follow; /* ifFollow */
|
||||
BB * succ, *latch; /* Successor and latching node */
|
||||
ICODE * picode; /* Pointer to HLI_JCOND instruction */
|
||||
QString l; /* Pointer to HLI_JCOND expression */
|
||||
bool emptyThen, /* THEN clause is empty */
|
||||
repCond; /* Repeat condition for while() */
|
||||
|
||||
/* Check if this basic block should be analysed */
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
if (this != latch) /* loop is over several bbs */
|
||||
if (this != latch) /* loop is over several bbs */
|
||||
{
|
||||
if (loopType == eNodeHeaderType::WHILE_TYPE)
|
||||
{
|
||||
@ -251,7 +251,7 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
|
||||
succ = edges[0].BBptr;
|
||||
if (succ->traversed != DFS_ALPHA)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -293,20 +293,20 @@ void BB::writeCode (int indLevel, Function * pProc , int *numLoc,int _latchNode,
|
||||
succ = pProc->m_dfsLast[loopFollow];
|
||||
if (succ->traversed != DFS_ALPHA)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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++;
|
||||
indLevel++;
|
||||
emptyThen = false;
|
||||
|
||||
if (ifFollow != MAX) /* there is a follow */
|
||||
if (ifFollow != MAX) /* there is a follow */
|
||||
{
|
||||
/* process the THEN part */
|
||||
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));
|
||||
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);
|
||||
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 */
|
||||
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",
|
||||
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)
|
||||
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);
|
||||
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 */
|
||||
{
|
||||
succ = edges[0].BBptr; /* fall-through edge */
|
||||
succ = edges[0].BBptr; /* fall-through edge */
|
||||
assert(succ->size()>0);
|
||||
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.
|
||||
* Args: pBB: pointer to the current basic block.
|
||||
* Icode: pointer to the array of icodes for current procedure.
|
||||
* lev: indentation level - used for formatting. */
|
||||
* Icode: pointer to the array of icodes for current procedure.
|
||||
* lev: indentation level - used for formatting. */
|
||||
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
|
||||
|
||||
@ -1,131 +1,13 @@
|
||||
set(dcc_LIB_SOURCES
|
||||
CallConvention.cpp
|
||||
ast.cpp
|
||||
backend.cpp
|
||||
bundle.cpp
|
||||
chklib.cpp
|
||||
comwrite.cpp
|
||||
control.cpp
|
||||
dataflow.cpp
|
||||
disassem.cpp
|
||||
DccFrontend.cpp
|
||||
error.cpp
|
||||
fixwild.cpp
|
||||
graph.cpp
|
||||
hlicode.cpp
|
||||
hltype.cpp
|
||||
machine_x86.cpp
|
||||
icode.cpp
|
||||
RegisterNode
|
||||
idioms.cpp
|
||||
idioms/idiom1.cpp
|
||||
idioms/arith_idioms.cpp
|
||||
idioms/call_idioms.cpp
|
||||
idioms/epilogue_idioms.cpp
|
||||
idioms/mov_idioms.cpp
|
||||
idioms/neg_idioms.cpp
|
||||
idioms/shift_idioms.cpp
|
||||
idioms/xor_idioms.cpp
|
||||
locident.cpp
|
||||
liveness_set.cpp
|
||||
parser.h
|
||||
parser.cpp
|
||||
procs.cpp
|
||||
project.cpp
|
||||
Procedure.cpp
|
||||
proplong.cpp
|
||||
reducible.cpp
|
||||
scanner.cpp
|
||||
symtab.cpp
|
||||
udm.cpp
|
||||
BasicBlock.cpp
|
||||
dcc_interface.cpp
|
||||
SET(dcc_test_SOURCES
|
||||
tests/comwrite.cpp
|
||||
tests/project.cpp
|
||||
tests/loader.cpp
|
||||
|
||||
MemoryChunk
|
||||
MemorySegment
|
||||
MemorySegmentCoordinator
|
||||
|
||||
Command.cpp
|
||||
Command.h
|
||||
Loaders.cpp
|
||||
Loaders.h
|
||||
FollowControlFlow.cpp
|
||||
FollowControlFlow.h
|
||||
|
||||
AutomatedPlanner
|
||||
)
|
||||
set(dcc_UI_SOURCES
|
||||
ui/DccMainWindow.ui
|
||||
ui/DccMainWindow.h
|
||||
ui/DccMainWindow.cpp
|
||||
ui/FunctionViewWidget.ui
|
||||
ui/FunctionViewWidget.h
|
||||
ui/FunctionViewWidget.cpp
|
||||
ui/FunctionListDockWidget.ui
|
||||
ui/FunctionListDockWidget.cpp
|
||||
ui/FunctionListDockWidget.h
|
||||
ui/RenderTags.cpp
|
||||
ui/RenderTags.h
|
||||
ui/CommandQueueView.cpp
|
||||
ui/CommandQueueView.h
|
||||
ui/CommandQueueView.ui
|
||||
)
|
||||
set(dcc_HEADERS
|
||||
../include/ast.h
|
||||
../include/bundle.h
|
||||
../include/BinaryImage.h
|
||||
../include/DccFrontend.h
|
||||
../include/Enums.h
|
||||
../include/dcc.h
|
||||
../include/disassem.h
|
||||
../include/dosdcc.h
|
||||
../include/error.h
|
||||
../include/graph.h
|
||||
../include/hlicode.h
|
||||
../include/machine_x86.h
|
||||
../include/icode.h
|
||||
../include/idioms/idiom.h
|
||||
../include/idioms/idiom1.h
|
||||
../include/idioms/arith_idioms.h
|
||||
../include/idioms/call_idioms.h
|
||||
../include/idioms/epilogue_idioms.h
|
||||
../include/idioms/mov_idioms.h
|
||||
../include/idioms/neg_idioms.h
|
||||
../include/idioms/shift_idioms.h
|
||||
../include/idioms/xor_idioms.h
|
||||
../include/locident.h
|
||||
../include/CallConvention.h
|
||||
../include/project.h
|
||||
../include/scanner.h
|
||||
../include/state.h
|
||||
../include/symtab.h
|
||||
../include/types.h
|
||||
../include/Procedure.h
|
||||
../include/StackFrame.h
|
||||
../include/BasicBlock.h
|
||||
../include/dcc_interface.h
|
||||
)
|
||||
include_directories(${GMOCK_INCLUDE_DIRS} ${GMOCK_ROOT}/gtest/include)
|
||||
add_executable(tester ${dcc_test_SOURCES})
|
||||
ADD_DEPENDENCIES(tester dcc_lib)
|
||||
|
||||
SOURCE_GROUP(Headers FILES ${dcc_HEADERS})
|
||||
|
||||
set(dcc_SOURCES
|
||||
dcc.cpp
|
||||
)
|
||||
|
||||
SOURCE_GROUP(Source FILES ${dcc_SOURCES} ${dcc_LIB_SOURCES})
|
||||
|
||||
ADD_LIBRARY(dcc_lib STATIC ${dcc_LIB_SOURCES} ${dcc_HEADERS})
|
||||
qt5_use_modules(dcc_lib Core)
|
||||
|
||||
ADD_EXECUTABLE(dcc_original ${dcc_SOURCES} ${dcc_UI_SOURCES})
|
||||
ADD_DEPENDENCIES(dcc_original dcc_lib)
|
||||
TARGET_LINK_LIBRARIES(dcc_original dcc_lib dcc_hash disasm_s)
|
||||
qt5_use_modules(dcc_original Core Widgets)
|
||||
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD 11)
|
||||
SET_PROPERTY(TARGET dcc_original PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
||||
|
||||
if(dcc_build_tests)
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
endif()
|
||||
target_link_libraries(tester dcc_lib disasm_s
|
||||
${GMOCK_BOTH_LIBRARIES} ${REQ_LLVM_LIBRARIES})
|
||||
add_test(dcc-tests tester)
|
||||
|
||||
@ -1,89 +1,9 @@
|
||||
#include "CallConvention.h"
|
||||
|
||||
#include "Procedure.h"
|
||||
|
||||
#include <QtCore/QTextStream>
|
||||
#include <ostream>
|
||||
#include <cassert>
|
||||
static void calculateReturnLocations(Function *func) {
|
||||
switch(func->getReturnType()) {
|
||||
case TYPE_LONG_SIGN:
|
||||
case TYPE_LONG_UNSIGN:
|
||||
func->getFunctionType()->setReturnLocation(LONGID_TYPE(rDX,rAX));
|
||||
break;
|
||||
case TYPE_WORD_SIGN:
|
||||
case TYPE_WORD_UNSIGN:
|
||||
func->getFunctionType()->setReturnLocation(rAX);
|
||||
break;
|
||||
case TYPE_BYTE_SIGN:
|
||||
case TYPE_BYTE_UNSIGN:
|
||||
func->getFunctionType()->setReturnLocation(rAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void calculateArgLocations_allOnStack(Function *func) {
|
||||
FunctionType *type = func->type;
|
||||
int stack_offset=2;
|
||||
if(func->args.size() == type->ContainedTys.size())
|
||||
return;
|
||||
func->args.resize(type->ContainedTys.size());
|
||||
func->args.numArgs=0;
|
||||
for(Type & argtype : type->ContainedTys) {
|
||||
STKSYM &arg(func->args[func->args.numArgs]);
|
||||
arg.label= stack_offset;
|
||||
arg.size = TypeContainer::typeSize(argtype.dcc_type);
|
||||
arg.type = argtype.dcc_type;
|
||||
arg.setArgName(func->args.numArgs);
|
||||
stack_offset+=arg.size;
|
||||
func->args.m_maxOff=stack_offset;
|
||||
func->args.numArgs++;
|
||||
}
|
||||
func->cbParam = stack_offset;
|
||||
}
|
||||
#include "CallConvention.h"
|
||||
#include <QtCore/QTextStream>
|
||||
|
||||
static void rebuildArguments_FromStackLayout(Function *func) {
|
||||
|
||||
STKFRAME &stk(func->args);
|
||||
std::map<int,const STKSYM *> arg_locations;
|
||||
FunctionType *f;
|
||||
|
||||
for(const STKSYM & s: stk) {
|
||||
if(s.label>0) {
|
||||
arg_locations[s.label] = &s;
|
||||
}
|
||||
}
|
||||
|
||||
if(arg_locations.empty())
|
||||
return;
|
||||
|
||||
std::vector<Type> argtypes;
|
||||
auto stack_loc_iter = arg_locations.begin();
|
||||
for(int i=stack_loc_iter->first; i<=arg_locations.rbegin()->first; ) {
|
||||
int till_next_loc=stack_loc_iter->first-i;
|
||||
if(till_next_loc==0) {
|
||||
int entry_size=stack_loc_iter->second->size;
|
||||
argtypes.push_back({stack_loc_iter->second->type});
|
||||
i+=entry_size;
|
||||
++stack_loc_iter;
|
||||
} else {
|
||||
if(till_next_loc>=4) {
|
||||
argtypes.push_back({TYPE_LONG_SIGN});
|
||||
i+=4;
|
||||
} else if(till_next_loc>=2) {
|
||||
argtypes.push_back({TYPE_WORD_SIGN});
|
||||
i+=2;
|
||||
} else {
|
||||
argtypes.push_back({TYPE_BYTE_SIGN});
|
||||
i+=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
f = FunctionType::get({func->type->getReturnType()},argtypes,func->type->isVarArg());
|
||||
f->retVal = func->type->retVal;
|
||||
delete func->type;
|
||||
func->type = f;
|
||||
}
|
||||
CConv *CConv::create(CC_Type v)
|
||||
CConv *CConv::create(Type v)
|
||||
{
|
||||
static C_CallingConvention *c_call = nullptr;
|
||||
static Pascal_CallingConvention *p_call = nullptr;
|
||||
@ -95,9 +15,9 @@ CConv *CConv::create(CC_Type v)
|
||||
if(nullptr==u_call)
|
||||
u_call = new Unknown_CallingConvention;
|
||||
switch(v) {
|
||||
case UNKNOWN: return u_call;
|
||||
case C: return c_call;
|
||||
case PASCAL: return p_call;
|
||||
case eUnknown: return u_call;
|
||||
case eCdecl: return c_call;
|
||||
case ePascal: return p_call;
|
||||
}
|
||||
assert(false);
|
||||
return nullptr;
|
||||
@ -107,31 +27,11 @@ void C_CallingConvention::writeComments(QTextStream & ostr)
|
||||
{
|
||||
ostr << " * C calling convention.\n";
|
||||
}
|
||||
|
||||
void C_CallingConvention::calculateStackLayout(Function *func)
|
||||
{
|
||||
calculateReturnLocations(func);
|
||||
rebuildArguments_FromStackLayout(func);
|
||||
calculateArgLocations_allOnStack(func);
|
||||
}
|
||||
void Pascal_CallingConvention::writeComments(QTextStream & ostr)
|
||||
{
|
||||
ostr << " * Pascal calling convention.\n";
|
||||
}
|
||||
void Pascal_CallingConvention::calculateStackLayout(Function *func)
|
||||
{
|
||||
calculateReturnLocations(func);
|
||||
//TODO: pascal args are passed in reverse order ?
|
||||
rebuildArguments_FromStackLayout(func);
|
||||
calculateArgLocations_allOnStack(func);
|
||||
}
|
||||
void Unknown_CallingConvention::writeComments(QTextStream & ostr)
|
||||
{
|
||||
ostr << " * Unknown calling convention.\n";
|
||||
}
|
||||
void Unknown_CallingConvention::calculateStackLayout(Function *func)
|
||||
{
|
||||
calculateReturnLocations(func);
|
||||
rebuildArguments_FromStackLayout(func);
|
||||
calculateArgLocations_allOnStack(func);
|
||||
}
|
||||
|
||||
138
src/Command.cpp
138
src/Command.cpp
@ -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();
|
||||
}
|
||||
@ -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
|
||||
@ -1,19 +1,60 @@
|
||||
#include "DccFrontend.h"
|
||||
|
||||
#include "Loaders.h"
|
||||
#include "dcc.h"
|
||||
#include "msvc_fixes.h"
|
||||
#include "project.h"
|
||||
#include "disassem.h"
|
||||
#include "CallGraph.h"
|
||||
#include "Command.h"
|
||||
#include "chklib.h"
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QDebug>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
class Loader
|
||||
{
|
||||
bool loadIntoProject(IProject *);
|
||||
};
|
||||
|
||||
struct PSP { /* PSP structure */
|
||||
uint16_t int20h; /* interrupt 20h */
|
||||
uint16_t eof; /* segment, end of allocation block */
|
||||
uint8_t res1; /* reserved */
|
||||
uint8_t dosDisp[5]; /* far call to DOS function dispatcher */
|
||||
uint8_t int22h[4]; /* vector for terminate routine */
|
||||
uint8_t int23h[4]; /* vector for ctrl+break routine */
|
||||
uint8_t int24h[4]; /* vector for error routine */
|
||||
uint8_t res2[22]; /* reserved */
|
||||
uint16_t segEnv; /* segment address of environment block */
|
||||
uint8_t res3[34]; /* reserved */
|
||||
uint8_t int21h[6]; /* opcode for int21h and far return */
|
||||
uint8_t res4[6]; /* reserved */
|
||||
uint8_t fcb1[16]; /* default file control block 1 */
|
||||
uint8_t fcb2[16]; /* default file control block 2 */
|
||||
uint8_t res5[4]; /* reserved */
|
||||
uint8_t cmdTail[0x80]; /* command tail and disk transfer area */
|
||||
};
|
||||
|
||||
static struct MZHeader { /* EXE file header */
|
||||
uint8_t sigLo; /* .EXE signature: 0x4D 0x5A */
|
||||
uint8_t sigHi;
|
||||
uint16_t lastPageSize; /* Size of the last page */
|
||||
uint16_t numPages; /* Number of pages in the file */
|
||||
uint16_t numReloc; /* Number of relocation items */
|
||||
uint16_t numParaHeader; /* # of paragraphs in the header */
|
||||
uint16_t minAlloc; /* Minimum number of paragraphs */
|
||||
uint16_t maxAlloc; /* Maximum number of paragraphs */
|
||||
uint16_t initSS; /* Segment displacement of stack */
|
||||
uint16_t initSP; /* Contents of SP at entry */
|
||||
uint16_t checkSum; /* Complemented checksum */
|
||||
uint16_t initIP; /* Contents of IP at entry */
|
||||
uint16_t initCS; /* Segment displacement of code */
|
||||
uint16_t relocTabOffset; /* Relocation table offset */
|
||||
uint16_t overlayNum; /* Overlay number */
|
||||
} header;
|
||||
|
||||
#define EXE_RELOCATION 0x10 /* EXE images rellocated to above PSP */
|
||||
|
||||
//static void LoadImage(char *filename);
|
||||
static void displayMemMap(void);
|
||||
/****************************************************************************
|
||||
@ -21,19 +62,19 @@ static void displayMemMap(void);
|
||||
***************************************************************************/
|
||||
void PROG::displayLoadInfo(void)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
printf("File type is %s\n", (fCOM)?"COM":"EXE");
|
||||
// if (not fCOM) {
|
||||
// printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
|
||||
// printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
|
||||
// printf("File size / 512 = %04X pages\n", LH(&header.numPages));
|
||||
// printf("# relocation items = %04X\n", LH(&header.numReloc));
|
||||
// printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
|
||||
// printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
|
||||
// printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
|
||||
// }
|
||||
printf("Load image size = %08lX\n", cbImage); // - sizeof(PSP)
|
||||
if (not fCOM) {
|
||||
printf("Signature = %02X%02X\n", header.sigLo, header.sigHi);
|
||||
printf("File size %% 512 = %04X\n", LH(&header.lastPageSize));
|
||||
printf("File size / 512 = %04X pages\n", LH(&header.numPages));
|
||||
printf("# relocation items = %04X\n", LH(&header.numReloc));
|
||||
printf("Offset to load image = %04X paras\n", LH(&header.numParaHeader));
|
||||
printf("Minimum allocation = %04X paras\n", LH(&header.minAlloc));
|
||||
printf("Maximum allocation = %04X paras\n", LH(&header.maxAlloc));
|
||||
}
|
||||
printf("Load image size = %08lX\n", cbImage - sizeof(PSP));
|
||||
printf("Initial SS:SP = %04X:%04X\n", initSS, initSP);
|
||||
printf("Initial CS:IP = %04X:%04X\n", initCS, initIP);
|
||||
|
||||
@ -55,7 +96,7 @@ static void fill(int ip, char *bf)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
static uint8_t type[4] = {'.', 'd', 'c', 'x'};
|
||||
uint8_t i;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 16; i++, ip++)
|
||||
{
|
||||
@ -73,7 +114,7 @@ static void displayMemMap(void)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
char c, b1[33], b2[33], b3[33];
|
||||
char c, b1[33], b2[33], b3[33];
|
||||
uint8_t i;
|
||||
int ip = 0;
|
||||
|
||||
@ -84,10 +125,10 @@ static void displayMemMap(void)
|
||||
printf("%06X %s\n", ip, b1);
|
||||
ip += 16;
|
||||
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)
|
||||
{
|
||||
fill(ip, b2); /* Skip until next two are not same */
|
||||
fill(ip, b2); /* Skip until next two are not same */
|
||||
fill(ip+16, 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 */
|
||||
Disassembler ds(1);
|
||||
for(PtrFunction &f : Project::get()->pProcList)
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f->markImpure();
|
||||
f.markImpure();
|
||||
if (option.asm1)
|
||||
{
|
||||
ds.disassem(f);
|
||||
ds.disassem(&f);
|
||||
}
|
||||
}
|
||||
if (option.Interact)
|
||||
{
|
||||
interactDis(Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
interactDis(&Project::get()->pProcList.front(), 0); /* Interactive disassembler */
|
||||
}
|
||||
|
||||
/* Converts jump target addresses to icode offsets */
|
||||
for(PtrFunction &f : Project::get()->pProcList)
|
||||
for(Function &f : Project::get()->pProcList)
|
||||
{
|
||||
f->bindIcodeOff();
|
||||
f.bindIcodeOff();
|
||||
}
|
||||
/* Print memory bitmap */
|
||||
if (option.Map)
|
||||
displayMemMap();
|
||||
return(true); // we no longer own proj !
|
||||
}
|
||||
struct DosLoader {
|
||||
protected:
|
||||
void prepareImage(PROG &prog,size_t sz,QFile &fp) {
|
||||
/* Allocate a block of memory for the program. */
|
||||
prog.cbImage = sz + sizeof(PSP);
|
||||
prog.Imagez = new uint8_t [prog.cbImage];
|
||||
prog.Imagez[0] = 0xCD; /* Fill in PSP int 20h location */
|
||||
prog.Imagez[1] = 0x20; /* for termination checking */
|
||||
/* Read in the image past where a PSP would go */
|
||||
if (sz != fp.read((char *)prog.Imagez + sizeof(PSP),sz))
|
||||
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||
}
|
||||
};
|
||||
struct ComLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
fp.seek(0);
|
||||
char sig[2];
|
||||
if(2==fp.read(sig,2)) {
|
||||
return not (sig[0] == 0x4D and sig[1] == 0x5A);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
fp.seek(0);
|
||||
/* COM file
|
||||
* In this case the load module size is just the file length
|
||||
*/
|
||||
auto cb = fp.size();
|
||||
|
||||
/* COM programs start off with an ORG 100H (to leave room for a PSP)
|
||||
* This is also the implied start address so if we load the image
|
||||
* at offset 100H addresses should all line up properly again.
|
||||
*/
|
||||
prog.initCS = 0;
|
||||
prog.initIP = 0x100;
|
||||
prog.initSS = 0;
|
||||
prog.initSP = 0xFFFE;
|
||||
prog.cReloc = 0;
|
||||
|
||||
prepareImage(prog, cb, fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#if 0
|
||||
struct RomLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
fp.seek(0xFFF0);
|
||||
uint8_t sig[1];
|
||||
if(fp.read((char *)sig,1) == 1)
|
||||
{
|
||||
return (sig[0] == 0xEA);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
printf("Loading ROM...\n");
|
||||
fp.seek(0);
|
||||
/* ROM file
|
||||
* In this case the load module size is just the file length
|
||||
*/
|
||||
auto cb = fp.size();
|
||||
|
||||
fp.seek(cb - 0x10);
|
||||
uint8_t buf[5];
|
||||
printf("Going to get CS/IP...\n");
|
||||
if(fp.read((char *)buf, 5) != 5)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fp.seek(0);
|
||||
|
||||
/* ROM File, Hard to say where it is suppose to start, so try to trust the
|
||||
*/
|
||||
prog.initIP = (buf[2] << 8) | buf[1];
|
||||
//prog.initCS = 0;
|
||||
prog.initCS = (buf[4] << 8) | buf[3];
|
||||
|
||||
prog.initSS = 0;
|
||||
prog.initSP = 0xFFFE;
|
||||
|
||||
prog.cReloc = 0;
|
||||
|
||||
prepareImage(prog, cb, fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepareImage(PROG &prog, size_t sz, QFile &fp)
|
||||
{
|
||||
int32_t start = 0x100000 - sz;
|
||||
/* Allocate a block of memory for the program. */
|
||||
prog.cbImage = 1 * 1024 * 1024; /* Allocate the whole 1MB memory */
|
||||
//prog.cbImage = 64 * 1024; /* Allocate the whole 1MB memory */
|
||||
prog.Imagez = new uint8_t [prog.cbImage];
|
||||
|
||||
if (fp.read((char *)prog.Imagez + start, sz) != sz)
|
||||
//if (fp.read((char *)prog.Imagez, sz) != sz)
|
||||
{
|
||||
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
struct RomLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
fp.seek(0xFFF0);
|
||||
uint8_t sig[1];
|
||||
if(fp.read((char *)sig,1) == 1)
|
||||
{
|
||||
return (sig[0] == 0xEA);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
fp.seek(0);
|
||||
/* COM file
|
||||
* In this case the load module size is just the file length
|
||||
*/
|
||||
auto cb = fp.size();
|
||||
|
||||
/* COM programs start off with an ORG 100H (to leave room for a PSP)
|
||||
* This is also the implied start address so if we load the image
|
||||
* at offset 100H addresses should all line up properly again.
|
||||
*/
|
||||
prog.initCS = 0;
|
||||
prog.initIP = 0x000;
|
||||
prog.initSS = 0;
|
||||
prog.initSP = 0xFFFE;
|
||||
prog.cReloc = 0;
|
||||
|
||||
prepareImage(prog, cb, fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void prepareImage(PROG &prog, size_t sz, QFile &fp)
|
||||
{
|
||||
/* Allocate a block of memory for the program. */
|
||||
prog.cbImage = sz;
|
||||
prog.Imagez = new uint8_t[prog.cbImage];
|
||||
|
||||
if (sz != fp.read((char *)prog.Imagez, sz))
|
||||
fatalError(CANNOT_READ, fp.fileName().toLocal8Bit().data());
|
||||
}
|
||||
};
|
||||
#endif
|
||||
struct ExeLoader : public DosLoader {
|
||||
bool canLoad(QFile &fp) {
|
||||
if(fp.size()<sizeof(header))
|
||||
return false;
|
||||
MZHeader tmp_header;
|
||||
fp.seek(0);
|
||||
fp.read((char *)&tmp_header, sizeof(header));
|
||||
if(not (tmp_header.sigLo == 0x4D and tmp_header.sigHi == 0x5A))
|
||||
return false;
|
||||
|
||||
/* This is a typical DOS kludge! */
|
||||
if (LH(&header.relocTabOffset) == 0x40)
|
||||
{
|
||||
qDebug() << "Don't understand new EXE format";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool load(PROG &prog,QFile &fp) {
|
||||
/* Read rest of header */
|
||||
fp.seek(0);
|
||||
if (fp.read((char *)&header, sizeof(header)) != sizeof(header))
|
||||
return false;
|
||||
|
||||
/* Calculate the load module size.
|
||||
* This is the number of pages in the file
|
||||
* less the length of the header and reloc table
|
||||
* less the number of bytes unused on last page
|
||||
*/
|
||||
uint32_t cb = (uint32_t)LH(&header.numPages) * 512 - (uint32_t)LH(&header.numParaHeader) * 16;
|
||||
if (header.lastPageSize)
|
||||
{
|
||||
cb -= 512 - LH(&header.lastPageSize);
|
||||
}
|
||||
|
||||
/* We quietly ignore minAlloc and maxAlloc since for our
|
||||
* purposes it doesn't really matter where in real memory
|
||||
* the program would end up. EXE programs can't really rely on
|
||||
* their load location so setting the PSP segment to 0 is fine.
|
||||
* Certainly programs that prod around in DOS or BIOS are going
|
||||
* to have to load DS from a constant so it'll be pretty
|
||||
* obvious.
|
||||
*/
|
||||
prog.initCS = (int16_t)LH(&header.initCS) + EXE_RELOCATION;
|
||||
prog.initIP = (int16_t)LH(&header.initIP);
|
||||
prog.initSS = (int16_t)LH(&header.initSS) + EXE_RELOCATION;
|
||||
prog.initSP = (int16_t)LH(&header.initSP);
|
||||
prog.cReloc = (int16_t)LH(&header.numReloc);
|
||||
|
||||
/* Allocate the relocation table */
|
||||
if (prog.cReloc)
|
||||
{
|
||||
prog.relocTable.resize(prog.cReloc);
|
||||
fp.seek(LH(&header.relocTabOffset));
|
||||
|
||||
/* Read in seg:offset pairs and convert to Image ptrs */
|
||||
uint8_t buf[4];
|
||||
for (int i = 0; i < prog.cReloc; i++)
|
||||
{
|
||||
fp.read((char *)buf,4);
|
||||
prog.relocTable[i] = LH(buf) + (((int)LH(buf+2) + EXE_RELOCATION)<<4);
|
||||
}
|
||||
}
|
||||
/* Seek to start of image */
|
||||
uint32_t start_of_image= LH(&header.numParaHeader) * 16;
|
||||
fp.seek(start_of_image);
|
||||
/* Allocate a block of memory for the program. */
|
||||
prepareImage(prog,cb,fp);
|
||||
|
||||
/* Set up memory map */
|
||||
cb = (prog.cbImage + 3) / 4;
|
||||
prog.map = (uint8_t *)malloc(cb);
|
||||
memset(prog.map, BM_UNKNOWN, (size_t)cb);
|
||||
|
||||
/* Relocate segment constants */
|
||||
for(uint32_t v : prog.relocTable) {
|
||||
uint8_t *p = &prog.Imagez[v];
|
||||
uint16_t w = (uint16_t)LH(p) + EXE_RELOCATION;
|
||||
*p++ = (uint8_t)(w & 0x00FF);
|
||||
*p = (uint8_t)((w & 0xFF00) >> 8);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
/*****************************************************************************
|
||||
* LoadImage
|
||||
****************************************************************************/
|
||||
|
||||
bool Project::load()
|
||||
{
|
||||
// addTask(loaderSelection,PreCond(BinaryImage))
|
||||
// addTask(applyLoader,PreCond(Loader))
|
||||
const char *fname = binary_path().toLocal8Bit().data();
|
||||
QFile finfo(binary_path());
|
||||
/* Open the input file */
|
||||
if(not finfo.open(QFile::ReadOnly)) {
|
||||
fatalError(CANNOT_OPEN, fname);
|
||||
}
|
||||
/* Read in first 2 bytes to check EXE signature */
|
||||
if (finfo.size()<=2)
|
||||
{
|
||||
fatalError(CANNOT_READ, fname);
|
||||
}
|
||||
RomLoader rom_loader;
|
||||
ComLoader com_loader;
|
||||
ExeLoader exe_loader;
|
||||
if(rom_loader.canLoad(finfo)) {
|
||||
/* We have no relacation and code should be on 64K only,
|
||||
* So let's consider it as a COM file
|
||||
*/
|
||||
prog.fCOM = true;
|
||||
return rom_loader.load(prog,finfo);
|
||||
}
|
||||
if(exe_loader.canLoad(finfo)) {
|
||||
prog.fCOM = false;
|
||||
return exe_loader.load(prog,finfo);
|
||||
}
|
||||
if(com_loader.canLoad(finfo)) {
|
||||
prog.fCOM = true;
|
||||
return com_loader.load(prog,finfo);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
uint32_t SynthLab;
|
||||
/* Parses the program, builds the call graph, and returns the list of
|
||||
* procedures found */
|
||||
void DccFrontend::parse(Project &proj)
|
||||
{
|
||||
PROG &prog(proj.prog);
|
||||
STATE state;
|
||||
|
||||
/* Set initial state */
|
||||
proj.addCommand(new MachineStateInitialization);
|
||||
proj.addCommand(new FindMain);
|
||||
}
|
||||
state.setState(rES, 0); /* PSP segment */
|
||||
state.setState(rDS, 0);
|
||||
state.setState(rCS, prog.initCS);
|
||||
state.setState(rSS, prog.initSS);
|
||||
state.setState(rSP, prog.initSP);
|
||||
state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
||||
SynthLab = SYNTHESIZED_MIN;
|
||||
|
||||
bool MachineStateInitialization::execute(CommandContext *ctx)
|
||||
{
|
||||
assert(ctx && ctx->m_project);
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
proj.m_entry_state.setState(rES, 0); /* PSP segment */
|
||||
proj.m_entry_state.setState(rDS, 0);
|
||||
proj.m_entry_state.setState(rCS, prog.initCS);
|
||||
proj.m_entry_state.setState(rSS, prog.initSS);
|
||||
proj.m_entry_state.setState(rSP, prog.initSP);
|
||||
proj.m_entry_state.IP = ((uint32_t)prog.initCS << 4) + prog.initIP;
|
||||
proj.SynthLab = SYNTHESIZED_MIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindMain::execute(CommandContext *ctx) {
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
|
||||
PtrFunction start_func = proj.findByName("start");
|
||||
if(ctx->m_project->m_entry_state.IP==0) {
|
||||
ctx->recordFailure(this,"Cannot search for main func when no entry point was found");
|
||||
return false;
|
||||
}
|
||||
/* Check for special settings of initial state, based on idioms of the startup code */
|
||||
if(checkStartup(ctx->m_project->m_entry_state)) {
|
||||
start_func->markDoNotDecompile(); // we have main, do not decompile the start proc
|
||||
//TODO: main arguments and return values should depend on detected compiler/library
|
||||
FunctionType *main_type = FunctionType::get(Type{TYPE_WORD_SIGN},{ Type{TYPE_WORD_SIGN},Type{TYPE_PTR} },false);
|
||||
main_type->setCallingConvention(CConv::C);
|
||||
proj.addCommand(new CreateFunction("main",SegOffAddr {prog.segMain,prog.offMain},main_type));
|
||||
|
||||
proj.addCommand(new LoadPatternLibrary());
|
||||
} else {
|
||||
start_func->state = proj.m_entry_state; // just in case we fail to find main, initialize 'state' for start func
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QString CreateFunction::instanceDescription() const {
|
||||
return QString("%1 \"%2\" @ 0x%3").arg(name()).arg(m_name).arg(m_addr.addr,0,16,QChar('0'));
|
||||
}
|
||||
|
||||
bool CreateFunction::execute(CommandContext *ctx) {
|
||||
Project &proj(*ctx->m_project);
|
||||
const PROG &prog(proj.prog);
|
||||
|
||||
PtrFunction func = proj.createFunction(m_type,m_name,m_addr);
|
||||
if(m_name=="main") {
|
||||
/* Check for special settings of initial state, based on idioms of the
|
||||
startup code */
|
||||
state.checkStartup();
|
||||
ilFunction start_proc;
|
||||
/* Make a struct for the initial procedure */
|
||||
if (prog.offMain != -1)
|
||||
{
|
||||
start_proc = proj.createFunction(0,"main");
|
||||
start_proc->retVal.loc = REG_FRAME;
|
||||
start_proc->retVal.type = TYPE_WORD_SIGN;
|
||||
start_proc->retVal.id.regi = rAX;
|
||||
/* We know where main() is. Start the flow of control from there */
|
||||
start_proc->procEntry = prog.offMain;
|
||||
/* In medium and large models, the segment of main may (will?) not be
|
||||
the same as the initial CS segment (of the startup code) */
|
||||
proj.m_entry_state.setState(rCS, prog.segMain);
|
||||
proj.m_entry_state.IP = prog.offMain;
|
||||
func->state = proj.m_entry_state;
|
||||
the same as the initial CS segment (of the startup code) */
|
||||
state.setState(rCS, prog.segMain);
|
||||
state.IP = prog.offMain;
|
||||
}
|
||||
if(m_name=="start") {
|
||||
proj.addCommand(new MachineStateInitialization);
|
||||
proj.addCommand(new FindMain);
|
||||
else
|
||||
{
|
||||
start_proc = proj.createFunction(0,"start");
|
||||
/* Create initial procedure at program start address */
|
||||
start_proc->procEntry = (uint32_t)state.IP;
|
||||
}
|
||||
|
||||
// proj.addCommand(new ProcessFunction);
|
||||
//proj.addCommand(new FollowControl());
|
||||
/* The state info is for the first procedure */
|
||||
start_proc->state = state;
|
||||
|
||||
/* Set up call graph initial node */
|
||||
proj.callGraph = new CALL_GRAPH;
|
||||
proj.callGraph->proc = start_proc;
|
||||
|
||||
/* This proc needs to be called to set things up for LibCheck(), which
|
||||
checks a proc to see if it is a know C (etc) library */
|
||||
prog.bSigs = SetupLibCheck();
|
||||
//BUG: proj and g_proj are 'live' at this point !
|
||||
|
||||
/* Recursively build entire procedure list */
|
||||
//proj.callGraph->proc->FollowCtrl(proj.callGraph, &proj.m_entry_state);
|
||||
return true;
|
||||
start_proc->FollowCtrl(proj.callGraph, &state);
|
||||
|
||||
/* This proc needs to be called to clean things up from SetupLibCheck() */
|
||||
CleanupLibCheck();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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
|
||||
177
src/Loaders.cpp
177
src/Loaders.cpp
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
@ -1,5 +0,0 @@
|
||||
#include "MemorySegment.h"
|
||||
|
||||
MemorySegment::MemorySegment(LinearAddress base, LinearAddress start, LinearAddress fin) : MemoryChunk(start,fin) {
|
||||
m_base = base;
|
||||
}
|
||||
@ -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; }
|
||||
};
|
||||
|
||||
@ -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));
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
@ -3,9 +3,6 @@
|
||||
#include "msvc_fixes.h"
|
||||
#include "project.h"
|
||||
#include "scanner.h"
|
||||
#include "ui/StructuredTextTarget.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
//FunctionType *Function::getFunctionType() const
|
||||
//{
|
||||
@ -38,100 +35,6 @@ void JumpTable::pruneEntries(uint16_t cs)
|
||||
}
|
||||
|
||||
|
||||
void Function::callingConv(CConv::CC_Type v) {
|
||||
type->setCallingConvention(v);
|
||||
getFunctionType()->m_call_conv->calculateStackLayout(this);
|
||||
}
|
||||
static QString sizeToPtrName(int size)
|
||||
{
|
||||
switch(size)
|
||||
{
|
||||
case 1:
|
||||
return "BYTE ptr" ;
|
||||
case 2:
|
||||
return "WORD ptr";
|
||||
case 4:
|
||||
return "DWORD ptr";
|
||||
}
|
||||
return "UNKOWN ptr";
|
||||
}
|
||||
static void toStructuredText(STKFRAME &stk,IStructuredTextTarget *out, int level) {
|
||||
int curlevel = 0;
|
||||
int maxlevel = stk.m_maxOff - stk.m_minOff;
|
||||
|
||||
for(STKSYM & p : stk)
|
||||
{
|
||||
if (curlevel > p.label)
|
||||
{
|
||||
qWarning() << "error, var collapse!!!";
|
||||
curlevel = p.label;
|
||||
}
|
||||
else if (curlevel < p.label)
|
||||
{
|
||||
out->addSpace(4);
|
||||
out->prtt(QString("gap len = %1").arg(p.label - curlevel,0,16));
|
||||
curlevel = p.label;
|
||||
out->addEOL();
|
||||
}
|
||||
out->addSpace(4);
|
||||
out->addTaggedString(XT_Symbol,p.name,&p);
|
||||
out->prtt("equ");
|
||||
out->addSpace();
|
||||
out->prtt(sizeToPtrName(p.size));
|
||||
out->addSpace();
|
||||
if (p.arrayMembers>1)
|
||||
{
|
||||
out->addTaggedString(XT_Number,QString::number(p.arrayMembers,16));
|
||||
out->prtt("dup (?)");
|
||||
out->addSpace();
|
||||
}
|
||||
out->TAGbegin(XT_Number, NULL);
|
||||
out->prtt(QString("%1h").arg(p.label,0,16));
|
||||
out->TAGend(XT_Number);
|
||||
out->addEOL();
|
||||
|
||||
curlevel += p.size * p.arrayMembers;
|
||||
}
|
||||
|
||||
if (curlevel < maxlevel)
|
||||
{
|
||||
out->prtt(QString(" gap len = %1h").arg(maxlevel - curlevel,0,16));
|
||||
}
|
||||
}
|
||||
extern void toStructuredText(LLInst *insn,IStructuredTextTarget *out, int level);
|
||||
|
||||
static void toStructuredText(ICODE &stk,IStructuredTextTarget *out, int level) {
|
||||
if(level==0) {
|
||||
toStructuredText(stk.ll(),out,level);
|
||||
}
|
||||
}
|
||||
|
||||
void Function::toStructuredText(IStructuredTextTarget *out, int level)
|
||||
{
|
||||
|
||||
out->TAGbegin(XT_Function, this);
|
||||
out->addTaggedString(XT_FuncName,name);
|
||||
out->prtt(" proc");
|
||||
out->addEOL();
|
||||
::toStructuredText(args,out,level);
|
||||
out->addEOL();
|
||||
for(ICODE &ic : Icode) {
|
||||
::toStructuredText(ic,out,level);
|
||||
}
|
||||
|
||||
out->addTaggedString(XT_FuncName,name);
|
||||
out->addSpace();
|
||||
out->prtt("endp");
|
||||
out->addEOL();
|
||||
out->TAGend(XT_Function);
|
||||
}
|
||||
|
||||
void FunctionType::setCallingConvention(CConv::CC_Type cc)
|
||||
{
|
||||
m_call_conv=CConv::create(cc);
|
||||
assert(m_call_conv);
|
||||
}
|
||||
void Function::switchState(DecompilationStep s)
|
||||
{
|
||||
nStep = s;
|
||||
void Function::callingConv(CConv::Type v) {
|
||||
m_call_conv=CConv::create(v);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ QString RegisterNode::walkCondExpr(Function *pProc, int *numLoc) const
|
||||
QString o;
|
||||
assert(&pProc->localId==m_syms);
|
||||
ID *id = &pProc->localId.id_arr[regiIdx];
|
||||
if (id->name[0] == '\0') /* no name */
|
||||
if (id->name[0] == '\0') /* no name */
|
||||
{
|
||||
id->setLocalName(++(*numLoc));
|
||||
codeOut += QString("%1 %2; ").arg(TypeContainer::typeName(id->type)).arg(id->name);
|
||||
|
||||
561
src/ast.cpp
561
src/ast.cpp
@ -13,6 +13,7 @@
|
||||
#include "project.h"
|
||||
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <boost/range.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/range/algorithm.hpp>
|
||||
@ -29,12 +30,15 @@ using namespace boost::adaptors;
|
||||
|
||||
extern int strSize (const uint8_t *, char);
|
||||
extern char *cChar(uint8_t c);
|
||||
|
||||
namespace
|
||||
{
|
||||
// Conditional operator symbols in C. Index by condOp enumeration type
|
||||
static const char * const condOpSym[] = { " <= ", " < ", " == ", " != ", " > ", " >= ",
|
||||
" & ", " | ", " ^ ", " ~ ",
|
||||
" + ", " - ", " * ", " / ",
|
||||
" >> ", " << ", " % ", " && ", " || " };
|
||||
constexpr const char * condOpSym[] = { " <= ", " < ", " == ", " != ", " > ", " >= ",
|
||||
" & ", " | ", " ^ ", " ~ ",
|
||||
" + ", " - ", " * ", " / ",
|
||||
" >> ", " << ", " % ", " && ", " || " };
|
||||
/* Size of hl types */
|
||||
constexpr const int hlSize[] = {2, 1, 1, 2, 2, 4, 4, 4, 2, 2, 1, 4, 4};
|
||||
|
||||
/* Local expression stack */
|
||||
//typedef struct _EXP_STK {
|
||||
@ -43,13 +47,13 @@ static const char * const condOpSym[] = { " <= ", " < ", " == ", " != ", " > ",
|
||||
//} EXP_STK; - for local expression stack
|
||||
|
||||
/* Returns the integer i in C hexadecimal format */
|
||||
static const char *hexStr (uint16_t i)
|
||||
const char *hexStr (uint16_t i)
|
||||
{
|
||||
static char buf[10];
|
||||
sprintf (buf, "%s%x", (i > 9) ? "0x" : "", i);
|
||||
return (buf);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Sets the du record for registers according to the du flag */
|
||||
void ICODE::setRegDU (eReg regi, operDu du_in)
|
||||
@ -62,19 +66,19 @@ void ICODE::setRegDU (eReg regi, operDu du_in)
|
||||
}
|
||||
switch (du_in)
|
||||
{
|
||||
case eDEF:
|
||||
du.def.addReg(regi);
|
||||
du1.addDef(regi);
|
||||
break;
|
||||
case eUSE:
|
||||
du.use.addReg(regi);
|
||||
break;
|
||||
case USE_DEF:
|
||||
du.addDefinedAndUsed(regi);
|
||||
du1.addDef(regi);
|
||||
break;
|
||||
case NONE: /* do nothing */
|
||||
break;
|
||||
case eDEF:
|
||||
du.def.addReg(regi);
|
||||
du1.addDef(regi);
|
||||
break;
|
||||
case eUSE:
|
||||
du.use.addReg(regi);
|
||||
break;
|
||||
case USE_DEF:
|
||||
du.addDefinedAndUsed(regi);
|
||||
du1.addDef(regi);
|
||||
break;
|
||||
case NONE: /* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,24 +88,24 @@ void ICODE::copyDU(const ICODE &duIcode, operDu _du, operDu duDu)
|
||||
{
|
||||
switch (_du)
|
||||
{
|
||||
case eDEF:
|
||||
if (duDu == eDEF)
|
||||
du.def=duIcode.du.def;
|
||||
else
|
||||
du.def=duIcode.du.use;
|
||||
break;
|
||||
case eUSE:
|
||||
if (duDu == eDEF)
|
||||
du.use = duIcode.du.def;
|
||||
else
|
||||
du.use = duIcode.du.use;
|
||||
break;
|
||||
case USE_DEF:
|
||||
du = duIcode.du;
|
||||
break;
|
||||
case NONE:
|
||||
assert(false);
|
||||
break;
|
||||
case eDEF:
|
||||
if (duDu == eDEF)
|
||||
du.def=duIcode.du.def;
|
||||
else
|
||||
du.def=duIcode.du.use;
|
||||
break;
|
||||
case eUSE:
|
||||
if (duDu == eDEF)
|
||||
du.use = duIcode.du.def;
|
||||
else
|
||||
du.use = duIcode.du.use;
|
||||
break;
|
||||
case USE_DEF:
|
||||
du = duIcode.du;
|
||||
break;
|
||||
case NONE:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +118,7 @@ void ICODE::copyDU(const ICODE &duIcode, operDu _du, operDu duDu)
|
||||
|
||||
/* Returns a unary conditional expression node. This procedure should
|
||||
* 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 */
|
||||
@ -124,7 +128,7 @@ GlobalVariable::GlobalVariable(int16_t segValue, int16_t off)
|
||||
valid = true;
|
||||
ident.idType = GLOB_VAR;
|
||||
adr = opAdr(segValue, off);
|
||||
auto i=Project::get()->getSymIdxByAdd(adr);
|
||||
auto i=Project::get()->getSymIdxByAddr(adr);
|
||||
if ( not Project::get()->validSymIdx(i) )
|
||||
{
|
||||
printf ("Error, glob var not found in symtab\n");
|
||||
@ -136,7 +140,7 @@ GlobalVariable::GlobalVariable(int16_t segValue, int16_t off)
|
||||
QString GlobalVariable::walkCondExpr(Function *, int *) const
|
||||
{
|
||||
if(valid)
|
||||
return Project::get()->symtab[globIdx].name;
|
||||
return Project::get()->symbolName(globIdx);
|
||||
return "INVALID GlobalVariable";
|
||||
}
|
||||
|
||||
@ -164,7 +168,7 @@ AstIdent *AstIdent::Loc(int off, LOCAL_ID *localId)
|
||||
AstIdent *AstIdent::Param(int off, const STKFRAME * argSymtab)
|
||||
{
|
||||
AstIdent *newExp;
|
||||
|
||||
|
||||
newExp = new AstIdent();
|
||||
newExp->ident.idType = PARAM;
|
||||
auto iter=argSymtab->findByLabel(off);
|
||||
@ -222,7 +226,7 @@ AstIdent *AstIdent::Long(LOCAL_ID *localId, opLoc sd, iICODE pIcode, hlFirst f,
|
||||
{
|
||||
AstIdent *newExp;
|
||||
/* Check for long constant and save it as a constant expression */
|
||||
if ((sd == SRC) and pIcode->ll()->srcIsImmed()) /* constant */
|
||||
if ((sd == SRC) and pIcode->ll()->testFlags(I)) /* constant */
|
||||
{
|
||||
int value;
|
||||
if (f == HIGH_FIRST)
|
||||
@ -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
|
||||
* TYPE_WORD_SIGN */
|
||||
* TYPE_WORD_SIGN */
|
||||
AstIdent *AstIdent::idID (const ID *retVal, LOCAL_ID *locsym, iICODE ix_)
|
||||
{
|
||||
int idx;
|
||||
AstIdent *newExp=nullptr;
|
||||
switch(retVal->type)
|
||||
{
|
||||
case TYPE_LONG_SIGN:
|
||||
{
|
||||
newExp = new AstIdent();
|
||||
idx = locsym->newLongReg (TYPE_LONG_SIGN, retVal->longId(), ix_);
|
||||
newExp->ident.idType = LONG_VAR;
|
||||
newExp->ident.idNode.longIdx = idx;
|
||||
break;
|
||||
}
|
||||
case TYPE_WORD_SIGN:
|
||||
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),WORD_REG,locsym);
|
||||
break;
|
||||
case TYPE_BYTE_SIGN:
|
||||
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),BYTE_REG,locsym);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"AstIdent::idID unhandled type %d\n",retVal->type);
|
||||
case TYPE_LONG_SIGN:
|
||||
{
|
||||
newExp = new AstIdent();
|
||||
int idx = locsym->newLongReg (TYPE_LONG_SIGN, retVal->longId(), ix_);
|
||||
newExp->ident.idType = LONG_VAR;
|
||||
newExp->ident.idNode.longIdx = idx;
|
||||
break;
|
||||
}
|
||||
case TYPE_WORD_UNSIGN:
|
||||
case TYPE_WORD_SIGN:
|
||||
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),WORD_REG,locsym);
|
||||
break;
|
||||
case TYPE_BYTE_SIGN:
|
||||
newExp = new RegisterNode(locsym->newByteWordReg(retVal->type, retVal->id.regi),BYTE_REG,locsym);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"AstIdent::idID unhandled type %d\n",retVal->type);
|
||||
}
|
||||
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 *newExp;
|
||||
|
||||
|
||||
int idx; /* idx into pIcode->localId table */
|
||||
|
||||
|
||||
const LLOperand &pm(*ll_insn.get(sd));
|
||||
|
||||
|
||||
if ( ((sd == DST) and ll_insn.testFlags(IM_DST)) or
|
||||
((sd == SRC) and ll_insn.testFlags(IM_SRC)) or
|
||||
(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 (rAX, du);
|
||||
}
|
||||
|
||||
|
||||
else if ((sd == DST) and ll_insn.testFlags(IM_TMP_DST))
|
||||
{ /* implicit tmp */
|
||||
newExp = new RegisterNode(LLOperand(rTMP,2), &pProc->localId);
|
||||
duIcode.setRegDU(rTMP, (operDu)eUSE);
|
||||
}
|
||||
|
||||
else if ((sd == SRC) and ll_insn.srcIsImmed()) /* constant */
|
||||
|
||||
else if ((sd == SRC) and ll_insn.testFlags(I)) /* constant */
|
||||
newExp = new Constant(ll_insn.src().getImm2(), 2);
|
||||
else if (pm.regi == rUNDEF) /* global variable */
|
||||
newExp = new GlobalVariable(pm.segValue, pm.off);
|
||||
@ -323,7 +327,7 @@ Expr *AstIdent::id(const LLInst &ll_insn, opLoc sd, Function * pProc, iICODE ix_
|
||||
newExp = new RegisterNode(pm, &pProc->localId);
|
||||
duIcode.setRegDU( pm.regi, du);
|
||||
}
|
||||
|
||||
|
||||
else if (pm.off) /* offset */
|
||||
{ // 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 */
|
||||
@ -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);
|
||||
/**** check long ops, indexed global var *****/
|
||||
}
|
||||
|
||||
else /* (pm->regi >= INDEXBASE and pm->off = 0) => indexed and no off */
|
||||
{
|
||||
if ((pm.seg == rDS) and (pm.regi > INDEX_BP_DI)) /* dereference */
|
||||
{
|
||||
eReg selected;
|
||||
switch (pm.regi) {
|
||||
case INDEX_SI: selected = rSI; break;
|
||||
case INDEX_DI: selected = rDI; break;
|
||||
case INDEX_BP: selected = rBP; break;
|
||||
case INDEX_BX: selected = rBX; break;
|
||||
default:
|
||||
newExp = nullptr;
|
||||
assert(false);
|
||||
case INDEX_SI: selected = rSI; break;
|
||||
case INDEX_DI: selected = rDI; break;
|
||||
case INDEX_BP: selected = rBP; break;
|
||||
case INDEX_BX: selected = rBX; break;
|
||||
default:
|
||||
newExp = nullptr;
|
||||
assert(false);
|
||||
}
|
||||
//NOTICE: was selected, 0
|
||||
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
|
||||
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
|
||||
{
|
||||
const LLOperand &pm((sd == SRC) ? src() : m_dst);
|
||||
|
||||
if ((sd == SRC) and srcIsImmed())
|
||||
return (CONSTANT);
|
||||
|
||||
if ((sd == SRC) and testFlags(I))
|
||||
return CONSTANT;
|
||||
else if (pm.regi == 0)
|
||||
return (GLOB_VAR);
|
||||
return GLOB_VAR;
|
||||
else if ( pm.isReg() )
|
||||
return (REGISTER);
|
||||
else if ((pm.seg == rSS) and (pm.regi == INDEX_BP))
|
||||
return REGISTER;
|
||||
else if ((pm.seg == rSS) and (pm.regi == INDEX_BP)) // TODO: this assumes BP-based function frames !
|
||||
{
|
||||
//TODO: which pm.seg/pm.regi pairs should produce PARAM/LOCAL_VAR ?
|
||||
if (pm.off >= 0)
|
||||
return (PARAM);
|
||||
else
|
||||
return (LOCAL_VAR);
|
||||
return PARAM;
|
||||
return LOCAL_VAR;
|
||||
}
|
||||
else
|
||||
return (OTHER);
|
||||
return OTHER;
|
||||
}
|
||||
|
||||
|
||||
/* Size of hl types */
|
||||
int hlSize[] = {2, 1, 1, 2, 2, 4, 4, 4, 2, 2, 1, 4, 4};
|
||||
|
||||
int Expr::hlTypeSize(Function * pproc) const
|
||||
{
|
||||
if (this == nullptr)
|
||||
return (2); /* for TYPE_UNKNOWN */
|
||||
return 2; /* for TYPE_UNKNOWN */
|
||||
fprintf(stderr,"hlTypeSize queried for Unkown type %d \n",m_type);
|
||||
return 2; // CC: is this correct?
|
||||
return 2; // CC: is this correct?
|
||||
}
|
||||
|
||||
/* Returns the type of the expression */
|
||||
@ -429,22 +429,22 @@ int AstIdent::hlTypeSize(Function *pproc) const
|
||||
{
|
||||
switch (ident.idType)
|
||||
{
|
||||
case GLOB_VAR:
|
||||
assert(false);
|
||||
return 1;
|
||||
case LOCAL_VAR:
|
||||
return (hlSize[pproc->localId.id_arr[ident.idNode.localIdx].type]);
|
||||
case PARAM:
|
||||
return (hlSize[pproc->args[ident.idNode.paramIdx].type]);
|
||||
case STRING:
|
||||
return (2);
|
||||
case LONG_VAR:
|
||||
return (4);
|
||||
case OTHER:
|
||||
return (2);
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
case GLOB_VAR:
|
||||
assert(false);
|
||||
return 1;
|
||||
case LOCAL_VAR:
|
||||
return (hlSize[pproc->localId.id_arr[ident.idNode.localIdx].type]);
|
||||
case PARAM:
|
||||
return (hlSize[pproc->args[ident.idNode.paramIdx].type]);
|
||||
case STRING:
|
||||
return 2;
|
||||
case LONG_VAR:
|
||||
return 4;
|
||||
case OTHER:
|
||||
return 2;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
} /* eos */
|
||||
}
|
||||
hlType BinaryOperator::expType(Function *pproc) const
|
||||
@ -478,24 +478,24 @@ hlType AstIdent::expType(Function *pproc) const
|
||||
{
|
||||
switch (ident.idType)
|
||||
{
|
||||
case UNDEF:
|
||||
case CONSTANT:
|
||||
case FUNCTION:
|
||||
case REGISTER:
|
||||
case GLOB_VAR:
|
||||
case GLOB_VAR_IDX:
|
||||
assert(false);
|
||||
return TYPE_UNKNOWN;
|
||||
case LOCAL_VAR:
|
||||
return (pproc->localId.id_arr[ident.idNode.localIdx].type);
|
||||
case PARAM:
|
||||
return (pproc->args[ident.idNode.paramIdx].type);
|
||||
case STRING:
|
||||
return (TYPE_STR);
|
||||
case LONG_VAR:
|
||||
return (pproc->localId.id_arr[ident.idNode.longIdx].type);
|
||||
default:
|
||||
return (TYPE_UNKNOWN);
|
||||
case UNDEF:
|
||||
case CONSTANT:
|
||||
case FUNCTION:
|
||||
case REGISTER:
|
||||
case GLOB_VAR:
|
||||
case GLOB_VAR_IDX:
|
||||
assert(false);
|
||||
return TYPE_UNKNOWN;
|
||||
case LOCAL_VAR:
|
||||
return (pproc->localId.id_arr[ident.idNode.localIdx].type);
|
||||
case PARAM:
|
||||
return (pproc->args[ident.idNode.paramIdx].type);
|
||||
case STRING:
|
||||
return (TYPE_STR);
|
||||
case LONG_VAR:
|
||||
return (pproc->localId.id_arr[ident.idNode.longIdx].type);
|
||||
default:
|
||||
return (TYPE_UNKNOWN);
|
||||
} /* eos */
|
||||
return (TYPE_UNKNOWN);
|
||||
}
|
||||
@ -508,17 +508,17 @@ hlType AstIdent::expType(Function *pproc) const
|
||||
Expr * HlTypeSupport::performLongRemoval (eReg regi, LOCAL_ID *locId, Expr *tree)
|
||||
{
|
||||
switch (tree->m_type) {
|
||||
case BOOLEAN_OP:
|
||||
case POST_INC: case POST_DEC:
|
||||
case PRE_INC: case PRE_DEC:
|
||||
case NEGATION: case ADDRESSOF:
|
||||
case DEREFERENCE:
|
||||
case IDENTIFIER:
|
||||
return tree->performLongRemoval(regi,locId);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"performLongRemoval attemped on %d\n",tree->m_type);
|
||||
break;
|
||||
case BOOLEAN_OP:
|
||||
case POST_INC: case POST_DEC:
|
||||
case PRE_INC: case PRE_DEC:
|
||||
case NEGATION: case ADDRESSOF:
|
||||
case DEREFERENCE:
|
||||
case IDENTIFIER:
|
||||
return tree->performLongRemoval(regi,locId);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"performLongRemoval attemped on %d\n",tree->m_type);
|
||||
break;
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
@ -529,7 +529,7 @@ static QString getString (int offset)
|
||||
PROG &prog(Project::get()->prog);
|
||||
QString o;
|
||||
int strLen, i;
|
||||
|
||||
|
||||
strLen = strSize (&prog.image()[offset], '\0');
|
||||
o += '"';
|
||||
for (i = 0; i < strLen; i++)
|
||||
@ -540,7 +540,7 @@ static QString getString (int offset)
|
||||
QString BinaryOperator::walkCondExpr(Function * pProc, int* numLoc) const
|
||||
{
|
||||
assert(rhs());
|
||||
|
||||
|
||||
return QString("(%1%2%3)")
|
||||
.arg((m_op!=NOT) ? lhs()->walkCondExpr(pProc, numLoc) : "")
|
||||
.arg(condOpSym[m_op])
|
||||
@ -554,67 +554,71 @@ QString AstIdent::walkCondExpr(Function *pProc, int *numLoc) const
|
||||
STKSYM * psym; /* Pointer to argument in the stack */
|
||||
QString codeContents;
|
||||
QString collectedContents;
|
||||
|
||||
|
||||
QTextStream codeOut(&codeContents);
|
||||
QTextStream o(&collectedContents);
|
||||
|
||||
|
||||
switch (ident.idType)
|
||||
{
|
||||
case LOCAL_VAR:
|
||||
o << pProc->localId.id_arr[ident.idNode.localIdx].name;
|
||||
break;
|
||||
|
||||
case PARAM:
|
||||
psym = &pProc->args[ident.idNode.paramIdx];
|
||||
if (psym->hasMacro)
|
||||
o << psym->macro<<"("<<psym->name<< ")";
|
||||
else
|
||||
o << psym->name;
|
||||
break;
|
||||
case STRING:
|
||||
o << getString (ident.idNode.strIdx);
|
||||
break;
|
||||
|
||||
case LONG_VAR:
|
||||
id = &pProc->localId.id_arr[ident.idNode.longIdx];
|
||||
if (id->name[0] != '\0') /* STK_FRAME & REG w/name*/
|
||||
o << id->name;
|
||||
else if (id->loc == REG_FRAME)
|
||||
{
|
||||
id->setLocalName(++(*numLoc));
|
||||
codeOut <<TypeContainer::typeName(id->type)<< " "<<id->name<<"; ";
|
||||
codeOut <<"/* "<<Machine_X86::regName(id->longId().h()) << ":" <<
|
||||
Machine_X86::regName(id->longId().l()) << " */\n";
|
||||
o << id->name;
|
||||
pProc->localId.propLongId (id->longId().l(),id->longId().h(), id->name);
|
||||
}
|
||||
else /* GLB_FRAME */
|
||||
{
|
||||
if (id->id.longGlb.regi == 0) /* not indexed */
|
||||
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"]";
|
||||
else if (id->id.longGlb.regi == rBX)
|
||||
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"][bx]";
|
||||
}
|
||||
break;
|
||||
case OTHER:
|
||||
off = ident.idNode.other.off;
|
||||
o << Machine_X86::regName(ident.idNode.other.seg)<< "[";
|
||||
o << Machine_X86::regName(ident.idNode.other.regi);
|
||||
if (off < 0)
|
||||
o << "-"<< hexStr (-off);
|
||||
else if (off>0)
|
||||
o << "+"<< hexStr (off);
|
||||
o << "]";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return "";
|
||||
|
||||
|
||||
case LOCAL_VAR:
|
||||
o << pProc->localId.id_arr[ident.idNode.localIdx].name;
|
||||
break;
|
||||
|
||||
case PARAM:
|
||||
psym = &pProc->args[ident.idNode.paramIdx];
|
||||
if (psym->hasMacro)
|
||||
o << psym->macro<<"("<<psym->name<< ")";
|
||||
else
|
||||
o << psym->name;
|
||||
break;
|
||||
case STRING:
|
||||
o << getString (ident.idNode.strIdx);
|
||||
break;
|
||||
|
||||
case LONG_VAR:
|
||||
id = &pProc->localId.id_arr[ident.idNode.longIdx];
|
||||
if (id->name[0] != '\0') /* STK_FRAME & REG w/name*/
|
||||
o << id->name;
|
||||
else if (id->loc == REG_FRAME)
|
||||
{
|
||||
id->setLocalName(++(*numLoc));
|
||||
codeOut <<TypeContainer::typeName(id->type)<< " "<<id->name<<"; ";
|
||||
codeOut <<"/* "<<Machine_X86::regName(id->longId().h()) << ":" <<
|
||||
Machine_X86::regName(id->longId().l()) << " */\n";
|
||||
o << id->name;
|
||||
pProc->localId.propLongId (id->longId().l(),id->longId().h(), id->name);
|
||||
}
|
||||
else /* GLB_FRAME */
|
||||
{
|
||||
if (id->id.longGlb.regi == 0) /* not indexed */
|
||||
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"]";
|
||||
else if (id->id.longGlb.regi == rBX)
|
||||
o << "[" << (id->id.longGlb.seg<<4) + id->id.longGlb.offH <<"][bx]";
|
||||
else {
|
||||
qCritical() << "AstIdent::walkCondExpr unhandled LONG_VAR in GLB_FRAME";
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OTHER:
|
||||
off = ident.idNode.other.off;
|
||||
o << Machine_X86::regName(ident.idNode.other.seg)<< "[";
|
||||
o << Machine_X86::regName(ident.idNode.other.regi);
|
||||
if (off < 0)
|
||||
o << "-"<< hexStr (-off);
|
||||
else if (off>0)
|
||||
o << "+"<< hexStr (off);
|
||||
o << "]";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return "";
|
||||
|
||||
|
||||
} /* eos */
|
||||
cCode.appendDecl(codeContents);
|
||||
return collectedContents;
|
||||
|
||||
|
||||
}
|
||||
QString UnaryOperator::wrapUnary(Function *pProc, int *numLoc,QChar op) const
|
||||
{
|
||||
@ -632,33 +636,33 @@ QString UnaryOperator::walkCondExpr(Function *pProc, int *numLoc) const
|
||||
QString outStr;
|
||||
switch(m_type)
|
||||
{
|
||||
case NEGATION:
|
||||
outStr+=wrapUnary(pProc,numLoc,'!');
|
||||
break;
|
||||
|
||||
case ADDRESSOF:
|
||||
outStr+=wrapUnary(pProc,numLoc,'&');
|
||||
break;
|
||||
|
||||
case DEREFERENCE:
|
||||
outStr+=wrapUnary(pProc,numLoc,'*');
|
||||
break;
|
||||
|
||||
case POST_INC:
|
||||
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "++";
|
||||
break;
|
||||
|
||||
case POST_DEC:
|
||||
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "--";
|
||||
break;
|
||||
|
||||
case PRE_INC:
|
||||
outStr += "++" + unaryExp->walkCondExpr (pProc, numLoc);
|
||||
break;
|
||||
|
||||
case PRE_DEC:
|
||||
outStr += "--" + unaryExp->walkCondExpr (pProc, numLoc);
|
||||
break;
|
||||
case NEGATION:
|
||||
outStr+=wrapUnary(pProc,numLoc,'!');
|
||||
break;
|
||||
|
||||
case ADDRESSOF:
|
||||
outStr+=wrapUnary(pProc,numLoc,'&');
|
||||
break;
|
||||
|
||||
case DEREFERENCE:
|
||||
outStr+=wrapUnary(pProc,numLoc,'*');
|
||||
break;
|
||||
|
||||
case POST_INC:
|
||||
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "++";
|
||||
break;
|
||||
|
||||
case POST_DEC:
|
||||
outStr += unaryExp->walkCondExpr (pProc, numLoc) + "--";
|
||||
break;
|
||||
|
||||
case PRE_INC:
|
||||
outStr += "++" + unaryExp->walkCondExpr (pProc, numLoc);
|
||||
break;
|
||||
|
||||
case PRE_DEC:
|
||||
outStr += "--" + unaryExp->walkCondExpr (pProc, numLoc);
|
||||
break;
|
||||
}
|
||||
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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Changes the boolean conditional operator at the root of this expression */
|
||||
void BinaryOperator::changeBoolOp (condOp newOp)
|
||||
{
|
||||
@ -690,7 +691,7 @@ bool Expr::insertSubTreeReg (AstIdent *&tree, Expr *_expr, eReg regi,const LOCAL
|
||||
* register regi */
|
||||
bool Expr::insertSubTreeReg (Expr *&tree, Expr *_expr, eReg regi,const LOCAL_ID *locsym)
|
||||
{
|
||||
|
||||
|
||||
if (tree == nullptr)
|
||||
return false;
|
||||
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 *temp;
|
||||
|
||||
|
||||
switch (m_type) {
|
||||
case NEGATION:
|
||||
case ADDRESSOF:
|
||||
case DEREFERENCE:
|
||||
temp = unaryExp->insertSubTreeReg( _expr, regi, locsym);
|
||||
if (nullptr!=temp)
|
||||
{
|
||||
unaryExp = temp;
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
default:
|
||||
fprintf(stderr,"insertSubTreeReg attempt on unhandled type %d\n",m_type);
|
||||
case NEGATION:
|
||||
case ADDRESSOF:
|
||||
case DEREFERENCE:
|
||||
temp = unaryExp->insertSubTreeReg( _expr, regi, locsym);
|
||||
if (nullptr!=temp)
|
||||
{
|
||||
unaryExp = temp;
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
default:
|
||||
fprintf(stderr,"insertSubTreeReg attempt on unhandled type %d\n",m_type);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -799,9 +800,8 @@ Expr *BinaryOperator::insertSubTreeLongReg(Expr *_expr, int longIdx)
|
||||
Expr *AstIdent::insertSubTreeLongReg(Expr *_expr, int longIdx)
|
||||
{
|
||||
if (ident.idNode.longIdx == longIdx)
|
||||
{
|
||||
return _expr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -817,67 +817,51 @@ Expr *BinaryOperator::clone() const
|
||||
|
||||
Expr *BinaryOperator::inverse() const
|
||||
{
|
||||
static condOp invCondOp[] = {GREATER, GREATER_EQUAL, NOT_EQUAL, EQUAL,
|
||||
LESS_EQUAL, LESS, DUMMY,DUMMY,DUMMY,DUMMY,
|
||||
DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY,
|
||||
DUMMY, DBL_OR, DBL_AND};
|
||||
constexpr static condOp invCondOp[] = {GREATER, GREATER_EQUAL, NOT_EQUAL, EQUAL,
|
||||
LESS_EQUAL, LESS, DUMMY,DUMMY,DUMMY,DUMMY,
|
||||
DUMMY, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY,
|
||||
DUMMY, DBL_OR, DBL_AND};
|
||||
BinaryOperator *res=reinterpret_cast<BinaryOperator *>(this->clone());
|
||||
switch (m_op)
|
||||
{
|
||||
case LESS_EQUAL: case LESS: case EQUAL:
|
||||
case NOT_EQUAL: case GREATER: case GREATER_EQUAL:
|
||||
res->m_op = invCondOp[m_op];
|
||||
return res;
|
||||
|
||||
case AND: case OR: case XOR: case NOT: case ADD:
|
||||
case SUB: case MUL: case DIV: case SHR: case SHL: case MOD:
|
||||
return UnaryOperator::Create(NEGATION, res);
|
||||
|
||||
case DBL_AND: case DBL_OR:
|
||||
res->m_op = invCondOp[m_op];
|
||||
res->m_lhs=m_lhs->inverse ();
|
||||
res->m_rhs=m_rhs->inverse ();
|
||||
return res;
|
||||
default:
|
||||
fprintf(stderr,"BinaryOperator::inverse attempt on unhandled op %d\n",m_op);
|
||||
case LESS_EQUAL: case LESS: case EQUAL:
|
||||
case NOT_EQUAL: case GREATER: case GREATER_EQUAL:
|
||||
res->m_op = invCondOp[m_op];
|
||||
return res;
|
||||
|
||||
case AND: case OR: case XOR: case NOT: case ADD:
|
||||
case SUB: case MUL: case DIV: case SHR: case SHL: case MOD:
|
||||
return UnaryOperator::Create(NEGATION, res);
|
||||
|
||||
case DBL_AND: case DBL_OR:
|
||||
res->m_op = invCondOp[m_op];
|
||||
res->m_lhs=m_lhs->inverse ();
|
||||
res->m_rhs=m_rhs->inverse ();
|
||||
return res;
|
||||
default:
|
||||
fprintf(stderr,"BinaryOperator::inverse attempt on unhandled op %d\n",m_op);
|
||||
} /* eos */
|
||||
assert(false);
|
||||
return res;
|
||||
|
||||
|
||||
}
|
||||
Expr *AstIdent::performLongRemoval(eReg regi, LOCAL_ID *locId)
|
||||
{
|
||||
eReg otherRegi; /* high or low part of long register */
|
||||
|
||||
if (ident.idType == LONG_VAR)
|
||||
{
|
||||
otherRegi = otherLongRegi (regi, ident.idNode.longIdx, locId);
|
||||
delete this;
|
||||
return new RegisterNode(locId->newByteWordReg(TYPE_WORD_SIGN,otherRegi),WORD_REG,locId);
|
||||
}
|
||||
return this;
|
||||
|
||||
if (ident.idType != LONG_VAR)
|
||||
return this;
|
||||
otherRegi = locId->getPairedRegisterAt(ident.idNode.longIdx,regi);
|
||||
bool long_was_signed = locId->id_arr[ident.idNode.longIdx].isSigned();
|
||||
delete this;
|
||||
return new RegisterNode(locId->newByteWordReg(long_was_signed ? TYPE_WORD_SIGN : TYPE_WORD_UNSIGN,otherRegi),WORD_REG,locId);
|
||||
}
|
||||
eReg AstIdent::otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
|
||||
{
|
||||
ID *id = &locTbl->id_arr[idx];
|
||||
if ((id->loc == REG_FRAME) and ((id->type == TYPE_LONG_SIGN) or
|
||||
(id->type == TYPE_LONG_UNSIGN)))
|
||||
{
|
||||
if (id->longId().h() == regi)
|
||||
return (id->longId().l());
|
||||
else if (id->longId().l() == regi)
|
||||
return (id->longId().h());
|
||||
}
|
||||
return rUNDEF; // Cristina: please check this!
|
||||
}
|
||||
|
||||
|
||||
QString Constant::walkCondExpr(Function *, int *) const
|
||||
{
|
||||
if (kte.kte < 1000)
|
||||
return QString::number(kte.kte);
|
||||
else
|
||||
return "0x" + QString::number(kte.kte,16);
|
||||
return "0x" + QString::number(kte.kte,16);
|
||||
}
|
||||
|
||||
int Constant::hlTypeSize(Function *) const
|
||||
@ -885,11 +869,6 @@ int Constant::hlTypeSize(Function *) const
|
||||
return kte.size;
|
||||
}
|
||||
|
||||
hlType Constant::expType(Function *pproc) const
|
||||
{
|
||||
return TYPE_CONST;
|
||||
}
|
||||
|
||||
QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
|
||||
{
|
||||
return pProc->writeCall(call.proc,*call.args, numLoc);
|
||||
@ -897,10 +876,10 @@ QString FuncNode::walkCondExpr(Function *pProc, int *numLoc) const
|
||||
|
||||
int FuncNode::hlTypeSize(Function *) const
|
||||
{
|
||||
return hlSize[call.proc->getReturnType()];
|
||||
return hlSize[call.proc->retVal.type];
|
||||
}
|
||||
|
||||
hlType FuncNode::expType(Function *) const
|
||||
{
|
||||
return call.proc->getReturnType();
|
||||
return call.proc->retVal.type;
|
||||
}
|
||||
|
||||
@ -30,12 +30,12 @@ using namespace boost;
|
||||
using namespace boost::adaptors;
|
||||
using namespace std;
|
||||
|
||||
bundle cCode; /* Procedure declaration and code */
|
||||
bundle cCode; /* Procedure declaration and code */
|
||||
|
||||
/* Returns a unique index to the next label */
|
||||
int getNextLabel()
|
||||
{
|
||||
static int labelIdx = 1; /* index of the next label */
|
||||
static int labelIdx = 1; /* index of the next label */
|
||||
return (labelIdx++);
|
||||
}
|
||||
|
||||
@ -62,8 +62,8 @@ static void fixupLabels (PPROC pProc)
|
||||
* 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
|
||||
* order of dsfLast numbering. */
|
||||
{ int i; /* index into the dfsLast array */
|
||||
PBB *dfsLast; /* pointer to the dfsLast array */
|
||||
{ int i; /* index into the dfsLast array */
|
||||
PBB *dfsLast; /* pointer to the dfsLast array */
|
||||
|
||||
dfsLast = pProc->dfsLast;
|
||||
for (i = 0; i < pProc->numBBs; i++)
|
||||
@ -82,10 +82,10 @@ char *cChar (uint8_t c)
|
||||
static char res[3];
|
||||
|
||||
switch (c) {
|
||||
case 0x8: /* backspace */
|
||||
case 0x8: /* backspace */
|
||||
sprintf (res, "\\b");
|
||||
break;
|
||||
case 0x9: /* horizontal tab */
|
||||
case 0x9: /* horizontal tab */
|
||||
sprintf (res, "\\t");
|
||||
break;
|
||||
case 0x0A: /* new line */
|
||||
@ -97,7 +97,7 @@ char *cChar (uint8_t c)
|
||||
case 0x0D: /* carriage return */
|
||||
sprintf (res, "\\r");
|
||||
break;
|
||||
default: /* any other character*/
|
||||
default: /* any other character*/
|
||||
sprintf (res, "%c", c);
|
||||
}
|
||||
return (res);
|
||||
@ -106,8 +106,8 @@ char *cChar (uint8_t c)
|
||||
|
||||
/* Prints the variable's name and initial contents on the file.
|
||||
* Note: to get to the value of the variable:
|
||||
* com file: prog.Image[operand]
|
||||
* exe file: prog.Image[operand+0x100] */
|
||||
* com file: prog.Image[operand]
|
||||
* exe file: prog.Image[operand+0x100] */
|
||||
static void printGlobVar (QTextStream &ostr,SYM * psym)
|
||||
{
|
||||
int j;
|
||||
@ -124,7 +124,7 @@ static void printGlobVar (QTextStream &ostr,SYM * psym)
|
||||
break;
|
||||
case 4: if (psym->type == TYPE_PTR) /* pointer */
|
||||
ostr << "uint16_t *\t"<<psym->name<<" = "<<LH(prog.image()+relocOp)<<";\n";
|
||||
else /* char */
|
||||
else /* char */
|
||||
ostr << "char\t"<<psym->name<<"[4] = \""<<
|
||||
prog.image()[relocOp]<<prog.image()[relocOp+1]<<
|
||||
prog.image()[relocOp+2]<<prog.image()[relocOp+3]<<";\n";
|
||||
@ -155,12 +155,12 @@ void Project::writeGlobSymTable()
|
||||
{
|
||||
if (sym.duVal.isUSE_VAL()) /* first used */
|
||||
printGlobVar (ostr,&sym);
|
||||
else { /* first defined */
|
||||
else { /* first defined */
|
||||
switch (sym.size) {
|
||||
case 1: ostr<<"uint8_t\t"; break;
|
||||
case 2: ostr<<"int\t"; break;
|
||||
case 2: ostr<<"int16_t\t"; break;
|
||||
case 4: if (sym.type == TYPE_PTR)
|
||||
ostr<<"int\t*";
|
||||
ostr<<"int32_t\t*";
|
||||
else
|
||||
ostr<<"char\t*";
|
||||
break;
|
||||
@ -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
|
||||
* is created and a goto is also emitted.
|
||||
* 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
|
||||
static void emitFwdGotoLabel (ICODE * pt, int indLevel)
|
||||
{
|
||||
@ -226,8 +226,8 @@ void Function::codeGen (QIODevice &fs)
|
||||
|
||||
/* Write procedure/function header */
|
||||
cCode.init();
|
||||
if (getReturnType() != TYPE_UNKNOWN) /* Function */
|
||||
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(getReturnType())).arg(name);
|
||||
if (flg & PROC_IS_FUNC) /* Function */
|
||||
ostr << QString("\n%1 %2 (").arg(TypeContainer::typeName(retVal.type)).arg(name);
|
||||
else /* Procedure */
|
||||
ostr << "\nvoid "+name+" (";
|
||||
|
||||
@ -279,12 +279,12 @@ void Function::codeGen (QIODevice &fs)
|
||||
fs.write(ostr_contents.toLatin1());
|
||||
|
||||
/* Write procedure's code */
|
||||
if (flg & PROC_ASM) /* generate assembler */
|
||||
if (flg & PROC_ASM) /* generate assembler */
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -325,7 +325,7 @@ void Function::codeGen (QIODevice &fs)
|
||||
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 */
|
||||
if ((pcallGraph->proc->flg & PROC_OUTPUT) or
|
||||
|
||||
1129
src/chklib.cpp
1129
src/chklib.cpp
File diff suppressed because it is too large
Load Diff
51
src/chklib.h
51
src/chklib.h
@ -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
|
||||
@ -14,7 +14,7 @@
|
||||
#include <sstream>
|
||||
#include <QTextStream>
|
||||
using namespace std;
|
||||
#define intSize 40
|
||||
#define intSize 40
|
||||
|
||||
static const char *int21h[] =
|
||||
{
|
||||
@ -131,21 +131,21 @@ static const char *int21h[] =
|
||||
|
||||
|
||||
static const char *intOthers[] = {
|
||||
"Exit", /* 0x20 */
|
||||
"", /* other table */
|
||||
"Terminate handler address", /* 0x22 */
|
||||
"Ctrl-C handler address", /* 0x23 */
|
||||
"Exit", /* 0x20 */
|
||||
"", /* other table */
|
||||
"Terminate handler address", /* 0x22 */
|
||||
"Ctrl-C handler address", /* 0x23 */
|
||||
"Critical-error handler address", /* 0x24 */
|
||||
"Absolute disk read", /* 0x25 */
|
||||
"Absolute disk write", /* 0x26 */
|
||||
"Terminate and stay resident", /* 0x27 */
|
||||
"Reserved", /* 0x28 */
|
||||
"Reserved", /* 0x29 */
|
||||
"Reserved", /* 0x2A */
|
||||
"Reserved", /* 0x2B */
|
||||
"Reserved", /* 0x2C */
|
||||
"Reserved", /* 0x2D */
|
||||
"Reserved" /* 0x2E */
|
||||
"Absolute disk read", /* 0x25 */
|
||||
"Absolute disk write", /* 0x26 */
|
||||
"Terminate and stay resident", /* 0x27 */
|
||||
"Reserved", /* 0x28 */
|
||||
"Reserved", /* 0x29 */
|
||||
"Reserved", /* 0x2A */
|
||||
"Reserved", /* 0x2B */
|
||||
"Reserved", /* 0x2C */
|
||||
"Reserved", /* 0x2D */
|
||||
"Reserved" /* 0x2E */
|
||||
};
|
||||
|
||||
|
||||
@ -200,8 +200,8 @@ void Function::writeProcComments()
|
||||
void Function::writeProcComments(QTextStream &ostr)
|
||||
{
|
||||
int i;
|
||||
ID *id; /* Pointer to register argument identifier */
|
||||
STKSYM * psym; /* Pointer to register argument symbol */
|
||||
ID *id; /* Pointer to register argument identifier */
|
||||
STKSYM * psym; /* Pointer to register argument symbol */
|
||||
|
||||
/* About the parameters */
|
||||
if (this->cbParam)
|
||||
@ -218,7 +218,7 @@ void Function::writeProcComments(QTextStream &ostr)
|
||||
id = &this->localId.id_arr[((RegisterNode *)psym->regs)->regiIdx];
|
||||
ostr << Machine_X86::regName(id->id.regi);
|
||||
}
|
||||
else /* long register */
|
||||
else /* long register */
|
||||
{
|
||||
id = &this->localId.id_arr[psym->regs->ident.idNode.longIdx];
|
||||
ostr << Machine_X86::regName(id->longId().h()) << ":";
|
||||
@ -239,24 +239,21 @@ void Function::writeProcComments(QTextStream &ostr)
|
||||
if (this->flg & PROC_ASM)
|
||||
{
|
||||
ostr << " * Untranslatable routine. Assembler provided.\n";
|
||||
switch (getReturnType()) { // TODO: Functions return value in various regs
|
||||
case TYPE_BYTE_SIGN:
|
||||
case TYPE_BYTE_UNSIGN:
|
||||
ostr << " * Return value in register al.\n";
|
||||
break;
|
||||
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
|
||||
ostr << " * Return value in register ax.\n";
|
||||
break;
|
||||
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
|
||||
ostr << " * Return value in registers dx:ax.\n";
|
||||
break;
|
||||
case TYPE_UNKNOWN:
|
||||
// void return type
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unknown retval type %d",getReturnType());
|
||||
break;
|
||||
} /* eos */
|
||||
if (this->flg & PROC_IS_FUNC)
|
||||
switch (this->retVal.type) { // TODO: Functions return value in various regs
|
||||
case TYPE_BYTE_SIGN: case TYPE_BYTE_UNSIGN:
|
||||
ostr << " * Return value in register al.\n";
|
||||
break;
|
||||
case TYPE_WORD_SIGN: case TYPE_WORD_UNSIGN:
|
||||
ostr << " * Return value in register ax.\n";
|
||||
break;
|
||||
case TYPE_LONG_SIGN: case TYPE_LONG_UNSIGN:
|
||||
ostr << " * Return value in registers dx:ax.\n";
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unknown retval type %d",this->retVal.type);
|
||||
break;
|
||||
} /* eos */
|
||||
}
|
||||
|
||||
/* Calling convention */
|
||||
|
||||
281
src/control.cpp
281
src/control.cpp
@ -7,27 +7,29 @@
|
||||
#include "msvc_fixes.h"
|
||||
|
||||
#include <boost/range/algorithm.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
|
||||
namespace {
|
||||
typedef std::list<int> nodeList; /* dfsLast index to the node */
|
||||
|
||||
#define ancestor(a,b) ((a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum))
|
||||
/* there is a path on the DFST from a to b if the a was first visited in a
|
||||
* dfs, and a was later visited than b when doing the last visit of each
|
||||
* node. */
|
||||
bool inline ancestor(BB *a,BB *b)
|
||||
{
|
||||
return (a->dfsLastNum < b->dfsLastNum) and (a->dfsFirstNum < b->dfsFirstNum);
|
||||
}
|
||||
|
||||
|
||||
/* Checks if the edge (p,s) is a back edge. If node s was visited first
|
||||
/** Checks if the edge (p,s) is a back edge. If node s was visited first
|
||||
* during the dfs traversal (ie. s has a smaller dfsFirst number) or s == p,
|
||||
* then it is a backedge.
|
||||
* Also incrementes the number of backedges entries to the header node. */
|
||||
static bool isBackEdge (BB * p,BB * s)
|
||||
bool isBackEdge (BB * p,BB * s)
|
||||
{
|
||||
if (p->dfsFirstNum >= s->dfsFirstNum)
|
||||
{
|
||||
@ -38,9 +40,9 @@ static bool isBackEdge (BB * p,BB * s)
|
||||
}
|
||||
|
||||
|
||||
/* Finds the common dominator of the current immediate dominator
|
||||
/** Finds the common dominator of the current immediate dominator
|
||||
* currImmDom and its predecessor's immediate dominator predImmDom */
|
||||
static int commonDom (int currImmDom, int predImmDom, Function * pProc)
|
||||
int commonDom (int currImmDom, int predImmDom, Function * pProc)
|
||||
{
|
||||
if (currImmDom == NO_DOM)
|
||||
return (predImmDom);
|
||||
@ -57,67 +59,44 @@ static int commonDom (int currImmDom, int predImmDom, Function * pProc)
|
||||
}
|
||||
return (currImmDom);
|
||||
}
|
||||
|
||||
|
||||
/* Finds the immediate dominator of each node in the graph pProc->cfg.
|
||||
* Adapted version of the dominators algorithm by Hecht and Ullman; finds
|
||||
* immediate dominators only.
|
||||
* Note: graph should be reducible */
|
||||
void Function::findImmedDom ()
|
||||
{
|
||||
BB * currNode;
|
||||
for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
|
||||
{
|
||||
currNode = m_dfsLast[currIdx];
|
||||
if (currNode->flg & INVALID_BB) /* Do not process invalid BBs */
|
||||
continue;
|
||||
for (BB * inedge : currNode->inEdges)
|
||||
{
|
||||
size_t predIdx = inedge->dfsLastNum;
|
||||
if (predIdx < currIdx)
|
||||
currNode->immedDom = commonDom (currNode->immedDom, predIdx, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Inserts the node n to the list l. */
|
||||
static void insertList (nodeList &l, int n)
|
||||
{
|
||||
l.push_back(n);
|
||||
}
|
||||
|
||||
|
||||
/* Returns whether or not the node n (dfsLast numbering of a basic block)
|
||||
* is on the list l. */
|
||||
static bool inList (const nodeList &l, int n)
|
||||
bool inList (const nodeList &l, int n)
|
||||
{
|
||||
return std::find(l.begin(),l.end(),n)!=l.end();
|
||||
}
|
||||
|
||||
|
||||
/* Frees space allocated by the list l. */
|
||||
static void freeList (nodeList &l)
|
||||
{
|
||||
l.clear();
|
||||
}
|
||||
|
||||
|
||||
/* Returns whether the node n belongs to the queue list q. */
|
||||
static bool inInt(BB * n, queue &q)
|
||||
bool inInt(BB * n, queue &q)
|
||||
{
|
||||
return std::find(q.begin(),q.end(),n)!=q.end();
|
||||
}
|
||||
|
||||
|
||||
/** Recursive procedure to find nodes that belong to the interval (ie. nodes
|
||||
* from G1). */
|
||||
void findNodesInInt (queue &intNodes, int level, interval *Ii)
|
||||
{
|
||||
if (level == 1)
|
||||
{
|
||||
for(BB *en : Ii->nodes)
|
||||
{
|
||||
appendQueue(intNodes,en);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(BB *en : Ii->nodes)
|
||||
{
|
||||
findNodesInInt(intNodes,level-1,en->correspInt);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Finds the follow of the endless loop headed at node head (if any).
|
||||
* The follow node is the closest node to the loop. */
|
||||
static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
|
||||
void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
|
||||
{
|
||||
head->loopFollow = MAX;
|
||||
for( int loop_node : loopNodes)
|
||||
{
|
||||
for (TYPEADR_TYPE &typeaddr: pProc->m_dfsLast[loop_node]->edges)
|
||||
for (const TYPEADR_TYPE &typeaddr: pProc->m_dfsLast[loop_node]->edges)
|
||||
{
|
||||
int succ = typeaddr.BBptr->dfsLastNum;
|
||||
if ((not inList(loopNodes, succ)) and (succ < head->loopFollow))
|
||||
@ -130,34 +109,34 @@ static void findEndlessFollow (Function * pProc, nodeList &loopNodes, BB * head)
|
||||
//static void findNodesInLoop(BB * latchNode,BB * head,PPROC pProc,queue *intNodes)
|
||||
/* Flags nodes that belong to the loop determined by (latchNode, head) and
|
||||
* determines the type of loop. */
|
||||
static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &intNodes)
|
||||
void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &intNodes)
|
||||
{
|
||||
int i, headDfsNum, intNodeType;
|
||||
nodeList loopNodes;
|
||||
int immedDom, /* dfsLast index to immediate dominator */
|
||||
int immedDom, /* dfsLast index to immediate dominator */
|
||||
thenDfs, elseDfs; /* dsfLast index for THEN and ELSE nodes */
|
||||
BB * pbb;
|
||||
|
||||
/* Flag nodes in loop headed by head (except header node) */
|
||||
headDfsNum = head->dfsLastNum;
|
||||
head->loopHead = headDfsNum;
|
||||
insertList (loopNodes, headDfsNum);
|
||||
loopNodes.push_back(headDfsNum);
|
||||
for (i = headDfsNum + 1; i < latchNode->dfsLastNum; i++)
|
||||
{
|
||||
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
|
||||
if (pProc->m_dfsLast[i]->flg & INVALID_BB) /* skip invalid BBs */
|
||||
continue;
|
||||
|
||||
immedDom = pProc->m_dfsLast[i]->immedDom;
|
||||
if (inList (loopNodes, immedDom) and inInt(pProc->m_dfsLast[i], intNodes))
|
||||
{
|
||||
insertList (loopNodes, i);
|
||||
loopNodes.push_back(i);
|
||||
if (pProc->m_dfsLast[i]->loopHead == NO_NODE)/*not in other loop*/
|
||||
pProc->m_dfsLast[i]->loopHead = headDfsNum;
|
||||
}
|
||||
}
|
||||
latchNode->loopHead = headDfsNum;
|
||||
if (latchNode != head)
|
||||
insertList (loopNodes, latchNode->dfsLastNum);
|
||||
loopNodes.push_back(latchNode->dfsLastNum);
|
||||
|
||||
/* Determine type of loop and follow node */
|
||||
intNodeType = head->nodeType;
|
||||
@ -192,7 +171,7 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
|
||||
head->loopFollow = latchNode->edges[THEN].BBptr->dfsLastNum;
|
||||
latchNode->back().ll()->setFlags(JX_LOOP);
|
||||
}
|
||||
else /* latch = 1-way */
|
||||
else /* latch = 1-way */
|
||||
if (latchNode->nodeType == LOOP_NODE)
|
||||
{
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
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];
|
||||
}
|
||||
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);
|
||||
}
|
||||
else
|
||||
@ -237,49 +216,95 @@ static void findNodesInLoop(BB * latchNode,BB * head,Function * pProc,queue &int
|
||||
findEndlessFollow (pProc, loopNodes, head);
|
||||
}
|
||||
|
||||
freeList(loopNodes);
|
||||
loopNodes.clear();
|
||||
}
|
||||
|
||||
//static void findNodesInInt (queue **intNodes, int level, interval *Ii)
|
||||
/* Recursive procedure to find nodes that belong to the interval (ie. nodes
|
||||
* from G1). */
|
||||
static void findNodesInInt (queue &intNodes, int level, interval *Ii)
|
||||
/** \returns whether the BB indexed by s is a successor of the BB indexed by \arg h
|
||||
* \note that h is a case node.
|
||||
*/
|
||||
bool successor (int s, int h, Function * pProc)
|
||||
{
|
||||
if (level == 1)
|
||||
BB * header = pProc->m_dfsLast[h];
|
||||
auto iter = std::find_if(header->edges.begin(),
|
||||
header->edges.end(),
|
||||
[s](const TYPEADR_TYPE &te)->bool{ return te.BBptr->dfsLastNum == s;});
|
||||
return iter!=header->edges.end();
|
||||
}
|
||||
|
||||
|
||||
/** Recursive procedure to tag nodes that belong to the case described by
|
||||
* the list l, head and tail (dfsLast index to first and exit node of the
|
||||
* case). */
|
||||
void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
|
||||
{
|
||||
int current; /* index to current node */
|
||||
|
||||
pBB->traversed = DFS_CASE;
|
||||
current = pBB->dfsLastNum;
|
||||
if ((current != tail) and (pBB->nodeType != MULTI_BRANCH) and (inList (l, pBB->immedDom)))
|
||||
{
|
||||
for(BB *en : Ii->nodes)
|
||||
l.push_back(current);
|
||||
pBB->caseHead = head;
|
||||
for(TYPEADR_TYPE &edge : pBB->edges)
|
||||
{
|
||||
appendQueue(intNodes,en);
|
||||
if (edge.BBptr->traversed != DFS_CASE)
|
||||
tagNodesInCase (edge.BBptr, l, head, tail);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
/** Flags all nodes in the list l as having follow node f, and deletes all
|
||||
* nodes from the list. */
|
||||
void flagNodes (nodeList &l, int f, Function * pProc)
|
||||
{
|
||||
for(int idx : l)
|
||||
{
|
||||
for(BB *en : Ii->nodes)
|
||||
pProc->m_dfsLast[idx]->ifFollow = f;
|
||||
}
|
||||
l.clear();
|
||||
}
|
||||
|
||||
|
||||
} // end of anonymouse namespace
|
||||
|
||||
/** Finds the immediate dominator of each node in the graph pProc->cfg.
|
||||
* Adapted version of the dominators algorithm by Hecht and Ullman; finds
|
||||
* immediate dominators only.
|
||||
* Note: graph should be reducible */
|
||||
void Function::findImmedDom ()
|
||||
{
|
||||
BB * currNode;
|
||||
for (size_t currIdx = 0; currIdx < numBBs; currIdx++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
interval *Ii;
|
||||
BB * intHead, /* interval header node */
|
||||
* pred, /* predecessor node */
|
||||
BB * intHead, /* interval header node */
|
||||
* pred, /* predecessor node */
|
||||
* latchNode;/* latching node (in case of loops) */
|
||||
size_t level = 0; /* derived sequence level */
|
||||
interval *initInt; /* initial interval */
|
||||
queue intNodes; /* list of interval nodes */
|
||||
size_t level = 0; /* derived sequence level */
|
||||
interval *initInt; /* initial interval */
|
||||
queue intNodes; /* list of interval nodes */
|
||||
|
||||
/* Structure loops */
|
||||
/* for all derived sequences Gi */
|
||||
for(auto & elem : *derivedG)
|
||||
{
|
||||
level++;
|
||||
Ii = elem.Ii;
|
||||
while (Ii) /* for all intervals Ii of Gi */
|
||||
for (Ii = elem.Ii; Ii!=nullptr; Ii = Ii->next) /* for all intervals Ii of Gi */
|
||||
{
|
||||
latchNode = nullptr;
|
||||
intNodes.clear();
|
||||
@ -321,45 +346,6 @@ void Function::structLoops(derSeq *derivedG)
|
||||
latchNode->flg |= IS_LATCH_NODE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Next interval */
|
||||
Ii = Ii->next;
|
||||
}
|
||||
|
||||
/* Next derived sequence */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Returns whether the BB indexed by s is a successor of the BB indexed by
|
||||
* h. Note that h is a case node. */
|
||||
static bool successor (int s, int h, Function * pProc)
|
||||
{
|
||||
BB * header = pProc->m_dfsLast[h];
|
||||
auto iter = std::find_if(header->edges.begin(),
|
||||
header->edges.end(),
|
||||
[s](const TYPEADR_TYPE &te)->bool{ return te.BBptr->dfsLastNum == s;});
|
||||
return iter!=header->edges.end();
|
||||
}
|
||||
|
||||
|
||||
/* Recursive procedure to tag nodes that belong to the case described by
|
||||
* the list l, head and tail (dfsLast index to first and exit node of the
|
||||
* case). */
|
||||
static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
|
||||
{
|
||||
int current; /* index to current node */
|
||||
|
||||
pBB->traversed = DFS_CASE;
|
||||
current = pBB->dfsLastNum;
|
||||
if ((current != tail) and (pBB->nodeType != MULTI_BRANCH) and (inList (l, pBB->immedDom)))
|
||||
{
|
||||
insertList (l, current);
|
||||
pBB->caseHead = head;
|
||||
for(TYPEADR_TYPE &edge : pBB->edges)
|
||||
{
|
||||
if (edge.BBptr->traversed != DFS_CASE)
|
||||
tagNodesInCase (edge.BBptr, l, head, tail);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -369,7 +355,7 @@ static void tagNodesInCase (BB * pBB, nodeList &l, int head, int tail)
|
||||
* has a case node. */
|
||||
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 */
|
||||
|
||||
/* 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 (exitNode == NO_NODE)
|
||||
{
|
||||
exitNode = j;
|
||||
}
|
||||
else if (m_dfsLast[exitNode]->inEdges.size() < m_dfsLast[j]->inEdges.size())
|
||||
exitNode = j;
|
||||
}
|
||||
@ -398,7 +382,7 @@ void Function::structCases()
|
||||
|
||||
/* Tag nodes that belong to the case by recording the
|
||||
* header field with caseHeader. */
|
||||
insertList (caseNodes, i);
|
||||
caseNodes.push_back(i);
|
||||
m_dfsLast[i]->caseHead = i;
|
||||
for(TYPEADR_TYPE &pb : caseHeader->edges)
|
||||
{
|
||||
@ -411,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 */
|
||||
void Function::structIfs ()
|
||||
{
|
||||
size_t followInEdges; /* Largest # in-edges so far */
|
||||
int curr, /* Index for linear scan of nodes */
|
||||
/*desc,*/ /* Index for descendant */
|
||||
follow; /* Possible follow node */
|
||||
nodeList domDesc, /* List of nodes dominated by curr */
|
||||
unresolved /* List of unresolved if nodes */
|
||||
size_t followInEdges; /* Largest # in-edges so far */
|
||||
int curr, /* Index for linear scan of nodes */
|
||||
/*desc,*/ /* Index for descendant */
|
||||
follow; /* Possible follow node */
|
||||
nodeList domDesc, /* List of nodes dominated by curr */
|
||||
unresolved /* List of unresolved if nodes */
|
||||
;
|
||||
BB * currNode, /* Pointer to current node */
|
||||
* pbb;
|
||||
BB * currNode, /* Pointer to current node */
|
||||
* pbb;
|
||||
|
||||
/* Linear scan of nodes in reverse dfsLast order */
|
||||
for (curr = numBBs - 1; curr >= 0; 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;
|
||||
|
||||
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)
|
||||
{
|
||||
insertList (domDesc, desc);
|
||||
domDesc.push_back(desc);
|
||||
pbb = m_dfsLast[desc];
|
||||
if ((pbb->inEdges.size() - pbb->numBackEdges) >= followInEdges)
|
||||
{
|
||||
@ -474,9 +444,9 @@ void Function::structIfs ()
|
||||
flagNodes (unresolved, follow, this);
|
||||
}
|
||||
else
|
||||
insertList (unresolved, curr);
|
||||
unresolved.push_back(curr);
|
||||
}
|
||||
freeList (domDesc);
|
||||
domDesc.clear();
|
||||
}
|
||||
}
|
||||
bool Function::removeInEdge_Flag_and_ProcessLatch(BB *pbb,BB *a,BB *b)
|
||||
@ -653,8 +623,7 @@ void Function::compoundCond()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Structuring algorithm to find the structures of the graph pProc->cfg */
|
||||
/** Structuring algorithm to find the structures of the graph pProc->cfg */
|
||||
void Function::structure(derSeq *derivedG)
|
||||
{
|
||||
/* Find immediate dominators of the graph */
|
||||
|
||||
358
src/dataflow.cpp
358
src/dataflow.cpp
@ -22,6 +22,9 @@
|
||||
|
||||
using namespace boost;
|
||||
using namespace boost::adaptors;
|
||||
using namespace std;
|
||||
namespace
|
||||
{
|
||||
struct ExpStack
|
||||
{
|
||||
Function *func;
|
||||
@ -49,6 +52,57 @@ struct ExpStack
|
||||
}
|
||||
|
||||
};
|
||||
ExpStack g_exp_stk;
|
||||
/** Returns a string with the source operand of Icode */
|
||||
Expr *srcIdent (const LLInst &ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
|
||||
{
|
||||
const LLOperand * src_op = ll_insn.get(SRC);
|
||||
if (src_op->isImmediate()) /* immediate operand ll_insn.testFlags(I)*/
|
||||
{
|
||||
//if (ll_insn.testFlags(B))
|
||||
return new Constant(src_op->getImm2(), src_op->byteWidth());
|
||||
}
|
||||
// otherwise
|
||||
return AstIdent::id (ll_insn, SRC, pProc, i, duIcode, du);
|
||||
}
|
||||
|
||||
|
||||
/** Returns the destination operand */
|
||||
Expr *dstIdent (const LLInst & ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
|
||||
{
|
||||
Expr *n;
|
||||
n = AstIdent::id (ll_insn, DST, pProc, i, duIcode, du);
|
||||
/** Is it needed? (pIcode->ll()->flg) & NO_SRC_B **/
|
||||
return (n);
|
||||
}
|
||||
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the expression exp given */
|
||||
void forwardSubsLong (int longIdx, Expr *_exp, ICODE &picode, ICODE &ticode, int *numHlIcodes)
|
||||
{
|
||||
bool res;
|
||||
|
||||
if (_exp == nullptr) /* In case expression popped is NULL */
|
||||
return;
|
||||
|
||||
/* Insert on rhs of ticode, if possible */
|
||||
res = Expr::insertSubTreeLongReg (_exp, ticode.hlU()->asgn.m_rhs, longIdx);
|
||||
if (res)
|
||||
{
|
||||
picode.invalidate();
|
||||
(*numHlIcodes)--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to insert it on lhs of ticode*/
|
||||
res = Expr::insertSubTreeLongReg (_exp, ticode.hlU()->asgn.m_lhs, longIdx);
|
||||
if (res)
|
||||
{
|
||||
picode.invalidate();
|
||||
(*numHlIcodes)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
/***************************************************************************
|
||||
* Expression stack functions
|
||||
**************************************************************************/
|
||||
@ -92,8 +146,6 @@ bool ExpStack::empty()
|
||||
return expStk.empty();
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
ExpStack g_exp_stk;
|
||||
|
||||
/* Returns the index of the local variable or parameter at offset off, if it
|
||||
* is in the stack frame provided. */
|
||||
@ -104,28 +156,6 @@ size_t STKFRAME::getLocVar(int off)
|
||||
}
|
||||
|
||||
|
||||
/* Returns a string with the source operand of Icode */
|
||||
static Expr *srcIdent (const LLInst &ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
|
||||
{
|
||||
const LLOperand * src_op = ll_insn.get(SRC);
|
||||
if (src_op->isImmediate()) /* immediate operand ll_insn.testFlags(I)*/
|
||||
{
|
||||
//if (ll_insn.testFlags(B))
|
||||
return new Constant(src_op->getImm2(), src_op->byteWidth());
|
||||
}
|
||||
// otherwise
|
||||
return AstIdent::id (ll_insn, SRC, pProc, i, duIcode, du);
|
||||
}
|
||||
|
||||
|
||||
/* Returns the destination operand */
|
||||
static Expr *dstIdent (const LLInst & ll_insn, Function * pProc, iICODE i, ICODE & duIcode, operDu du)
|
||||
{
|
||||
Expr *n;
|
||||
n = AstIdent::id (ll_insn, DST, pProc, i, duIcode, du);
|
||||
/** Is it needed? (pIcode->ll()->flg) & NO_SRC_B **/
|
||||
return (n);
|
||||
}
|
||||
/* Eliminates all condition codes and generates new hlIcode instructions */
|
||||
void Function::elimCondCodes ()
|
||||
{
|
||||
@ -196,7 +226,7 @@ void Function::elimCondCodes ()
|
||||
notSup = true;
|
||||
std::cout << hex<<defIcode.loc_ip;
|
||||
reportError (JX_NOT_DEF, defIcode.ll()->getOpcode());
|
||||
flg |= PROC_ASM; /* generate asm */
|
||||
flg |= PROC_ASM; /* generate asm */
|
||||
}
|
||||
if (not notSup)
|
||||
{
|
||||
@ -224,7 +254,7 @@ void Function::elimCondCodes ()
|
||||
ICODE &a(*defAt);
|
||||
ICODE &b(*useAt);
|
||||
reportError (NOT_DEF_USE,a.ll()->label,a.ll()->getOpcode(),b.ll()->getOpcode());
|
||||
flg |= PROC_ASM; /* generate asm */
|
||||
flg |= PROC_ASM; /* generate asm */
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -269,7 +299,7 @@ void Function::genLiveKtes ()
|
||||
def.reset();
|
||||
pbb = m_dfsLast[i];
|
||||
if (pbb->flg & INVALID_BB)
|
||||
continue; // skip invalid BBs
|
||||
continue; // skip invalid BBs
|
||||
for(ICODE &insn : *pbb)
|
||||
{
|
||||
if ((insn.type == HIGH_LEVEL_ICODE) and ( insn.valid() ))
|
||||
@ -295,9 +325,9 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
|
||||
Function * pcallee; /* invoked subroutine */
|
||||
//ICODE *ticode /* icode that invokes a subroutine */
|
||||
;
|
||||
LivenessSet prevLiveOut, /* previous live out */
|
||||
prevLiveIn; /* previous live in */
|
||||
bool change; /* is there change in the live sets?*/
|
||||
LivenessSet prevLiveOut, /* previous live out */
|
||||
prevLiveIn; /* previous live in */
|
||||
bool change; /* is there change in the live sets?*/
|
||||
|
||||
/* liveOut for this procedure */
|
||||
liveOut = in_liveOut;
|
||||
@ -322,12 +352,12 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
|
||||
pbb->liveOut = in_liveOut;
|
||||
|
||||
/* Get return expression of function */
|
||||
if (getReturnType()!=TYPE_UNKNOWN)
|
||||
if (flg & PROC_IS_FUNC)
|
||||
{
|
||||
auto picode = pbb->rbegin(); /* icode of function return */
|
||||
if (picode->hl()->opcode == HLI_RET)
|
||||
{
|
||||
picode->hlU()->expr(AstIdent::idID(&type->retVal, &localId, (++pbb->rbegin()).base()));
|
||||
picode->hlU()->expr(AstIdent::idID(&retVal, &localId, (++pbb->rbegin()).base()));
|
||||
picode->du.use = in_liveOut;
|
||||
}
|
||||
}
|
||||
@ -354,7 +384,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
|
||||
}
|
||||
else /* library routine */
|
||||
{
|
||||
if ( (pcallee->getReturnType()!=TYPE_UNKNOWN) and /* returns a value */
|
||||
if ( (pcallee->flg & PROC_IS_FUNC) and /* returns a value */
|
||||
(pcallee->liveOut & pbb->edges[0].BBptr->liveIn).any()
|
||||
)
|
||||
pbb->liveOut = pcallee->liveOut;
|
||||
@ -364,7 +394,7 @@ void Function::liveRegAnalysis (LivenessSet &in_liveOut)
|
||||
|
||||
if ((not (pcallee->flg & PROC_ISLIB)) or ( pbb->liveOut.any() ))
|
||||
{
|
||||
switch (pcallee->getReturnType()) {
|
||||
switch (pcallee->retVal.type) {
|
||||
case TYPE_LONG_SIGN:
|
||||
case TYPE_LONG_UNSIGN:
|
||||
ticode.du1.setDef(rAX).addDef(rDX);
|
||||
@ -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) )
|
||||
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 */
|
||||
if ( liveOut.testRegAndSubregs(regi) )
|
||||
@ -462,7 +492,7 @@ bool BB::FindUseBeforeDef(eReg regi, int defRegIdx, iICODE start_at)
|
||||
* on optimized code. */
|
||||
void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
|
||||
{
|
||||
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->getReturnType()!=TYPE_UNKNOWN)))
|
||||
if (not ((picode.hl()->opcode == HLI_CALL) and (picode.hl()->call.proc->flg & PROC_IS_FUNC)))
|
||||
return;
|
||||
|
||||
BB *tbb = this->edges[0].BBptr;
|
||||
@ -489,7 +519,7 @@ void BB::ProcessUseDefForFunc(eReg regi, int defRegIdx, ICODE &picode)
|
||||
* thus remove it. Also check that this is not a return
|
||||
* from a library function (routines such as printf
|
||||
* 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)
|
||||
{
|
||||
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
|
||||
(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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -563,7 +593,7 @@ void Function::genDU1 ()
|
||||
}
|
||||
|
||||
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the rhs of picode. */
|
||||
void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode, int &numHlIcodes) const
|
||||
void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, ICODE &picode, ICODE &ticode, int &numHlIcodes) const
|
||||
{
|
||||
bool res;
|
||||
UnaryOperator *lhs_unary;
|
||||
@ -579,16 +609,16 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
|
||||
return;
|
||||
|
||||
/* Insert on rhs of ticode, if possible */
|
||||
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.m_rhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
|
||||
res = Expr::insertSubTreeReg (ticode.hlU()->asgn.m_rhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
picode.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to insert it on lhs of ticode*/
|
||||
RegisterNode *op = dynamic_cast<RegisterNode *>(ticode->hlU()->asgn.m_lhs);
|
||||
RegisterNode *op = dynamic_cast<RegisterNode *>(ticode.hlU()->asgn.m_lhs);
|
||||
if(op)
|
||||
{
|
||||
eReg inserted = id_arr[lhs_reg->regiIdx].id.regi;
|
||||
@ -599,45 +629,18 @@ void LOCAL_ID::forwardSubs (Expr *lhs, Expr *rhs, iICODE picode, iICODE ticode,
|
||||
return;
|
||||
}
|
||||
}
|
||||
res = Expr::insertSubTreeReg (ticode->hlU()->asgn.m_lhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
|
||||
res = Expr::insertSubTreeReg (ticode.hlU()->asgn.m_lhs,rhs, id_arr[lhs_reg->regiIdx].id.regi, this);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
picode.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Substitutes the rhs (or lhs if rhs not possible) of ticode for the expression exp given */
|
||||
static void forwardSubsLong (int longIdx, Expr *_exp, iICODE picode, iICODE ticode, int *numHlIcodes)
|
||||
{
|
||||
bool res;
|
||||
|
||||
if (_exp == nullptr) /* In case expression popped is NULL */
|
||||
return;
|
||||
|
||||
/* Insert on rhs of ticode, if possible */
|
||||
res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.m_rhs, longIdx);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
(*numHlIcodes)--;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to insert it on lhs of ticode*/
|
||||
res = Expr::insertSubTreeLongReg (_exp, ticode->hlU()->asgn.m_lhs, longIdx);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
(*numHlIcodes)--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns whether the elements of the expression rhs are all x-clear from
|
||||
* instruction f up to instruction t. */
|
||||
/** 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)
|
||||
{
|
||||
if(nullptr==unaryExp)
|
||||
@ -672,12 +675,14 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
|
||||
Expr *_exp;
|
||||
bool res;
|
||||
int size_of_arg=0;
|
||||
Project &proj(*Project::get());
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
|
||||
/* if (numArgs == 0)
|
||||
return; */
|
||||
assert(pProc==g_exp_stk.func);
|
||||
_exp = g_exp_stk.pop();
|
||||
if (callee->flg & PROC_ISLIB) /* library function */
|
||||
if (callee->isLibrary() ) /* library function */
|
||||
{
|
||||
if (callee->args.numArgs > 0)
|
||||
{
|
||||
@ -692,7 +697,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
|
||||
}
|
||||
else {
|
||||
if(numArgs<callee->args.size()) {
|
||||
if(proj.getLoaderMetadata().compiler_memory_model==eLarge) {
|
||||
if(prog.addressingMode=='l') {
|
||||
if((callee->args[numArgs].type==TYPE_STR) or (callee->args[numArgs].type==TYPE_PTR)) {
|
||||
RegisterNode *rn = dynamic_cast<RegisterNode *>(g_exp_stk.top());
|
||||
AstIdent *idn = dynamic_cast<AstIdent *>(g_exp_stk.top());
|
||||
@ -720,7 +725,7 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* user function */
|
||||
else /* user function */
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), pProc);
|
||||
res = picode->newStkArg (_exp, picode->ll()->getOpcode(), pProc);
|
||||
/* Do not update the size of k if the expression was a segment register
|
||||
* in a near call */
|
||||
if (res == false)
|
||||
@ -745,11 +750,11 @@ int C_CallingConvention::processCArg (Function * callee, Function * pProc, ICODE
|
||||
/** Eliminates extraneous intermediate icode instructions when finding
|
||||
* expressions. Generates new hlIcodes in the form of expression trees.
|
||||
* For HLI_CALL hlIcodes, places the arguments in the argument list. */
|
||||
void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode,bool isLong) const
|
||||
void LOCAL_ID::processTargetIcode(ICODE &picode, int &numHlIcodes, ICODE &ticode,bool isLong) const
|
||||
{
|
||||
bool res;
|
||||
HLTYPE &p_hl(*picode->hlU());
|
||||
HLTYPE &t_hl(*ticode->hlU());
|
||||
HLTYPE &p_hl(*picode.hlU());
|
||||
HLTYPE &t_hl(*ticode.hlU());
|
||||
|
||||
AstIdent *lhs_ident = dynamic_cast<AstIdent *>(p_hl.asgn.lhs());
|
||||
switch (t_hl.opcode)
|
||||
@ -787,14 +792,14 @@ void LOCAL_ID::processTargetIcode(iICODE picode, int &numHlIcodes, iICODE ticode
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
picode.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
break;
|
||||
|
||||
case HLI_CALL: /* register arguments */
|
||||
newRegArg ( picode, ticode);
|
||||
picode->invalidate();
|
||||
picode.invalidate();
|
||||
numHlIcodes--;
|
||||
break;
|
||||
default:
|
||||
@ -835,19 +840,19 @@ void Pascal_CallingConvention::processHLI(Function *func,Expr *_exp, iICODE pico
|
||||
int k;
|
||||
pp = picode->hl()->call.proc;
|
||||
|
||||
cb = pp->cbParam; /* fixed # arguments */
|
||||
cb = pp->cbParam; /* fixed # arguments */
|
||||
k = 0;
|
||||
numArgs = 0;
|
||||
while(k<cb)
|
||||
{
|
||||
_exp = g_exp_stk.pop();
|
||||
if (pp->flg & PROC_ISLIB) /* library function */
|
||||
if (pp->isLibrary() ) /* library function */
|
||||
{
|
||||
if (pp->args.numArgs > 0)
|
||||
_exp = func->adjustActArgType(_exp, pp->args[numArgs].type);
|
||||
res = picode->newStkArg (_exp, (llIcode)picode->ll()->getOpcode(), func);
|
||||
res = picode->newStkArg (_exp, picode->ll()->getOpcode(), func);
|
||||
}
|
||||
else /* user function */
|
||||
else /* user function */
|
||||
{
|
||||
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");
|
||||
}
|
||||
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)
|
||||
k += _exp->hlTypeSize (func);
|
||||
@ -876,31 +882,30 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
{
|
||||
bool res;
|
||||
|
||||
ID *_retVal; // function return value
|
||||
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL
|
||||
//Expr *lhs; // exp ptr for return value of a HLI_CALL
|
||||
iICODE ticode; // Target icode
|
||||
ID *_retVal; // function return value
|
||||
Expr *_exp; // expression pointer - for HLI_POP and HLI_CALL */
|
||||
iICODE ticode; // Target icode */
|
||||
HLTYPE *ti_hl=nullptr;
|
||||
uint8_t regi;
|
||||
numHlIcodes = 0;
|
||||
assert(&fnc->localId==&locals);
|
||||
// register(s) to be forward substituted
|
||||
// register(s) to be forward substituted */
|
||||
auto valid_and_highlevel = instructions | filtered(ICODE::TypeAndValidFilter<HIGH_LEVEL_ICODE>());
|
||||
for (auto picode = valid_and_highlevel.begin(); picode != valid_and_highlevel.end(); picode++)
|
||||
{
|
||||
ICODE &_ic(*picode);
|
||||
HLTYPE &_icHl(*picode->hlU());
|
||||
HLTYPE &_icHl(*_ic.hlU());
|
||||
numHlIcodes++;
|
||||
if (picode->du1.getNumRegsDef() == 1) /* uint8_t/uint16_t regs */
|
||||
if (_ic.du1.getNumRegsDef() == 1) /* uint8_t/uint16_t regs */
|
||||
{
|
||||
/* Check for only one use of this register. If this is
|
||||
* the last definition of the register in this BB, check
|
||||
* that it is not liveOut from this basic block */
|
||||
if (picode->du1.numUses(0)==1)
|
||||
if (_ic.du1.numUses(0)==1)
|
||||
{
|
||||
/* Check that this register is not liveOut, if it
|
||||
* is the last definition of the register */
|
||||
regi = picode->du1.regi[0];
|
||||
regi = _ic.du1.regi[0];
|
||||
|
||||
/* Check if we can forward substitute this register */
|
||||
switch (_icHl.opcode)
|
||||
@ -909,16 +914,16 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
/* Replace rhs of current icode into target
|
||||
* icode expression */
|
||||
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
((ticode->hl()->opcode != HLI_CALL) and
|
||||
(ticode->hl()->opcode != HLI_RET)))
|
||||
continue;
|
||||
|
||||
if (_icHl.asgn.m_rhs->xClear (make_iterator_range(picode.base(),picode->du1.idx[0].uses[0]),
|
||||
if (_icHl.asgn.m_rhs->xClear (make_iterator_range(picode.base(),_ic.du1.idx[0].uses[0]),
|
||||
end(), locals))
|
||||
{
|
||||
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,false);
|
||||
locals.processTargetIcode(_ic, numHlIcodes, *ticode,false);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -927,9 +932,9 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
// pop X
|
||||
// lab1:
|
||||
// call F() <- somehow this is marked as user of POP ?
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
ti_hl = ticode->hlU();
|
||||
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
((ti_hl->opcode != HLI_CALL) and
|
||||
(ti_hl->opcode != HLI_RET)))
|
||||
continue;
|
||||
@ -937,7 +942,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
_exp = g_exp_stk.pop(); /* pop last exp pushed */
|
||||
switch (ticode->hl()->opcode) {
|
||||
case HLI_ASSIGN:
|
||||
locals.forwardSubs(_icHl.expr(), _exp, picode.base(), ticode, numHlIcodes);
|
||||
locals.forwardSubs(_icHl.expr(), _exp, _ic, *ticode, numHlIcodes);
|
||||
break;
|
||||
|
||||
case HLI_JCOND: case HLI_PUSH: case HLI_RET:
|
||||
@ -950,7 +955,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
&locals);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
}
|
||||
@ -960,7 +965,7 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
newRegArg (pProc, picode, ticode);
|
||||
picode->invalidate();
|
||||
numHlIcodes--;
|
||||
break; */
|
||||
break; */
|
||||
default:
|
||||
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;
|
||||
|
||||
case HLI_CALL:
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
ti_hl = ticode->hlU();
|
||||
_retVal = &_icHl.call.proc->type->retVal;
|
||||
_retVal = &_icHl.call.proc->retVal;
|
||||
switch (ti_hl->opcode)
|
||||
{
|
||||
case HLI_ASSIGN:
|
||||
@ -980,28 +985,28 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
if (not res)
|
||||
Expr::insertSubTreeReg (ti_hl->asgn.m_lhs, _exp,_retVal->id.regi, &locals);
|
||||
//TODO: HERE missing: 2 regs
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
break;
|
||||
|
||||
case HLI_PUSH: case HLI_RET:
|
||||
ti_hl->expr( _icHl.call.toAst() );
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
break;
|
||||
|
||||
case HLI_JCOND:
|
||||
_exp = _icHl.call.toAst();
|
||||
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--;
|
||||
}
|
||||
else /* cannot substitute function */
|
||||
else /* cannot substitute function */
|
||||
{
|
||||
auto lhs = AstIdent::idID(_retVal,&locals,picode.base());
|
||||
picode->setAsgn(lhs, _exp);
|
||||
_ic.setAsgn(lhs, _exp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1014,33 +1019,34 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
}
|
||||
}
|
||||
|
||||
else if (picode->du1.getNumRegsDef() == 2) /* long regs */
|
||||
else if (_ic.du1.getNumRegsDef() == 2) /* long regs */
|
||||
{
|
||||
/* Check for only one use of these registers */
|
||||
if ((picode->du1.numUses(0) == 1) and (picode->du1.numUses(1) == 1))
|
||||
if ((_ic.du1.numUses(0) == 1) and (_ic.du1.numUses(1) == 1))
|
||||
{
|
||||
regi = picode->du1.regi[0]; //TODO: verify that regi actually should be assigned this
|
||||
regi = _ic.du1.regi[0]; //TODO: verify that regi actually should be assigned this
|
||||
|
||||
switch (_icHl.opcode)
|
||||
{
|
||||
case HLI_ASSIGN:
|
||||
/* Replace rhs of current icode into target icode expression */
|
||||
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0])
|
||||
/* Replace rhs of current icode into target
|
||||
* icode expression */
|
||||
if (_ic.du1.idx[0].uses[0] == _ic.du1.idx[1].uses[0])
|
||||
{
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
((ticode->hl()->opcode != HLI_CALL) and
|
||||
(ticode->hl()->opcode != HLI_RET)))
|
||||
continue;
|
||||
locals.processTargetIcode(picode.base(), numHlIcodes, ticode,true);
|
||||
locals.processTargetIcode(_ic, numHlIcodes, *ticode,true);
|
||||
}
|
||||
break;
|
||||
|
||||
case HLI_POP:
|
||||
if (picode->du1.idx[0].uses[0] == picode->du1.idx[1].uses[0])
|
||||
if (_ic.du1.idx[0].uses[0] == _ic.du1.idx[1].uses[0])
|
||||
{
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
if ((picode->du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
if ((_ic.du.lastDefRegi.testRegAndSubregs(regi)) and
|
||||
((ticode->hl()->opcode != HLI_CALL) and
|
||||
(ticode->hl()->opcode != HLI_RET)))
|
||||
continue;
|
||||
@ -1048,21 +1054,20 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
_exp = g_exp_stk.pop(); /* pop last exp pushed */
|
||||
switch (ticode->hl()->opcode) {
|
||||
case HLI_ASSIGN:
|
||||
forwardSubsLong (static_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
|
||||
_exp, picode.base(), ticode, &numHlIcodes);
|
||||
forwardSubsLong (dynamic_cast<AstIdent *>(_icHl.expr())->ident.idNode.longIdx,
|
||||
_exp, _ic, *ticode, &numHlIcodes);
|
||||
break;
|
||||
case HLI_JCOND:
|
||||
case HLI_PUSH:
|
||||
case HLI_JCOND: case HLI_PUSH:
|
||||
res = Expr::insertSubTreeLongReg (_exp,
|
||||
ticode->hlU()->exp.v,
|
||||
dynamic_cast<AstIdent *>(_icHl.asgn.lhs())->ident.idNode.longIdx);
|
||||
if (res)
|
||||
{
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
break;
|
||||
case HLI_CALL: /*** missing ***/
|
||||
case HLI_CALL: /*** missing ***/
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
|
||||
case HLI_CALL: /* check for function return */
|
||||
ticode = picode->du1.idx[0].uses.front();
|
||||
ticode = _ic.du1.idx[0].uses.front();
|
||||
switch (ticode->hl()->opcode)
|
||||
{
|
||||
case HLI_ASSIGN:
|
||||
@ -1081,32 +1086,32 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
ticode,HIGH_FIRST, picode.base(),
|
||||
eDEF, *(++iICODE(ticode))->ll()));
|
||||
ticode->hlU()->asgn.m_rhs = _exp;
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
break;
|
||||
|
||||
case HLI_PUSH:
|
||||
case HLI_RET:
|
||||
ticode->hlU()->expr( _icHl.call.toAst() );
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
break;
|
||||
|
||||
case HLI_JCOND:
|
||||
_exp = _icHl.call.toAst();
|
||||
_retVal = &picode->hl()->call.proc->type->retVal;
|
||||
_retVal = &_ic.hl()->call.proc->retVal;
|
||||
res = Expr::insertSubTreeLongReg (_exp,
|
||||
ticode->hlU()->exp.v,
|
||||
locals.newLongReg ( _retVal->type, _retVal->longId(), picode.base()));
|
||||
if (res) /* was substituted */
|
||||
if (res) /* was substituted */
|
||||
{
|
||||
picode->invalidate();
|
||||
_ic.invalidate();
|
||||
numHlIcodes--;
|
||||
}
|
||||
else /* cannot substitute function */
|
||||
else /* cannot substitute function */
|
||||
{
|
||||
auto lhs = locals.createId(_retVal,picode.base());
|
||||
picode->setAsgn(lhs, _exp);
|
||||
_ic.setAsgn(lhs, _exp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1127,8 +1132,8 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
{
|
||||
g_exp_stk.processExpPush(numHlIcodes, *picode);
|
||||
}
|
||||
else if(picode->du1.getNumRegsDef()!=0)
|
||||
printf("Num def %d\n",picode->du1.getNumRegsDef());
|
||||
else if(_ic.du1.getNumRegsDef()!=0)
|
||||
printf("Num def %d\n",_ic.du1.getNumRegsDef());
|
||||
|
||||
/* For HLI_CALL instructions that use arguments from the stack,
|
||||
* pop them from the expression stack and place them on the
|
||||
@ -1142,11 +1147,11 @@ void BB::findBBExps(LOCAL_ID &locals,Function *fnc)
|
||||
|
||||
/* If we could not substitute the result of a function,
|
||||
* assign it to the corresponding registers */
|
||||
if ( not _icHl.call.proc->isLibrary() and (not picode->du1.used(0)) and (picode->du1.getNumRegsDef() > 0))
|
||||
if ( not _icHl.call.proc->isLibrary() and (not _ic.du1.used(0)) and (_ic.du1.getNumRegsDef() > 0))
|
||||
{
|
||||
_exp = new FuncNode(_icHl.call.proc, _icHl.call.args);
|
||||
auto lhs = AstIdent::idID (&_icHl.call.proc->type->retVal, &locals, picode.base());
|
||||
picode->setAsgn(lhs, _exp);
|
||||
auto lhs = AstIdent::idID (&_icHl.call.proc->retVal, &locals, picode.base());
|
||||
_ic.setAsgn(lhs, _exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1182,6 +1187,7 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
|
||||
if(not _liveOut.any())
|
||||
return;
|
||||
}
|
||||
flg |= PROC_IS_FUNC;
|
||||
isAx = _liveOut.testReg(rAX);
|
||||
isBx = _liveOut.testReg(rBX);
|
||||
isCx = _liveOut.testReg(rCX);
|
||||
@ -1217,55 +1223,53 @@ void Function::preprocessReturnDU(LivenessSet &_liveOut)
|
||||
|
||||
if (isAx and isDx) /* long or pointer */
|
||||
{
|
||||
type->setReturnType(TYPE_LONG_SIGN);
|
||||
type->m_call_conv->calculateStackLayout(this);
|
||||
retVal.type = TYPE_LONG_SIGN;
|
||||
retVal.loc = REG_FRAME;
|
||||
retVal.longId() = LONGID_TYPE(rDX,rAX);
|
||||
/*idx = */localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), Icode.begin());
|
||||
localId.propLongId (rAX, rDX, "");
|
||||
}
|
||||
else if (isAx or isBx or isCx or isDx) /* uint16_t */
|
||||
else if (isAx or isBx or isCx or isDx) /* uint16_t */
|
||||
{
|
||||
eReg selected_reg;
|
||||
retVal.type = TYPE_WORD_SIGN;
|
||||
retVal.loc = REG_FRAME;
|
||||
if (isAx)
|
||||
selected_reg = rAX;
|
||||
retVal.id.regi = rAX;
|
||||
else if (isBx)
|
||||
selected_reg = rBX;
|
||||
retVal.id.regi = rBX;
|
||||
else if (isCx)
|
||||
selected_reg = rCX;
|
||||
retVal.id.regi = rCX;
|
||||
else
|
||||
selected_reg = rDX;
|
||||
type->setReturnType(TYPE_WORD_SIGN);
|
||||
type->m_call_conv->calculateStackLayout(this);
|
||||
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,selected_reg);
|
||||
retVal.id.regi = rDX;
|
||||
/*idx = */localId.newByteWordReg(TYPE_WORD_SIGN,retVal.id.regi);
|
||||
}
|
||||
else if(isAL or isBL or isCL or isDL)
|
||||
{
|
||||
eReg selected_reg;
|
||||
retVal.type = TYPE_BYTE_SIGN;
|
||||
retVal.loc = REG_FRAME;
|
||||
if (isAL)
|
||||
selected_reg = rAL;
|
||||
retVal.id.regi = rAL;
|
||||
else if (isBL)
|
||||
selected_reg = rBL;
|
||||
retVal.id.regi = rBL;
|
||||
else if (isCL)
|
||||
selected_reg = rCL;
|
||||
retVal.id.regi = rCL;
|
||||
else
|
||||
selected_reg = rDL;
|
||||
type->setReturnType(TYPE_BYTE_SIGN);
|
||||
type->m_call_conv->calculateStackLayout(this);
|
||||
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
|
||||
retVal.id.regi = rDL;
|
||||
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
|
||||
}
|
||||
else if(isAH or isBH or isCH or isDH)
|
||||
{
|
||||
eReg selected_reg;
|
||||
retVal.type = TYPE_BYTE_SIGN;
|
||||
retVal.loc = REG_FRAME;
|
||||
if (isAH)
|
||||
selected_reg = rAH;
|
||||
retVal.id.regi = rAH;
|
||||
else if (isBH)
|
||||
selected_reg = rBH;
|
||||
retVal.id.regi = rBH;
|
||||
else if (isCH)
|
||||
selected_reg = rCH;
|
||||
retVal.id.regi = rCH;
|
||||
else
|
||||
selected_reg = rDH;
|
||||
type->setReturnType(TYPE_BYTE_SIGN);
|
||||
type->m_call_conv->calculateStackLayout(this);
|
||||
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,selected_reg);
|
||||
retVal.id.regi = rDH;
|
||||
/*idx = */localId.newByteWordReg(TYPE_BYTE_SIGN,retVal.id.regi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1288,10 +1292,10 @@ void Function::dataFlow(LivenessSet &_liveOut)
|
||||
liveAnal = true;
|
||||
elimCondCodes();
|
||||
genLiveKtes();
|
||||
liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */
|
||||
if (not (flg & PROC_ASM)) /* can generate C for pProc */
|
||||
liveRegAnalysis (_liveOut); /* calls dataFlow() recursively */
|
||||
if (not (flg & PROC_ASM)) /* can generate C for pProc */
|
||||
{
|
||||
genDU1 (); /* generate def/use level 1 chain */
|
||||
findExps (); /* forward substitution algorithm */
|
||||
genDU1 (); /* generate def/use level 1 chain */
|
||||
findExps (); /* forward substitution algorithm */
|
||||
}
|
||||
}
|
||||
|
||||
44
src/dcc.cpp
44
src/dcc.cpp
@ -14,23 +14,22 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include "ui/DccMainWindow.h"
|
||||
|
||||
|
||||
/* Global variables - extern to other modules */
|
||||
extern QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||
extern SYMTAB symtab; /* Global symbol table */
|
||||
extern STATS stats; /* cfg statistics */
|
||||
extern OPTION option; /* Command line options */
|
||||
extern QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||
extern SYMTAB symtab; /* Global symbol table */
|
||||
extern STATS stats; /* cfg statistics */
|
||||
extern OPTION option; /* Command line options */
|
||||
|
||||
static char *initargs(int argc, char *argv[]);
|
||||
static void displayTotalStats(void);
|
||||
static void displayTotalStats();
|
||||
/****************************************************************************
|
||||
* main
|
||||
***************************************************************************/
|
||||
void setupOptions(QCoreApplication &app) {
|
||||
void setupOptions(const QCoreApplication &app) {
|
||||
//[-a1a2cmsi]
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("dcc");
|
||||
@ -80,7 +79,7 @@ void setupOptions(QCoreApplication &app) {
|
||||
option.Interact = false;
|
||||
option.Calls = parser.isSet(boolOpts[2]);
|
||||
option.filename = args.first();
|
||||
option.CustomEntryPoint = parser.value(entryPointOption).toUInt(0,16);
|
||||
option.CustomEntryPoint = parser.value(entryPointOption).toUInt(nullptr,16);
|
||||
if(parser.isSet(targetFileOption))
|
||||
asm1_name = asm2_name = parser.value(targetFileOption);
|
||||
else if(option.asm1 or option.asm2) {
|
||||
@ -91,36 +90,23 @@ void setupOptions(QCoreApplication &app) {
|
||||
}
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication::setApplicationName("dcc");
|
||||
QCoreApplication::setApplicationVersion("0.2");
|
||||
if(argc==1) {
|
||||
QApplication app(argc,argv);
|
||||
DccMainWindow win;
|
||||
win.show();
|
||||
return app.exec();
|
||||
|
||||
}
|
||||
QCoreApplication app(argc,argv);
|
||||
|
||||
QCoreApplication::setApplicationVersion("0.1");
|
||||
setupOptions(app);
|
||||
|
||||
Project *proj = Project::get();
|
||||
/* Front end reads in EXE or COM file, parses it into I-code while
|
||||
* building the call graph and attaching appropriate bits of code for
|
||||
* each procedure.
|
||||
*/
|
||||
proj->create(option.filename);
|
||||
Project::get()->create(option.filename);
|
||||
|
||||
DccFrontend fe(&app);
|
||||
proj->addLoadCommands(option.filename);
|
||||
proj->processAllCommands();
|
||||
if(proj->m_error_state) {
|
||||
proj->dumpAllErrors();
|
||||
if(not Project::get()->load()) {
|
||||
return -1;
|
||||
}
|
||||
if (option.verbose)
|
||||
proj->prog.displayLoadInfo();
|
||||
|
||||
Project::get()->prog.displayLoadInfo();
|
||||
if(false==fe.FrontEnd ())
|
||||
return -1;
|
||||
if(option.asm1)
|
||||
@ -137,9 +123,9 @@ int main(int argc, char **argv)
|
||||
* analysis, data flow etc. and outputs it to output file ready for
|
||||
* re-compilation.
|
||||
*/
|
||||
BackEnd(proj->callGraph);
|
||||
BackEnd(Project::get()->callGraph);
|
||||
|
||||
proj->callGraph->write();
|
||||
Project::get()->callGraph->write();
|
||||
|
||||
if (option.Stats)
|
||||
displayTotalStats();
|
||||
|
||||
@ -2,20 +2,55 @@
|
||||
#include "dcc.h"
|
||||
#include "project.h"
|
||||
struct DccImpl : public IDcc {
|
||||
PtrFunction m_current_func;
|
||||
ilFunction m_current_func;
|
||||
// IDcc interface
|
||||
public:
|
||||
bool load(QString name)
|
||||
void BaseInit()
|
||||
{
|
||||
m_current_func = Project::get()->functions().end();
|
||||
}
|
||||
void Init(QObject *tgt)
|
||||
{
|
||||
}
|
||||
ilFunction GetFirstFuncHandle()
|
||||
{
|
||||
return Project::get()->functions().begin();
|
||||
}
|
||||
ilFunction GetCurFuncHandle()
|
||||
{
|
||||
return m_current_func;
|
||||
}
|
||||
void analysis_Once()
|
||||
{
|
||||
}
|
||||
void load(QString name)
|
||||
{
|
||||
option.filename = name;
|
||||
Project::get()->create(name);
|
||||
return Project::get()->addLoadCommands(name);
|
||||
}
|
||||
void prtout_asm(IXmlTarget *, int level)
|
||||
{
|
||||
}
|
||||
void prtout_cpp(IXmlTarget *, int level)
|
||||
{
|
||||
}
|
||||
size_t getFuncCount()
|
||||
{
|
||||
return Project::get()->functions().size();
|
||||
}
|
||||
const lFunction &validFunctions() const
|
||||
{
|
||||
return Project::get()->functions();
|
||||
}
|
||||
void SetCurFunc_by_Name(QString v)
|
||||
{
|
||||
PtrFunction p(Project::get()->findByName(v));
|
||||
if(p!=nullptr)
|
||||
m_current_func = p;
|
||||
lFunction & funcs(Project::get()->functions());
|
||||
for(auto iter=funcs.begin(),fin=funcs.end(); iter!=fin; ++iter) {
|
||||
if(iter->name==v) {
|
||||
m_current_func = iter;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
QDir installDir() {
|
||||
return QDir(".");
|
||||
|
||||
743
src/disassem.cpp
743
src/disassem.cpp
@ -18,7 +18,6 @@
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "src/ui/StructuredTextTarget.h"
|
||||
|
||||
// Note: for the time being, there is no interactive disassembler
|
||||
// for unix
|
||||
@ -29,7 +28,7 @@ using namespace std;
|
||||
#define POS_LAB 15 /* Position of label */
|
||||
#define POS_OPC 20 /* Position of opcode */
|
||||
#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_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 CIcodeRec pc;
|
||||
static int cb, numIcode, allocIcode;
|
||||
static int cb, j, numIcode, allocIcode;
|
||||
static map<int,int> pl;
|
||||
static uint32_t nextInst;
|
||||
//static bool fImpure;
|
||||
static bool fImpure;
|
||||
//static int g_lab;
|
||||
static PtrFunction pProc; /* Points to current proc struct */
|
||||
static Function * pProc; /* Points to current proc struct */
|
||||
|
||||
struct POSSTACK_ENTRY
|
||||
{
|
||||
@ -108,12 +107,12 @@ static vector<POSSTACK_ENTRY> posStack; /* position stack */
|
||||
|
||||
#define printfd(x) printf(x)
|
||||
#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)
|
||||
{
|
||||
if (srcIsImmed() and not testFlags(JMP_ICODE) and isJmpInst())
|
||||
if (testFlags(I) and not testFlags(JMP_ICODE) and isJmpInst())
|
||||
{
|
||||
/* Replace the immediate operand with an icode index */
|
||||
iICODE labTgt=_pc.labelSrch(src().getImm2());
|
||||
@ -134,12 +133,12 @@ void LLInst::findJumpTargets(CIcodeRec &_pc)
|
||||
}
|
||||
/*****************************************************************************
|
||||
* disassem - Prints a disassembled listing of a procedure.
|
||||
* pass == 1 generates output on file .a1
|
||||
* pass == 2 generates output on file .a2
|
||||
* pass == 3 generates output on file .b
|
||||
* pass == 1 generates output on file .a1
|
||||
* pass == 2 generates output on file .a2
|
||||
* pass == 3 generates output on file .b
|
||||
****************************************************************************/
|
||||
|
||||
void Disassembler::disassem(PtrFunction ppProc)
|
||||
void Disassembler::disassem(Function * ppProc)
|
||||
{
|
||||
|
||||
|
||||
@ -214,7 +213,364 @@ void Disassembler::disassem(PtrFunction ppProc)
|
||||
****************************************************************************/
|
||||
void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass)
|
||||
{
|
||||
assert(false);
|
||||
PROG &prog(Project::get()->prog);
|
||||
QString oper_contents;
|
||||
QTextStream oper_stream(&oper_contents);
|
||||
QString hex_bytes;
|
||||
QString result_contents;
|
||||
QTextStream result_stream(&result_contents);
|
||||
QString opcode_with_mods;
|
||||
|
||||
QString operands_contents;
|
||||
QTextStream operands_s(&operands_contents);
|
||||
oper_stream.setNumberFlags(QTextStream::UppercaseBase|QTextStream::UppercaseDigits);
|
||||
|
||||
/* Disassembly stage 1 --
|
||||
* Do not try to display NO_CODE entries or synthetic instructions,
|
||||
* other than JMPs, that have been introduced for def/use analysis. */
|
||||
if ((option.asm1) and
|
||||
( inst.testFlags(NO_CODE) or
|
||||
(inst.testFlags(SYNTHETIC) and (inst.getOpcode() != iJMP))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (inst.testFlags(NO_CODE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (inst.testFlags(TARGET | CASE))
|
||||
{
|
||||
if (pass == 3)
|
||||
cCode.appendCode("\n"); /* Print to c code buffer */
|
||||
else
|
||||
m_fp<< "\n"; /* No, print to the stream */
|
||||
}
|
||||
|
||||
/* Find next instruction label and print hex bytes */
|
||||
if (inst.testFlags(SYNTHETIC))
|
||||
nextInst = inst.label;
|
||||
else
|
||||
{
|
||||
cb = (uint32_t) inst.numBytes;
|
||||
nextInst = inst.label + cb;
|
||||
|
||||
/* Output hex code in program image */
|
||||
if (pass != 3)
|
||||
{
|
||||
for (j = 0; j < cb; j++)
|
||||
{
|
||||
hex_bytes += QString("%1").arg(uint16_t(prog.image()[inst.label + j]),2,16,QChar('0')).toUpper();
|
||||
}
|
||||
hex_bytes += ' ';
|
||||
}
|
||||
}
|
||||
oper_stream.setFieldWidth(POS_LAB);
|
||||
oper_stream.setFieldAlignment(QTextStream::AlignLeft);
|
||||
oper_stream << hex_bytes;
|
||||
/* Check if there is a symbol here */
|
||||
selectTable(Label);
|
||||
oper_stream.setFieldWidth(5); // align for the labels
|
||||
{
|
||||
QString lab_contents;
|
||||
QTextStream lab_stream(&lab_contents);
|
||||
if (readVal(lab_stream, inst.label, nullptr))
|
||||
{
|
||||
lab_stream << ':'; /* Also removes the null */
|
||||
}
|
||||
else if (inst.testFlags(TARGET)) /* Symbols override Lnn labels */
|
||||
{
|
||||
/* Print label */
|
||||
if (pl.count(loc_ip)==0)
|
||||
{
|
||||
pl[loc_ip] = ++g_lab;
|
||||
}
|
||||
lab_stream<< "L"<<pl[loc_ip]<<':';
|
||||
}
|
||||
lab_stream.flush();
|
||||
oper_stream << lab_contents;
|
||||
oper_stream.setFieldWidth(0);
|
||||
}
|
||||
if ((inst.getOpcode()==iSIGNEX )and inst.testFlags(B))
|
||||
{
|
||||
inst.setOpcode(iCBW);
|
||||
}
|
||||
opcode_with_mods += Machine_X86::opcodeName(inst.getOpcode());
|
||||
|
||||
switch ( inst.getOpcode() )
|
||||
{
|
||||
case iADD: case iADC: case iSUB: case iSBB: case iAND: case iOR:
|
||||
case iXOR: case iTEST: case iCMP: case iMOV: case iLEA: case iXCHG:
|
||||
strDst(operands_s,inst.getFlag(), inst.m_dst);
|
||||
inst.strSrc(operands_s);
|
||||
break;
|
||||
|
||||
case iESC:
|
||||
inst.flops(operands_s);
|
||||
break;
|
||||
|
||||
case iSAR: case iSHL: case iSHR: case iRCL: case iRCR: case iROL:
|
||||
case iROR:
|
||||
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
|
||||
if(inst.testFlags(I))
|
||||
inst.strSrc(operands_s);
|
||||
else
|
||||
operands_s<<", cl";
|
||||
break;
|
||||
|
||||
case iINC: case iDEC: case iNEG: case iNOT: case iPOP:
|
||||
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
|
||||
break;
|
||||
|
||||
case iPUSH:
|
||||
if (inst.testFlags(I))
|
||||
{
|
||||
operands_s<<strHex(inst.src().getImm2());
|
||||
}
|
||||
else
|
||||
{
|
||||
strDst(operands_s,inst.getFlag() | I, inst.m_dst);
|
||||
}
|
||||
break;
|
||||
|
||||
case iDIV: case iIDIV: case iMUL: case iIMUL: case iMOD:
|
||||
if (inst.testFlags(I))
|
||||
{
|
||||
strDst(operands_s,inst.getFlag(), inst.m_dst) <<", ";
|
||||
formatRM(operands_s, inst.src());
|
||||
inst.strSrc(operands_s);
|
||||
}
|
||||
else
|
||||
strDst(operands_s,inst.getFlag() | I, inst.src());
|
||||
break;
|
||||
|
||||
case iLDS: case iLES: case iBOUND:
|
||||
strDst(operands_s,inst.getFlag(), inst.m_dst)<<", dword ptr";
|
||||
inst.strSrc(operands_s,true);
|
||||
break;
|
||||
|
||||
case iJB: case iJBE: case iJAE: case iJA:
|
||||
case iJL: case iJLE: case iJGE: case iJG:
|
||||
case iJE: case iJNE: case iJS: case iJNS:
|
||||
case iJO: case iJNO: case iJP: case iJNP:
|
||||
case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
|
||||
case iJMP: case iJMPF:
|
||||
|
||||
/* Check if there is a symbol here */
|
||||
{
|
||||
ICODE *lab=pc.GetIcode(inst.src().getImm2());
|
||||
selectTable(Label);
|
||||
if ((inst.src().getImm2() < (uint32_t)numIcode) and /* Ensure in range */
|
||||
readVal(operands_s, lab->ll()->label, nullptr))
|
||||
{
|
||||
break; /* Symbolic label. Done */
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.testFlags(NO_LABEL))
|
||||
{
|
||||
//strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op));
|
||||
operands_s<<strHex(inst.src().getImm2());
|
||||
}
|
||||
else if (inst.testFlags(I) )
|
||||
{
|
||||
j = inst.src().getImm2();
|
||||
if (pl.count(j)==0) /* Forward jump */
|
||||
{
|
||||
pl[j] = ++g_lab;
|
||||
}
|
||||
if (inst.getOpcode() == iJMPF)
|
||||
{
|
||||
operands_s<<" far ptr ";
|
||||
}
|
||||
operands_s<<"L"<<pl[j];
|
||||
}
|
||||
else if (inst.getOpcode() == iJMPF)
|
||||
{
|
||||
operands_s<<"dword ptr";
|
||||
inst.strSrc(operands_s,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
strDst(operands_s,I, inst.src());
|
||||
}
|
||||
break;
|
||||
|
||||
case iCALL: case iCALLF:
|
||||
if (inst.testFlags(I))
|
||||
{
|
||||
QString oper = QString("%1 ptr %2")
|
||||
.arg((inst.getOpcode() == iCALL) ? "near" : "far")
|
||||
.arg((inst.src().proc.proc)->name);
|
||||
operands_s<< qPrintable(oper);
|
||||
}
|
||||
else if (inst.getOpcode() == iCALLF)
|
||||
{
|
||||
operands_s<<"dword ptr ";
|
||||
inst.strSrc(operands_s,true);
|
||||
}
|
||||
else
|
||||
strDst(operands_s,I, inst.src());
|
||||
break;
|
||||
|
||||
case iENTER:
|
||||
operands_s<<strHex(inst.m_dst.off) << ", " << strHex(inst.src().getImm2());
|
||||
break;
|
||||
|
||||
case iRET: case iRETF: case iINT:
|
||||
if (inst.testFlags(I))
|
||||
{
|
||||
operands_s<<strHex(inst.src().getImm2());
|
||||
}
|
||||
break;
|
||||
|
||||
case iCMPS: case iREPNE_CMPS: case iREPE_CMPS:
|
||||
case iSCAS: case iREPNE_SCAS: case iREPE_SCAS:
|
||||
case iSTOS: case iREP_STOS:
|
||||
case iLODS: case iREP_LODS:
|
||||
case iMOVS: case iREP_MOVS:
|
||||
case iINS: case iREP_INS:
|
||||
case iOUTS: case iREP_OUTS:
|
||||
if (inst.src().segOver)
|
||||
{
|
||||
bool is_dx_src=(inst.getOpcode() == iOUTS or inst.getOpcode() == iREP_OUTS);
|
||||
if(is_dx_src)
|
||||
operands_s<<"dx, "<<szPtr[inst.getFlag() & B];
|
||||
else
|
||||
operands_s<<szPtr[inst.getFlag() & B];
|
||||
if (inst.getOpcode() == iLODS or
|
||||
inst.getOpcode() == iREP_LODS or
|
||||
inst.getOpcode() == iOUTS or
|
||||
inst.getOpcode() == iREP_OUTS)
|
||||
{
|
||||
operands_s<<Machine_X86::regName(inst.src().segOver); // szWreg[src.segOver-rAX]
|
||||
}
|
||||
else
|
||||
{
|
||||
operands_s<<"es:[di], "<<Machine_X86::regName(inst.src().segOver);
|
||||
}
|
||||
operands_s<<":[si]";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(inst.getFlag() & B)
|
||||
opcode_with_mods+='B';
|
||||
else
|
||||
opcode_with_mods+='W';
|
||||
}
|
||||
break;
|
||||
|
||||
case iXLAT:
|
||||
if (inst.src().segOver)
|
||||
{
|
||||
operands_s<<" "<<szPtr[1];
|
||||
operands_s<<Machine_X86::regName(inst.src().segOver)<<":[bx]";
|
||||
}
|
||||
break;
|
||||
|
||||
case iIN:
|
||||
(inst.getFlag() & B)? operands_s<<"al, " : operands_s<< "ax, ";
|
||||
(inst.testFlags(I))? operands_s << strHex(inst.src().getImm2()) : operands_s<< "dx";
|
||||
break;
|
||||
|
||||
case iOUT:
|
||||
{
|
||||
QString d1=((inst.testFlags(I))? strHex(inst.src().getImm2()): "dx");
|
||||
QString d2=((inst.getFlag() & B) ? ", al": ", ax");
|
||||
operands_s<<d1 << d2;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
oper_stream.setFieldWidth(15);
|
||||
operands_s.flush();
|
||||
oper_stream << qSetFieldWidth(15) << opcode_with_mods << qSetFieldWidth(0) << operands_contents;
|
||||
/* Comments */
|
||||
if (inst.testFlags(SYNTHETIC))
|
||||
{
|
||||
fImpure = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = inst.label, fImpure = 0; j > 0 and j < (int)nextInst; j++)
|
||||
{
|
||||
fImpure |= BITMAP(j, BM_DATA);
|
||||
}
|
||||
}
|
||||
result_stream.setFieldWidth(54);
|
||||
result_stream.setFieldAlignment(QTextStream::AlignLeft);
|
||||
oper_stream.flush();
|
||||
result_stream << oper_contents;
|
||||
result_stream.setFieldWidth(0);
|
||||
/* Check for user supplied comment */
|
||||
selectTable(Comment);
|
||||
QString cbuf_contents;
|
||||
QTextStream cbuf(&cbuf_contents);
|
||||
if (readVal(cbuf, inst.label, nullptr))
|
||||
{
|
||||
cbuf.flush();
|
||||
result_stream <<"; "<<*cbuf.string();
|
||||
}
|
||||
else if (fImpure or (inst.testFlags(SWITCH | CASE | SEG_IMMED | IMPURE | SYNTHETIC | TERMINATES)))
|
||||
{
|
||||
if (inst.testFlags(CASE))
|
||||
{
|
||||
result_stream << ";Case l"<< inst.caseEntry;
|
||||
}
|
||||
if (inst.testFlags(SWITCH))
|
||||
{
|
||||
result_stream << ";Switch ";
|
||||
}
|
||||
if (fImpure)
|
||||
{
|
||||
result_stream << ";Accessed as data ";
|
||||
}
|
||||
if (inst.testFlags(IMPURE))
|
||||
{
|
||||
result_stream << ";Impure operand ";
|
||||
}
|
||||
if (inst.testFlags(SEG_IMMED))
|
||||
{
|
||||
result_stream << ";Segment constant";
|
||||
}
|
||||
if (inst.testFlags(TERMINATES))
|
||||
{
|
||||
result_stream << ";Exit to DOS";
|
||||
}
|
||||
}
|
||||
|
||||
/* Comment on iINT icodes */
|
||||
if (inst.getOpcode() == iINT)
|
||||
inst.writeIntComment(result_stream);
|
||||
|
||||
/* Display output line */
|
||||
if(pass==3)
|
||||
{
|
||||
/* output to .b code buffer */
|
||||
if (inst.testFlags(SYNTHETIC))
|
||||
result_stream<<";Synthetic inst";
|
||||
if (pass == 3) { /* output to .b code buffer */
|
||||
cCode.appendCode("%s\n", qPrintable(result_contents));
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[12];
|
||||
/* output to .a1 or .a2 file */
|
||||
if (not inst.testFlags(SYNTHETIC) )
|
||||
{
|
||||
sprintf(buf,"%03d %06X",loc_ip, inst.label);
|
||||
}
|
||||
else /* SYNTHETIC instruction */
|
||||
{
|
||||
sprintf(buf,"%03d ",loc_ip);
|
||||
result_stream<<";Synthetic inst";
|
||||
}
|
||||
result_stream.flush();
|
||||
m_fp<<buf<< " " << result_contents << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -273,19 +629,19 @@ static QTextStream & strDst(QTextStream &os,uint32_t flg, const LLOperand &pm)
|
||||
/****************************************************************************
|
||||
* strSrc *
|
||||
****************************************************************************/
|
||||
//QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
|
||||
//{
|
||||
// if(false==skip_comma)
|
||||
// os<<", ";
|
||||
// if (srcIsImmed())
|
||||
// os<<strHex(src().getImm2());
|
||||
// else if (testFlags(IM_SRC)) /* level 2 */
|
||||
// os<<"dx:ax";
|
||||
// else
|
||||
// formatRM(os, src());
|
||||
QTextStream &LLInst::strSrc(QTextStream &os,bool skip_comma)
|
||||
{
|
||||
if(false==skip_comma)
|
||||
os<<", ";
|
||||
if (testFlags(I))
|
||||
os<<strHex(src().getImm2());
|
||||
else if (testFlags(IM_SRC)) /* level 2 */
|
||||
os<<"dx:ax";
|
||||
else
|
||||
formatRM(os, src());
|
||||
|
||||
// return os;
|
||||
//}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -304,7 +660,7 @@ static char *strHex(uint32_t d)
|
||||
/****************************************************************************
|
||||
* interactDis - interactive disassembler *
|
||||
****************************************************************************/
|
||||
void interactDis(const PtrFunction & initProc, int initIC)
|
||||
void interactDis(Function * initProc, int initIC)
|
||||
{
|
||||
QString procname = "UNKNOWN";
|
||||
if(initProc)
|
||||
@ -334,29 +690,29 @@ void LLInst::flops(QTextStream &out)
|
||||
}
|
||||
else switch (op & 0x30)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
out << "dword ptr ";
|
||||
break;
|
||||
case 0x20:
|
||||
out << "qword ptr ";
|
||||
break;
|
||||
case 0x30:
|
||||
switch (op)
|
||||
{
|
||||
case 0x3C: /* FBLD */
|
||||
case 0x3E: /* FBSTP */
|
||||
out << "tbyte ptr ";
|
||||
case 0x00:
|
||||
case 0x10:
|
||||
out << "dword ptr ";
|
||||
break;
|
||||
case 0x3D: /* FILD 64 bit */
|
||||
case 0x3F: /* FISTP 64 bit */
|
||||
case 0x20:
|
||||
out << "qword ptr ";
|
||||
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:
|
||||
out << "uint16_t ptr ";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
out << "uint16_t ptr ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
out.setFieldWidth(0);
|
||||
formatRM(out, m_dst);
|
||||
@ -371,271 +727,46 @@ void LLInst::flops(QTextStream &out)
|
||||
int destRegIdx=m_dst.regi - rAX;
|
||||
switch (op)
|
||||
{
|
||||
case 0x0C:
|
||||
out << szFlops0C[destRegIdx];
|
||||
break;
|
||||
case 0x0D:
|
||||
out << szFlops0D[destRegIdx];
|
||||
break;
|
||||
case 0x0E:
|
||||
out << szFlops0E[destRegIdx];
|
||||
break;
|
||||
case 0x0F:
|
||||
out << szFlops0F[destRegIdx];
|
||||
break;
|
||||
case 0x15:
|
||||
out << szFlops15[destRegIdx];
|
||||
break;
|
||||
case 0x1C:
|
||||
out << szFlops1C[destRegIdx];
|
||||
break;
|
||||
case 0x33:
|
||||
out << szFlops33[destRegIdx];
|
||||
break;
|
||||
case 0x3C:
|
||||
out << szFlops3C[destRegIdx];
|
||||
break;
|
||||
default:
|
||||
out << Machine_X86::floatOpName(0x40+op);
|
||||
if ((op >= 0x20) and (op <= 0x27))
|
||||
{
|
||||
/* This is the ST(i), ST form. */
|
||||
out << "ST("<<destRegIdx - rAX<<"),ST";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ST, ST(i) */
|
||||
out << "ST,ST("<<destRegIdx;
|
||||
}
|
||||
case 0x0C:
|
||||
out << szFlops0C[destRegIdx];
|
||||
break;
|
||||
case 0x0D:
|
||||
out << szFlops0D[destRegIdx];
|
||||
break;
|
||||
case 0x0E:
|
||||
out << szFlops0E[destRegIdx];
|
||||
break;
|
||||
case 0x0F:
|
||||
out << szFlops0F[destRegIdx];
|
||||
break;
|
||||
case 0x15:
|
||||
out << szFlops15[destRegIdx];
|
||||
break;
|
||||
case 0x1C:
|
||||
out << szFlops1C[destRegIdx];
|
||||
break;
|
||||
case 0x33:
|
||||
out << szFlops33[destRegIdx];
|
||||
break;
|
||||
case 0x3C:
|
||||
out << szFlops3C[destRegIdx];
|
||||
break;
|
||||
default:
|
||||
out << Machine_X86::floatOpName(0x40+op);
|
||||
if ((op >= 0x20) and (op <= 0x27))
|
||||
{
|
||||
/* This is the ST(i), ST form. */
|
||||
out << "ST("<<destRegIdx - rAX<<"),ST";
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ST, ST(i) */
|
||||
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();
|
||||
}
|
||||
|
||||
@ -11,36 +11,37 @@
|
||||
|
||||
#include "dcc.h"
|
||||
|
||||
static std::map<eErrorId,std::string> errorMessage =
|
||||
{
|
||||
{INVALID_ARG ,"Invalid option -%c\n"},
|
||||
{INVALID_OPCODE ,"Invalid instruction %02X at location %06lX\n"},
|
||||
{INVALID_386OP ,"Don't understand 80386 instruction %02X at location %06lX\n"},
|
||||
{FUNNY_SEGOVR ,"Segment override with no memory operand at location %06lX\n"},
|
||||
{FUNNY_REP ,"REP prefix without a string instruction at location %06lX\n"},
|
||||
{CANNOT_OPEN ,"Cannot open %s\n"},
|
||||
{CANNOT_READ ,"Error while reading %s\n"},
|
||||
{MALLOC_FAILED ,"malloc of %ld bytes failed\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"},
|
||||
{INVALID_SYNTHETIC_BB,"Basic Block is a synthetic jump\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"},
|
||||
{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"},
|
||||
{NOT_DEF_USE ,"%x: Def - use not supported. Def op = %d, use op = %d.\n"},
|
||||
{REPEAT_FAIL ,"Failed to construct repeat..until() condition.\n"},
|
||||
{WHILE_FAIL ,"Failed to construct while() condition.\n"},
|
||||
};
|
||||
static const std::map<eErrorId,std::string> errorMessage =
|
||||
{
|
||||
{INVALID_ARG ,"Invalid option -%c\n"},
|
||||
{INVALID_OPCODE ,"Invalid instruction %02X at location %06lX\n"},
|
||||
{INVALID_386OP ,"Don't understand 80386 instruction %02X at location %06lX\n"},
|
||||
{FUNNY_SEGOVR ,"Segment override with no memory operand at location %06lX\n"},
|
||||
{FUNNY_REP ,"REP prefix without a string instruction at location %06lX\n"},
|
||||
{CANNOT_OPEN ,"Cannot open %s\n"},
|
||||
{CANNOT_READ ,"Error while reading %s\n"},
|
||||
{MALLOC_FAILED ,"malloc of %ld bytes failed\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"},
|
||||
{INVALID_SYNTHETIC_BB,"Basic Block is a synthetic jump\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"},
|
||||
{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"},
|
||||
{NOT_DEF_USE ,"%x: Def - use not supported. Def op = %d, use op = %d.\n"},
|
||||
{REPEAT_FAIL ,"Failed to construct repeat..until() condition.\n"},
|
||||
{WHILE_FAIL ,"Failed to construct while() condition.\n"},
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
fatalError: displays error message and exits the program.
|
||||
****************************************************************************/
|
||||
void fatalError(eErrorId errId, ...)
|
||||
{ va_list args;
|
||||
//#ifdef __UNIX__ /* ultrix */
|
||||
{
|
||||
va_list args;
|
||||
//#ifdef __UNIX__ /* ultrix */
|
||||
#if 0
|
||||
int errId;
|
||||
int errId;
|
||||
|
||||
va_start(args);
|
||||
errId = va_arg(args, int);
|
||||
@ -49,10 +50,12 @@ void fatalError(eErrorId errId, ...)
|
||||
#endif
|
||||
|
||||
if (errId == USAGE)
|
||||
fprintf(stderr,"Usage: dcc [-a1a2cmpsvVi][-o asmfile] DOS_executable\n");
|
||||
fprintf(stderr,"Usage: dcc [-a1a2cmpsvVi][-o asmfile] DOS_executable\n");
|
||||
else {
|
||||
auto msg_iter = errorMessage.find(errId);
|
||||
assert(msg_iter!=errorMessage.end());
|
||||
fprintf(stderr, "dcc: ");
|
||||
vfprintf(stderr, errorMessage[errId].c_str(), args);
|
||||
vfprintf(stderr, msg_iter->second.c_str(), args);
|
||||
}
|
||||
va_end(args);
|
||||
exit((int)errId);
|
||||
@ -63,10 +66,11 @@ void fatalError(eErrorId errId, ...)
|
||||
reportError: reports the warning/error and continues with the program.
|
||||
****************************************************************************/
|
||||
void reportError(eErrorId errId, ...)
|
||||
{ va_list args;
|
||||
//#ifdef __UNIX__ /* ultrix */
|
||||
{
|
||||
va_list args;
|
||||
//#ifdef __UNIX__ /* ultrix */
|
||||
#if 0
|
||||
int errId;
|
||||
int errId;
|
||||
|
||||
va_start(args);
|
||||
errId = va_arg(args, int);
|
||||
@ -74,6 +78,8 @@ void reportError(eErrorId errId, ...)
|
||||
va_start(args, errId);
|
||||
#endif
|
||||
fprintf(stderr, "dcc: ");
|
||||
vfprintf(stderr, errorMessage[errId].c_str(), args);
|
||||
auto msg_iter = errorMessage.find(errId);
|
||||
assert(msg_iter!=errorMessage.end());
|
||||
vfprintf(stderr, msg_iter->second.c_str(), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ void fixWildCards(uint8_t pat[])
|
||||
op = pat[pc++];
|
||||
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)
|
||||
{
|
||||
/* Arithmetic group 00-3F */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* dcc project CFG related functions
|
||||
* dcc project CFG related functions
|
||||
* (C) Cristina Cifuentes
|
||||
****************************************************************************/
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
extern Project g_proj;
|
||||
//static BB * rmJMP(Function * pProc, int marker, BB * pBB);
|
||||
//static void mergeFallThrough(Function * pProc, BB * pBB);
|
||||
//static void dfsNumbering(BB * pBB, std::vector<BB*> &dfsLast, int *first, int *last);
|
||||
@ -46,7 +47,7 @@ void Function::createCFG()
|
||||
|
||||
BB * psBB;
|
||||
BB * pBB;
|
||||
iICODE pIcode = Icode.begin();
|
||||
iICODE pIcode = Icode.begin();
|
||||
|
||||
stats.numBBbef = stats.numBBaft = 0;
|
||||
rICODE current_range=make_iterator_range(pIcode,++iICODE(pIcode));
|
||||
@ -92,7 +93,7 @@ void Function::createCFG()
|
||||
pBB->addOutEdge(elem);
|
||||
hasCase = true;
|
||||
}
|
||||
else if (ll->srcIsImmed() and not ll->testFlags(NO_LABEL)) //TODO: WHY NO_LABEL TESTIT
|
||||
else if ((ll->getFlag() & (I | NO_LABEL)) == I) //TODO: WHY NO_LABEL TESTIT
|
||||
{
|
||||
pBB = BB::Create(current_range, ONE_BRANCH, this);
|
||||
pBB->addOutEdge(ll->src().getImm2());
|
||||
@ -204,7 +205,7 @@ void Function::freeCFG()
|
||||
void Function::compressCFG()
|
||||
{
|
||||
BB *pNxt;
|
||||
int ip, first=0, last;
|
||||
int ip, first=0, last;
|
||||
|
||||
/* First pass over BB list removes redundant jumps of the form
|
||||
* (Un)Conditional -> Unconditional jump */
|
||||
@ -240,7 +241,7 @@ void Function::compressCFG()
|
||||
{
|
||||
if (pBB->inEdges.empty())
|
||||
{
|
||||
if (entry_node) /* Init it misses out on */
|
||||
if (entry_node) /* Init it misses out on */
|
||||
pBB->index = UN_INIT;
|
||||
else
|
||||
{
|
||||
@ -320,7 +321,7 @@ BB *BB::rmJMP(int marker, BB * pBB)
|
||||
****************************************************************************/
|
||||
void BB::mergeFallThrough( CIcodeRec &Icode)
|
||||
{
|
||||
BB * pChild;
|
||||
BB * pChild;
|
||||
if (nullptr==this)
|
||||
{
|
||||
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)
|
||||
{
|
||||
BB * pChild;
|
||||
BB * pChild;
|
||||
traversed = DFS_NUM;
|
||||
dfsFirstNum = (*first)++;
|
||||
|
||||
|
||||
@ -332,7 +332,7 @@ void Function::highLevelGen()
|
||||
lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
|
||||
}
|
||||
if(ll->getOpcode()==iPUSH) {
|
||||
if(ll->srcIsImmed()) {
|
||||
if(ll->testFlags(I)) {
|
||||
lhs = new Constant(src_ll->opz,src_ll->byteWidth());
|
||||
}
|
||||
// lhs = AstIdent::id (*pIcode->ll(), DST, this, i, *pIcode, NONE);
|
||||
@ -399,8 +399,7 @@ void Function::highLevelGen()
|
||||
}
|
||||
break;
|
||||
|
||||
case iMOV:
|
||||
pIcode->setAsgn(lhs, rhs);
|
||||
case iMOV: pIcode->setAsgn(lhs, rhs);
|
||||
break;
|
||||
|
||||
case iMUL:
|
||||
@ -433,8 +432,7 @@ void Function::highLevelGen()
|
||||
break;
|
||||
|
||||
case iRET:
|
||||
case iRETF:
|
||||
pIcode->setUnary(HLI_RET, nullptr);
|
||||
case iRETF: pIcode->setUnary(HLI_RET, nullptr);
|
||||
break;
|
||||
|
||||
case iSHL:
|
||||
@ -463,8 +461,6 @@ void Function::highLevelGen()
|
||||
rhs = new BinaryOperator(XOR,lhs, rhs);
|
||||
pIcode->setAsgn(lhs, rhs);
|
||||
break;
|
||||
//TODO: default: // mostly to silence static analyzer warnings ?
|
||||
// delete rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
* 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 _form;
|
||||
@ -559,11 +555,10 @@ void HLTYPE::set(Expr *l, Expr *r)
|
||||
asgn.m_lhs=l;
|
||||
asgn.m_rhs=r;
|
||||
}
|
||||
/** Returns a string with the contents of the current high-level icode.
|
||||
* \note this routine does not output the contens of HLI_JCOND icodes. This is
|
||||
* done in a separate routine to be able to support the removal of
|
||||
* empty THEN clauses on an if..then..else.
|
||||
*/
|
||||
/* Returns a string with the contents of the current high-level icode.
|
||||
* Note: this routine does not output the contens of HLI_JCOND icodes. This is
|
||||
* done in a separate routine to be able to support the removal of
|
||||
* empty THEN clauses on an if..then..else. */
|
||||
QString HLTYPE::write1HlIcode (Function * pProc, int *numLoc) const
|
||||
{
|
||||
const HlTypeSupport *p = get();
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
#include "msvc_fixes.h"
|
||||
#include "dcc.h"
|
||||
#include "types.h" // Common types like uint8_t, etc
|
||||
#include "ast.h" // Some icode types depend on these
|
||||
#include "types.h" // Common types like uint8_t, etc
|
||||
#include "ast.h" // Some icode types depend on these
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -15,8 +15,10 @@ CIcodeRec::CIcodeRec()
|
||||
{
|
||||
}
|
||||
|
||||
/* Copies the icode that is pointed to by pIcode to the icode array. */
|
||||
ICODE * CIcodeRec::addIcode(const ICODE *pIcode)
|
||||
/* Copies the icode that is pointed to by pIcode to the icode array.
|
||||
* If there is need to allocate extra memory, it is done so, and
|
||||
* the alloc variable is adjusted. */
|
||||
ICODE * CIcodeRec::addIcode(ICODE *pIcode)
|
||||
{
|
||||
push_back(*pIcode);
|
||||
back().loc_ip = size()-1;
|
||||
@ -65,15 +67,6 @@ extern bundle cCode;
|
||||
* is created and a goto is also emitted.
|
||||
* Note: this procedure is to be used when the label is to be backpatched
|
||||
* onto code in cCode.code */
|
||||
void LLInst::clrFlags(uint32_t flag)
|
||||
{
|
||||
if(getOpcode()==iMOD)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
flg &= ~flag;
|
||||
}
|
||||
|
||||
void LLInst::emitGotoLabel (int indLevel)
|
||||
{
|
||||
if ( not testFlags(HLL_LABEL) ) /* node hasn't got a lab */
|
||||
@ -82,7 +75,8 @@ void LLInst::emitGotoLabel (int indLevel)
|
||||
hllLabNum = getNextLabel();
|
||||
setFlags(HLL_LABEL);
|
||||
|
||||
/* Node has been traversed already, so backpatch this label into the code */
|
||||
/* Node has been traversed already, so backpatch this label into
|
||||
* the code */
|
||||
cCode.code.addLabelBundle (codeIdx, hllLabNum);
|
||||
}
|
||||
cCode.appendCode( "%sgoto L%ld;\n", indentStr(indLevel), hllLabNum);
|
||||
@ -95,7 +89,7 @@ bool LLOperand::isReg() const
|
||||
{
|
||||
return (regi>=rAX) and (regi<=rTMP);
|
||||
}
|
||||
void LLOperand::addProcInformation(int param_count, CConv::CC_Type call_conv)
|
||||
void LLOperand::addProcInformation(int param_count, CConv::Type call_conv)
|
||||
{
|
||||
proc.proc->cbParam = (int16_t)param_count;
|
||||
proc.cb = param_count;
|
||||
|
||||
@ -124,10 +124,11 @@ void Function::findIdioms()
|
||||
/* Check for library functions that return a long register.
|
||||
* Propagate this result */
|
||||
if (pIcode->ll()->src().proc.proc != nullptr)
|
||||
if ( pIcode->ll()->src().proc.proc->flg & PROC_ISLIB )
|
||||
if ((pIcode->ll()->src().proc.proc->flg & PROC_ISLIB) and
|
||||
(pIcode->ll()->src().proc.proc->flg & PROC_IS_FUNC))
|
||||
{
|
||||
if ((pIcode->ll()->src().proc.proc->getReturnType()==TYPE_LONG_SIGN)
|
||||
or (pIcode->ll()->src().proc.proc->getReturnType() == TYPE_LONG_UNSIGN))
|
||||
if ((pIcode->ll()->src().proc.proc->retVal.type==TYPE_LONG_SIGN)
|
||||
or (pIcode->ll()->src().proc.proc->retVal.type == TYPE_LONG_UNSIGN))
|
||||
localId.newLongReg(TYPE_LONG_SIGN, LONGID_TYPE(rDX,rAX), pIcode/*ip*/);
|
||||
}
|
||||
|
||||
@ -187,7 +188,7 @@ void Function::findIdioms()
|
||||
(pIcode++)->invalidate();
|
||||
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
|
||||
{
|
||||
flg |= (PROC_HLL | PROC_IS_HLL);
|
||||
@ -212,12 +213,12 @@ void Function::findIdioms()
|
||||
/* Check if number of parameter bytes match their calling convention */
|
||||
if ((flg & PROC_HLL) and (not args.empty()))
|
||||
{
|
||||
args.m_minOff += (flg & PROC_FAR ? 4 : 2);
|
||||
delta = args.m_maxOff - args.m_minOff;
|
||||
args.m_minOff += ((flg & PROC_FAR)!=0 ? 4 : 2);
|
||||
delta = args.maxOff - args.m_minOff;
|
||||
if (cbParam != delta)
|
||||
{
|
||||
cbParam = delta;
|
||||
callingConv(CConv::UNKNOWN);
|
||||
callingConv(CConv::eUnknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,7 +238,7 @@ void Function::bindIcodeOff()
|
||||
for(ICODE &c : Icode) // TODO: use filtered here
|
||||
{
|
||||
LLInst *ll=c.ll();
|
||||
if (ll->srcIsImmed() and ll->isJmpInst())
|
||||
if (ll->testFlags(I) and ll->isJmpInst())
|
||||
{
|
||||
iICODE loc=Icode.labelSrch(ll->src().getImm2());
|
||||
if (loc!=Icode.end())
|
||||
@ -254,7 +255,7 @@ void Function::bindIcodeOff()
|
||||
LLInst *ll=icode.ll();
|
||||
if (not ll->isJmpInst())
|
||||
continue;
|
||||
if (ll->srcIsImmed())
|
||||
if (ll->testFlags(I) )
|
||||
{
|
||||
uint32_t found;
|
||||
if (not Icode.labelSrch(ll->src().getImm2(), found))
|
||||
|
||||
@ -80,17 +80,17 @@ int Idiom6::action()
|
||||
/*****************************************************************************
|
||||
* idiom 18: Post-increment or post-decrement in a conditional jump
|
||||
* Used
|
||||
* 0 MOV reg, var (including register variables)
|
||||
* 1 INC var or DEC var <------------------------- input point
|
||||
* 2 CMP var, Y
|
||||
* 3 JX label
|
||||
* => HLI_JCOND (var++ X Y)
|
||||
* Eg: MOV ax, si
|
||||
* INC si
|
||||
* CMP ax, 8
|
||||
* JL labX
|
||||
* => HLI_JCOND (si++ < 8)
|
||||
* Found in Borland Turbo C. Intrinsic to C languages.
|
||||
* 0 MOV reg, var (including register variables)
|
||||
* 1 INC var or DEC var <------------------------- input point
|
||||
* 2 CMP var, Y
|
||||
* 3 JX label
|
||||
* => HLI_JCOND (var++ X Y)
|
||||
* Eg: MOV ax, si
|
||||
* INC si
|
||||
* CMP ax, 8
|
||||
* JL labX
|
||||
* => HLI_JCOND (si++ < 8)
|
||||
* Found in Borland Turbo C. Intrinsic to C languages.
|
||||
****************************************************************************/
|
||||
bool Idiom18::match(iICODE picode)
|
||||
{
|
||||
@ -106,7 +106,7 @@ bool Idiom18::match(iICODE picode)
|
||||
m_idiom_type=-1;
|
||||
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) )
|
||||
return false;
|
||||
regi = m_icodes[0]->ll()->m_dst.regi;
|
||||
@ -115,12 +115,12 @@ bool Idiom18::match(iICODE picode)
|
||||
return false;
|
||||
// Simple matching finished, select apropriate matcher based on dst type
|
||||
/* 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 */
|
||||
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;
|
||||
// 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))
|
||||
// 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;
|
||||
else /* indexed */
|
||||
else /* indexed */
|
||||
{
|
||||
m_idiom_type=3;
|
||||
/* not supported yet */
|
||||
@ -147,13 +147,13 @@ bool Idiom18::match(iICODE picode)
|
||||
break;
|
||||
case 1: /* register variable */
|
||||
/* Check previous instruction for a MOV */
|
||||
if ( (m_icodes[0]->ll()->src().regi == m_icodes[1]->ll()->m_dst.regi))
|
||||
if ( m_icodes[0]->ll()->src().regi == m_icodes[1]->ll()->m_dst.regi)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 2: /* local */
|
||||
if ((m_icodes[0]->ll()->src().off == m_icodes[1]->ll()->m_dst.off))
|
||||
if (m_icodes[0]->ll()->src().off == m_icodes[1]->ll()->m_dst.off)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -187,13 +187,13 @@ int Idiom18::action() // action length
|
||||
|
||||
/*****************************************************************************
|
||||
* idiom 19: pre-increment or pre-decrement in conditional jump, comparing against 0.
|
||||
* [INC | DEC] var (including register vars)
|
||||
* JX lab JX lab
|
||||
* => HLI_JCOND (++var X 0) or HLI_JCOND (--var X 0)
|
||||
* Eg: INC [bp+4]
|
||||
* [INC | DEC] var (including register vars)
|
||||
* JX lab JX lab
|
||||
* => HLI_JCOND (++var X 0) or HLI_JCOND (--var X 0)
|
||||
* Eg: INC [bp+4]
|
||||
* JG lab2
|
||||
* => HLI_JCOND (++[bp+4] > 0)
|
||||
* Found in Borland Turbo C. Intrinsic to C language.
|
||||
* => HLI_JCOND (++[bp+4] > 0)
|
||||
* Found in Borland Turbo C. Intrinsic to C language.
|
||||
****************************************************************************/
|
||||
bool Idiom19::match(iICODE picode)
|
||||
{
|
||||
@ -206,7 +206,7 @@ bool Idiom19::match(iICODE picode)
|
||||
m_is_dec = m_icodes[0]->ll()->match(iDEC);
|
||||
if ( not m_icodes[1]->ll()->conditionalJump() )
|
||||
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 */ ;
|
||||
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)))
|
||||
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;
|
||||
}
|
||||
else /* indexed */
|
||||
else /* indexed */
|
||||
{
|
||||
fprintf(stderr,"idiom19 : Untested type [indexed]\n");
|
||||
return true;
|
||||
@ -241,23 +241,23 @@ int Idiom19::action()
|
||||
|
||||
/*****************************************************************************
|
||||
* idiom20: Pre increment/decrement in conditional expression (compares
|
||||
* against a register, variable or constant different than 0).
|
||||
* INC var or DEC var (including register vars)
|
||||
* MOV reg, var MOV reg, var
|
||||
* CMP reg, Y CMP reg, Y
|
||||
* JX lab JX lab
|
||||
* => HLI_JCOND (++var X Y) or HLI_JCOND (--var X Y)
|
||||
* Eg: INC si (si is a register variable)
|
||||
* MOV ax, si
|
||||
* CMP ax, 2
|
||||
* JL lab4
|
||||
* => HLI_JCOND (++si < 2)
|
||||
* Found in Turbo C. Intrinsic to C language.
|
||||
* against a register, variable or constant different than 0).
|
||||
* INC var or DEC var (including register vars)
|
||||
* MOV reg, var MOV reg, var
|
||||
* CMP reg, Y CMP reg, Y
|
||||
* JX lab JX lab
|
||||
* => HLI_JCOND (++var X Y) or HLI_JCOND (--var X Y)
|
||||
* Eg: INC si (si is a register variable)
|
||||
* MOV ax, si
|
||||
* CMP ax, 2
|
||||
* JL lab4
|
||||
* => HLI_JCOND (++si < 2)
|
||||
* Found in Turbo C. Intrinsic to C language.
|
||||
****************************************************************************/
|
||||
bool Idiom20::match(iICODE picode)
|
||||
{
|
||||
uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
|
||||
uint8_t regi; /* register of the MOV */
|
||||
uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
|
||||
uint8_t regi; /* register of the MOV */
|
||||
if(std::distance(picode,m_end)<4)
|
||||
return false;
|
||||
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);
|
||||
/* Get variable */
|
||||
if (ll_dest.regi == 0) /* global variable */
|
||||
if (ll_dest.regi == 0) /* global variable */
|
||||
{
|
||||
/* not supported yet */ ;
|
||||
}
|
||||
else if ( ll_dest.isReg() ) /* register */
|
||||
else if ( ll_dest.isReg() ) /* register */
|
||||
{
|
||||
type = 1;
|
||||
// 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))
|
||||
// type = 1;
|
||||
}
|
||||
else if (ll_dest.off) /* local variable */
|
||||
else if (ll_dest.off) /* local variable */
|
||||
type = 2;
|
||||
else /* indexed */
|
||||
else /* indexed */
|
||||
{
|
||||
printf("idiom20 : Untested type [indexed]\n");
|
||||
type = 3;
|
||||
|
||||
@ -11,9 +11,9 @@ using namespace std;
|
||||
* Eg: CALL proc_X
|
||||
* ADD SP, 6
|
||||
* => pProc->cbParam = immed
|
||||
* Special case: when the call is at the end of the procedure,
|
||||
* sometimes the stack gets restored by a MOV sp, bp.
|
||||
* Need to flag the procedure in these cases.
|
||||
* Special case: when the call is at the end of the procedure,
|
||||
* sometimes the stack gets restored by a MOV sp, bp.
|
||||
* Need to flag the procedure in these cases.
|
||||
* Used by compilers to restore the stack when invoking a procedure using
|
||||
* the C calling convention.
|
||||
****************************************************************************/
|
||||
@ -25,7 +25,7 @@ bool Idiom3::match(iICODE picode)
|
||||
/* Match ADD SP, immed */
|
||||
for(int i=0; i<2; ++i)
|
||||
m_icodes[i] = picode++;
|
||||
if ( m_icodes[1]->ll()->srcIsImmed() and m_icodes[1]->ll()->match(iADD,rSP))
|
||||
if ( m_icodes[1]->ll()->testFlags(I) and m_icodes[1]->ll()->match(iADD,rSP))
|
||||
{
|
||||
m_param_count = m_icodes[1]->ll()->src().getImm2();
|
||||
return true;
|
||||
@ -39,9 +39,9 @@ bool Idiom3::match(iICODE picode)
|
||||
}
|
||||
int Idiom3::action()
|
||||
{
|
||||
if (m_icodes[0]->ll()->srcIsImmed())
|
||||
if (m_icodes[0]->ll()->testFlags(I) )
|
||||
{
|
||||
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
|
||||
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::eCdecl);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -97,9 +97,9 @@ bool Idiom17::match(iICODE picode)
|
||||
}
|
||||
int Idiom17::action()
|
||||
{
|
||||
if (m_icodes[0]->ll()->srcIsImmed())
|
||||
if (m_icodes[0]->ll()->testFlags(I))
|
||||
{
|
||||
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::C);
|
||||
m_icodes[0]->ll()->src().addProcInformation(m_param_count,CConv::eCdecl);
|
||||
for(size_t idx=1; idx<m_icodes.size(); ++idx)
|
||||
{
|
||||
m_icodes[idx]->invalidate();
|
||||
|
||||
@ -48,7 +48,7 @@ bool Idiom2::match(iICODE pIcode)
|
||||
iICODE nicode;
|
||||
if(pIcode==m_func->Icode.begin()) // pIcode->loc_ip == 0
|
||||
return false;
|
||||
if ( pIcode->ll()->srcIsImmed() or (not pIcode->ll()->match(rSP,rBP)) )
|
||||
if ( pIcode->ll()->testFlags(I) or (not pIcode->ll()->match(rSP,rBP)) )
|
||||
return false;
|
||||
if(distance(pIcode,m_end)<3)
|
||||
return false;
|
||||
@ -63,7 +63,7 @@ bool Idiom2::match(iICODE pIcode)
|
||||
}
|
||||
if(nicode == m_end)
|
||||
return false;
|
||||
//TODO: strange test here - 'I' means instruction has immediate source operand
|
||||
|
||||
if (nicode->ll()->match(iPOP,rBP) and not (nicode->ll()->testFlags(I | TARGET | CASE)) )
|
||||
{
|
||||
m_icodes.push_back(nicode++); // Matched POP BP
|
||||
@ -71,7 +71,7 @@ bool Idiom2::match(iICODE pIcode)
|
||||
/* Match RET(F) */
|
||||
if ( nicode != m_end and
|
||||
not (nicode->ll()->testFlags(I | TARGET | CASE)) and
|
||||
nicode->ll()->matchAny({iRET,iRETF})
|
||||
(nicode->ll()->match(iRET) or nicode->ll()->match(iRETF))
|
||||
)
|
||||
{
|
||||
m_icodes.push_back(nicode); // Matched RET
|
||||
@ -95,15 +95,15 @@ int Idiom2::action()
|
||||
* RET(F) immed
|
||||
* ==> pProc->cbParam = immed
|
||||
* 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 SI]
|
||||
* POP BP
|
||||
* RET(F) [immed]
|
||||
* - Third version: pop stack vars
|
||||
* [POP DI]
|
||||
* [POP SI]
|
||||
* RET(F) [immed]
|
||||
* - Third version: pop stack vars
|
||||
* [POP DI]
|
||||
* [POP SI]
|
||||
* RET(F) [immed]
|
||||
****************************************************************************/
|
||||
bool Idiom4::match(iICODE pIcode)
|
||||
{
|
||||
@ -120,7 +120,7 @@ bool Idiom4::match(iICODE pIcode)
|
||||
{
|
||||
iICODE prev1 = --iICODE(pIcode);
|
||||
/* Check for POP BP */
|
||||
if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->srcIsImmed() )
|
||||
if (prev1->ll()->match(iPOP,rBP) and not prev1->ll()->testFlags(I) )
|
||||
m_icodes.push_back(prev1);
|
||||
else if(prev1!=m_func->Icode.begin())
|
||||
{
|
||||
@ -131,7 +131,7 @@ bool Idiom4::match(iICODE pIcode)
|
||||
}
|
||||
|
||||
/* Check for RET(F) immed */
|
||||
if (pIcode->ll()->srcIsImmed() )
|
||||
if (pIcode->ll()->testFlags(I) )
|
||||
{
|
||||
m_param_count = (int16_t)pIcode->ll()->src().getImm2();
|
||||
return true;
|
||||
@ -148,7 +148,7 @@ int Idiom4::action()
|
||||
if(m_param_count)
|
||||
{
|
||||
m_func->cbParam = (int16_t)m_param_count;
|
||||
m_func->callingConv(CConv::PASCAL);
|
||||
m_func->callingConv(CConv::ePascal);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -53,8 +53,8 @@ int Idiom1::checkStkVars (iICODE pIcode)
|
||||
****************************************************************************/
|
||||
bool Idiom1::match(iICODE picode)
|
||||
{
|
||||
//uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
|
||||
//uint8_t regi; /* register of the MOV */
|
||||
//uint8_t type = 0; /* type of variable: 1 = reg-var, 2 = local */
|
||||
//uint8_t regi; /* register of the MOV */
|
||||
if(m_func->flg & PROC_HLL)
|
||||
return false;
|
||||
if(picode==m_end)
|
||||
@ -63,7 +63,7 @@ bool Idiom1::match(iICODE picode)
|
||||
m_icodes.clear();
|
||||
m_min_off = 0;
|
||||
/* PUSH BP as first instruction of procedure */
|
||||
if ( (not picode->ll()->srcIsImmed()) and picode->ll()->src().regi == rBP)
|
||||
if ( (not picode->ll()->testFlags(I)) and picode->ll()->src().regi == rBP)
|
||||
{
|
||||
m_icodes.push_back( picode++ ); // insert iPUSH
|
||||
if(picode==m_end)
|
||||
@ -109,10 +109,10 @@ bool Idiom1::match(iICODE picode)
|
||||
m_min_off = 2 + (n * 2);
|
||||
}
|
||||
else
|
||||
return false; // Cristina: check this please!
|
||||
return false; // Cristina: check this please!
|
||||
}
|
||||
else
|
||||
return false; // Cristina: check this please!
|
||||
return false; // Cristina: check this please!
|
||||
}
|
||||
}
|
||||
else // push di [push si] / push si [push di]
|
||||
|
||||
@ -12,14 +12,14 @@ using namespace std;
|
||||
* Eg: MOV ax, di
|
||||
* XOR dx, dx
|
||||
* => MOV dx:ax, di
|
||||
* Note: only the following combinations are allowed:
|
||||
* dx:ax
|
||||
* cx:bx
|
||||
* this is to remove the possibility of making errors in situations
|
||||
* like this:
|
||||
* MOV dx, offH
|
||||
* MOV ax, offL
|
||||
* XOR cx, cx
|
||||
* Note: only the following combinations are allowed:
|
||||
* dx:ax
|
||||
* cx:bx
|
||||
* this is to remove the possibility of making errors in situations
|
||||
* like this:
|
||||
* MOV dx, offH
|
||||
* MOV ax, offL
|
||||
* XOR cx, cx
|
||||
* Found in Borland Turbo C, used for division of unsigned integer
|
||||
* operands.
|
||||
****************************************************************************/
|
||||
@ -33,10 +33,10 @@ bool Idiom14::match(iICODE pIcode)
|
||||
LLInst * matched [] {m_icodes[0]->ll(),m_icodes[1]->ll()};
|
||||
/* Check for regL */
|
||||
m_regL = matched[0]->m_dst.regi;
|
||||
if (not matched[0]->srcIsImmed() and ((m_regL == rAX) or (m_regL ==rBX)))
|
||||
if (not matched[0]->testFlags(I) and ((m_regL == rAX) or (m_regL ==rBX)))
|
||||
{
|
||||
/* Check for XOR regH, regH */
|
||||
if (matched[1]->match(iXOR) and not matched[1]->srcIsImmed())
|
||||
if (matched[1]->match(iXOR) and not matched[1]->testFlags(I))
|
||||
{
|
||||
m_regH = matched[1]->m_dst.regi;
|
||||
if (m_regH == matched[1]->src().getReg2())
|
||||
@ -84,7 +84,7 @@ bool Idiom13::match(iICODE pIcode)
|
||||
|
||||
/* Check for regL */
|
||||
regi = m_icodes[0]->ll()->m_dst.regi;
|
||||
if (not m_icodes[0]->ll()->srcIsImmed() and (regi >= rAL) and (regi <= rBH))
|
||||
if (not m_icodes[0]->ll()->testFlags(I) and (regi >= rAL) and (regi <= rBH))
|
||||
{
|
||||
/* Check for MOV regH, 0 */
|
||||
if (m_icodes[1]->ll()->match(iMOV,I) and (m_icodes[1]->ll()->src().getImm2() == 0))
|
||||
|
||||
@ -67,15 +67,15 @@ int Idiom11::action()
|
||||
|
||||
/*****************************************************************************
|
||||
* idiom 16: Bitwise negation
|
||||
* NEG reg
|
||||
* SBB reg, reg
|
||||
* INC reg
|
||||
* => ASGN reg, !reg
|
||||
* Eg: NEG ax
|
||||
* SBB ax, ax
|
||||
* INC ax
|
||||
* => ax = !ax
|
||||
* Found in Borland Turbo C when negating bitwise.
|
||||
* NEG reg
|
||||
* SBB reg, reg
|
||||
* INC reg
|
||||
* => ASGN reg, !reg
|
||||
* Eg: NEG ax
|
||||
* SBB ax, ax
|
||||
* INC ax
|
||||
* => ax = !ax
|
||||
* Found in Borland Turbo C when negating bitwise.
|
||||
****************************************************************************/
|
||||
bool Idiom16::match (iICODE picode)
|
||||
{
|
||||
|
||||
@ -21,7 +21,7 @@ bool Idiom8::match(iICODE pIcode)
|
||||
return false;
|
||||
m_icodes[0]=pIcode++;
|
||||
m_icodes[1]=pIcode++;
|
||||
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if ( m_icodes[1]->ll()->match(iRCR,I) and
|
||||
(m_icodes[1]->ll()->src().getImm2() == 1))
|
||||
return true;
|
||||
@ -65,7 +65,7 @@ bool Idiom15::match(iICODE pIcode)
|
||||
if(distance(pIcode,m_end)<2)
|
||||
return false;
|
||||
/* Match SHL reg, 1 */
|
||||
if (not pIcode->ll()->srcIsImmed() or (pIcode->ll()->src().getImm2() != 1))
|
||||
if (not pIcode->ll()->testFlags(I) or (pIcode->ll()->src().getImm2() != 1))
|
||||
return false;
|
||||
m_icodes.clear();
|
||||
regi = pIcode->ll()->m_dst.regi;
|
||||
@ -110,7 +110,7 @@ bool Idiom12::match(iICODE pIcode)
|
||||
return false;
|
||||
m_icodes[0]=pIcode++;
|
||||
m_icodes[1]=pIcode++;
|
||||
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if (m_icodes[1]->ll()->match(iRCL,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
|
||||
return true;
|
||||
return false;
|
||||
@ -150,7 +150,7 @@ bool Idiom9::match(iICODE pIcode)
|
||||
return false;
|
||||
m_icodes[0]=pIcode++;
|
||||
m_icodes[1]=pIcode++;
|
||||
if (m_icodes[0]->ll()->srcIsImmed() and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if (m_icodes[0]->ll()->testFlags(I) and (m_icodes[0]->ll()->src().getImm2() == 1))
|
||||
if (m_icodes[1]->ll()->match(iRCR,I) and (m_icodes[1]->ll()->src().getImm2() == 1))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
@ -7,16 +7,16 @@ using namespace std;
|
||||
|
||||
/*****************************************************************************
|
||||
* idiom21 - Assign long kte with high part zero
|
||||
* XOR regH, regH
|
||||
* MOV regL, kte
|
||||
* => regH:regL = kte
|
||||
* Eg: XOR dx, dx
|
||||
* MOV ax, 3
|
||||
* => dx:ax = 3
|
||||
* Note: only the following valid combinations are available:
|
||||
* dx:ax
|
||||
* cx:bx
|
||||
* Found in Borland Turbo C code.
|
||||
* XOR regH, regH
|
||||
* MOV regL, kte
|
||||
* => regH:regL = kte
|
||||
* Eg: XOR dx, dx
|
||||
* MOV ax, 3
|
||||
* => dx:ax = 3
|
||||
* Note: only the following valid combinations are available:
|
||||
* dx:ax
|
||||
* cx:bx
|
||||
* Found in Borland Turbo C code.
|
||||
****************************************************************************/
|
||||
bool Idiom21::match (iICODE picode)
|
||||
{
|
||||
@ -26,7 +26,7 @@ bool Idiom21::match (iICODE picode)
|
||||
m_icodes[0]=picode++;
|
||||
m_icodes[1]=picode++;
|
||||
|
||||
if (not m_icodes[1]->ll()->srcIsImmed())
|
||||
if (not m_icodes[1]->ll()->testFlags(I))
|
||||
return false;
|
||||
|
||||
dst = &m_icodes[0]->ll()->m_dst;
|
||||
@ -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());
|
||||
rhs = new Constant(m_icodes[1]->ll()->src().getImm2(), 4);
|
||||
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();
|
||||
return 2;
|
||||
}
|
||||
@ -87,8 +87,8 @@ bool Idiom7::match(iICODE picode)
|
||||
}
|
||||
int Idiom7::action()
|
||||
{
|
||||
Expr *lhs = AstIdent::id (*m_icode->ll(), DST, m_func, m_icode, *m_icode, NONE);
|
||||
|
||||
Expr *lhs;
|
||||
lhs = AstIdent::id (*m_icode->ll(), DST, m_func, m_icode, *m_icode, NONE);
|
||||
m_icode->setAsgn(dynamic_cast<AstIdent *>(lhs), new Constant(0, 2));
|
||||
m_icode->du.use.reset(); /* clear register used in iXOR */
|
||||
m_icode->ll()->setFlags(I);
|
||||
@ -103,11 +103,11 @@ int Idiom7::action()
|
||||
* Eg: OR ax, ax
|
||||
* JNE labX
|
||||
* => CMP reg 0
|
||||
* JNE labX
|
||||
* This instruction is NOT converted into the equivalent high-level
|
||||
* 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
|
||||
* modified to simplify the analysis.
|
||||
* JNE labX
|
||||
* This instruction is NOT converted into the equivalent high-level
|
||||
* 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
|
||||
* modified to simplify the analysis.
|
||||
* Found in Borland Turbo C.
|
||||
****************************************************************************/
|
||||
bool Idiom10::match(iICODE pIcode)
|
||||
@ -117,7 +117,7 @@ bool Idiom10::match(iICODE pIcode)
|
||||
m_icodes[0]=pIcode++;
|
||||
m_icodes[1]=pIcode++;
|
||||
/* Check OR reg, reg */
|
||||
if (not m_icodes[0]->ll()->srcIsImmed() and
|
||||
if (not m_icodes[0]->ll()->testFlags(I) and
|
||||
m_icodes[0]->ll()->src().isReg() and
|
||||
(m_icodes[0]->ll()->src().getReg2() == m_icodes[0]->ll()->m_dst.getReg2()))
|
||||
if (m_icodes[1]->ll()->match(iJNE)) //.conditionalJump()
|
||||
|
||||
168
src/locident.cpp
168
src/locident.cpp
@ -10,6 +10,11 @@
|
||||
#include "msvc_fixes.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
static const int LOCAL_ID_DELTA = 25;
|
||||
static const int IDX_ARRAY_DELTA = 5;
|
||||
|
||||
|
||||
bool LONGID_TYPE::srcDstRegMatch(iICODE a, iICODE b) const
|
||||
{
|
||||
@ -54,9 +59,14 @@ ID::ID(hlType t, const LONGGLB_TYPE &s) : type(t),illegal(false)
|
||||
assert((t==TYPE_LONG_SIGN) or (t==TYPE_LONG_UNSIGN));
|
||||
}
|
||||
|
||||
eReg ID::getPairedRegister(eReg first) const {
|
||||
if (longId().h() == first)
|
||||
return (longId().l());
|
||||
else if (longId().l() == first)
|
||||
return (longId().h());
|
||||
return rUNDEF;
|
||||
}
|
||||
|
||||
#define LOCAL_ID_DELTA 25
|
||||
#define IDX_ARRAY_DELTA 5
|
||||
|
||||
/* Creates a new identifier node of type t and returns it.
|
||||
* Arguments: locSym : local long symbol table
|
||||
@ -65,8 +75,7 @@ ID::ID(hlType t, const LONGGLB_TYPE &s) : type(t),illegal(false)
|
||||
* ix : index into icode array where this var is used */
|
||||
void LOCAL_ID::newIdent(hlType t, frameType f)
|
||||
{
|
||||
ID newid(t,f);
|
||||
id_arr.push_back(newid);
|
||||
id_arr.emplace_back(t,f);
|
||||
}
|
||||
|
||||
|
||||
@ -74,19 +83,16 @@ void LOCAL_ID::newIdent(hlType t, frameType f)
|
||||
* TYPE_WORD_(UN)SIGN type. Returns the index to this new entry. */
|
||||
int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/* Check for entry in the table */
|
||||
auto found=std::find_if(id_arr.begin(),id_arr.end(),[t,regi](ID &el)->bool {
|
||||
return ((el.type == t) and (el.id.regi == regi));
|
||||
});
|
||||
return ((el.type == t) and (el.id.regi == regi));
|
||||
});
|
||||
if(found!=id_arr.end())
|
||||
return found-id_arr.begin();
|
||||
/* Not in table, create new identifier */
|
||||
newIdent (t, REG_FRAME);
|
||||
idx = id_arr.size() - 1;
|
||||
id_arr[idx].id.regi = regi;
|
||||
return (idx);
|
||||
id_arr.back().id.regi = regi;
|
||||
return id_arr.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
@ -99,11 +105,8 @@ int LOCAL_ID::newByteWordReg(hlType t, eReg regi)
|
||||
void LOCAL_ID::flagByteWordId (int off)
|
||||
{
|
||||
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off](ID &en)->bool {
|
||||
//if (((en.type == TYPE_WORD_SIGN) or (en.type == TYPE_BYTE_SIGN)) and
|
||||
if ((en.typeBitsize()<=16) and
|
||||
(en.id.bwId.off == off) and (en.id.bwId.regOff == 0))
|
||||
return true;
|
||||
return false;
|
||||
//if (((en.type == TYPE_WORD_SIGN) or (en.type == TYPE_BYTE_SIGN)) and
|
||||
return ((en.typeBitsize()<=16) and (en.id.bwId.off == off) and (en.id.bwId.regOff == 0));
|
||||
});
|
||||
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. */
|
||||
int LOCAL_ID::newByteWordStk(hlType t, int off, uint8_t regOff)
|
||||
{
|
||||
int idx;
|
||||
|
||||
/* Check for entry in the table */
|
||||
auto found=std::find_if(id_arr.begin(),id_arr.end(),[off,regOff](ID &el)->bool {
|
||||
if ((el.id.bwId.off == off) and (el.id.bwId.regOff == regOff))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if ((el.id.bwId.off == off) and (el.id.bwId.regOff == regOff))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
if(found!=id_arr.end())
|
||||
return found-id_arr.begin(); //return Index to found element
|
||||
|
||||
/* Not in table, create new identifier */
|
||||
newIdent (t, STK_FRAME);
|
||||
idx = id_arr.size() - 1;
|
||||
id_arr[idx].id.bwId.regOff = regOff;
|
||||
id_arr[idx].id.bwId.off = off;
|
||||
return (idx);
|
||||
ID &last_id(id_arr.back());
|
||||
last_id.id.bwId.regOff = regOff;
|
||||
last_id.id.bwId.off = off;
|
||||
return id_arr.size()-1;
|
||||
}
|
||||
|
||||
|
||||
@ -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++)
|
||||
{
|
||||
if (/*(locSym->id[idx].type == t) and Not checking type */
|
||||
(id_arr[idx].id.bwGlb.seg == seg) and
|
||||
(id_arr[idx].id.bwGlb.off == off) and
|
||||
(id_arr[idx].id.bwGlb.regi == regi))
|
||||
(id_arr[idx].id.bwGlb.seg == seg) and
|
||||
(id_arr[idx].id.bwGlb.off == off) and
|
||||
(id_arr[idx].id.bwGlb.regi == regi))
|
||||
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++)
|
||||
{
|
||||
ID &entry(id_arr[idx]);
|
||||
if(not entry.isLong() or (entry.loc != REG_FRAME))
|
||||
if(not entry.isLongRegisterPair())
|
||||
continue;
|
||||
if (/*(locSym->id[idx].type == t) and Not checking type */
|
||||
(entry.longId().h() == regH) and
|
||||
@ -189,23 +190,22 @@ int LOCAL_ID::newLongReg(hlType t, const LONGID_TYPE &longT, iICODE ix_)
|
||||
{
|
||||
/* Check for occurrence in the list */
|
||||
if (entry.idx.inList(ix_))
|
||||
return (idx);
|
||||
return idx;
|
||||
else
|
||||
{
|
||||
/* Insert icode index in list */
|
||||
entry.idx.push_back(ix_);
|
||||
return (idx);
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not in the table, create new identifier */
|
||||
id_arr.push_back(ID(t, LONGID_TYPE(regH,regL)));
|
||||
id_arr.emplace_back(t, LONGID_TYPE(regH,regL));
|
||||
id_arr.back().idx.push_back(ix_);
|
||||
return (id_arr.size() - 1);
|
||||
}
|
||||
/** Returns an identifier conditional expression node of type TYPE_LONG or
|
||||
* TYPE_WORD_SIGN */
|
||||
/** \returns an identifier conditional expression node of type TYPE_LONG or TYPE_WORD_SIGN */
|
||||
AstIdent * LOCAL_ID::createId(const ID *retVal, iICODE ix_)
|
||||
{
|
||||
return AstIdent::idID(retVal,this,ix_);
|
||||
@ -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++)
|
||||
{
|
||||
if (/*(locSym->id[idx].type == t) and Not checking type */
|
||||
(id_arr[idx].id.longGlb.seg == seg) and
|
||||
(id_arr[idx].id.longGlb.offH == offH) and
|
||||
(id_arr[idx].id.longGlb.offL == offL))
|
||||
(id_arr[idx].id.longGlb.seg == seg) and
|
||||
(id_arr[idx].id.longGlb.offH == offH) and
|
||||
(id_arr[idx].id.longGlb.offL == offL))
|
||||
return (idx);
|
||||
}
|
||||
printf("%d",t);
|
||||
/* Not in the table, create new identifier */
|
||||
id_arr.push_back(ID(t, LONGGLB_TYPE(seg,offH,offL)));
|
||||
return (id_arr.size() - 1);
|
||||
id_arr.emplace_back(t, LONGGLB_TYPE(seg,offH,offL));
|
||||
return id_arr.size() - 1;
|
||||
|
||||
}
|
||||
|
||||
@ -240,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. */
|
||||
int LOCAL_ID::newLongIdx( int16_t seg, int16_t offH, int16_t offL,uint8_t regi, hlType t)
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
/* Check for entry in the table */
|
||||
for (idx = 0; idx < id_arr.size(); idx++)
|
||||
for (size_t idx = 0; idx < id_arr.size(); idx++)
|
||||
{
|
||||
if (/*(locSym->id[idx].type == t) and Not checking type */
|
||||
(id_arr[idx].id.longGlb.seg == seg) and
|
||||
(id_arr[idx].id.longGlb.offH == offH) and
|
||||
(id_arr[idx].id.longGlb.offL == offL) and
|
||||
(id_arr[idx].id.longGlb.regi == regi))
|
||||
(id_arr[idx].id.longGlb.seg == seg) and
|
||||
(id_arr[idx].id.longGlb.offH == offH) and
|
||||
(id_arr[idx].id.longGlb.offL == offL) and
|
||||
(id_arr[idx].id.longGlb.regi == regi))
|
||||
return (idx);
|
||||
}
|
||||
|
||||
/* Not in the table, create new identifier */
|
||||
id_arr.push_back(ID(t,LONGGLB_TYPE(seg,offH,offL,regi)));
|
||||
idx = id_arr.size() - 1;
|
||||
return (idx);
|
||||
id_arr.emplace_back(t,LONGGLB_TYPE(seg,offH,offL,regi));
|
||||
return id_arr.size() - 1;
|
||||
}
|
||||
|
||||
|
||||
@ -272,8 +269,8 @@ int LOCAL_ID::newLongStk(hlType t, int offH, int offL)
|
||||
if(id_arr[idx].loc!=STK_FRAME)
|
||||
continue;
|
||||
if ((id_arr[idx].type == t) and
|
||||
(id_arr[idx].longStkId().offH == offH) and
|
||||
(id_arr[idx].longStkId().offL == offL))
|
||||
(id_arr[idx].longStkId().offH == offH) and
|
||||
(id_arr[idx].longStkId().offL == offL))
|
||||
return (idx);
|
||||
}
|
||||
|
||||
@ -282,7 +279,7 @@ int LOCAL_ID::newLongStk(hlType t, int offH, int offL)
|
||||
flagByteWordId (offL);
|
||||
|
||||
/* Create new identifier */
|
||||
id_arr.push_back(ID(t,LONG_STKID_TYPE(offH,offL)));
|
||||
id_arr.emplace_back(t,LONG_STKID_TYPE(offH,offL));
|
||||
return (id_arr.size() - 1);
|
||||
}
|
||||
|
||||
@ -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!
|
||||
const LLOperand *pmH, *pmL;
|
||||
LLInst &p_ll(*pIcode->ll());
|
||||
LLInst &p_ll(*pIcode->ll());
|
||||
if (f == LOW_FIRST)
|
||||
{
|
||||
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 */
|
||||
printf ("long not supported, idx and no off\n");
|
||||
|
||||
return (idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
@ -356,22 +353,22 @@ bool checkLongEq (LONG_STKID_TYPE longId, iICODE pIcode, int i, Function * pProc
|
||||
pmLdst = &atOffset.m_dst;
|
||||
pmHsrc = &pIcode->ll()->src();
|
||||
pmLsrc = &atOffset.src();
|
||||
// if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off))
|
||||
// {
|
||||
// asgn.lhs = AstIdent::LongIdx (i);
|
||||
// if ((longId.offH == pmHsrc->off) and (longId.offL == pmLsrc->off))
|
||||
// {
|
||||
// asgn.lhs = AstIdent::LongIdx (i);
|
||||
|
||||
// if ( not pIcode->ll()->testFlags(NO_SRC) )
|
||||
// {
|
||||
// asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// else if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
|
||||
// {
|
||||
// asgn.lhs = AstIdent::Long (&pProc->localId, DST, pIcode, HIGH_FIRST, pIcode,eDEF, atOffset);
|
||||
// asgn.rhs = AstIdent::LongIdx (i);
|
||||
// return true;
|
||||
// }
|
||||
// if ( not pIcode->ll()->testFlags(NO_SRC) )
|
||||
// {
|
||||
// asgn.rhs = AstIdent::Long (&pProc->localId, SRC, pIcode, HIGH_FIRST, pIcode, eUSE, atOffset);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
// else if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
|
||||
// {
|
||||
// asgn.lhs = AstIdent::Long (&pProc->localId, DST, pIcode, HIGH_FIRST, pIcode,eDEF, atOffset);
|
||||
// asgn.rhs = AstIdent::LongIdx (i);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if ((longId.offH == pmHdst->off) and (longId.offL == pmLdst->off))
|
||||
{
|
||||
@ -403,7 +400,7 @@ bool checkLongEq (LONG_STKID_TYPE longId, iICODE pIcode, int i, Function * pProc
|
||||
* pProc : ptr to current procedure record
|
||||
* rhs, lhs : return expressions if successful. */
|
||||
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 */
|
||||
const LLOperand *pmHdst, *pmLdst, *pmHsrc, *pmLsrc;
|
||||
@ -431,33 +428,26 @@ bool checkLongRegEq (LONGID_TYPE longId, iICODE pIcode, int i,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Given an index into the local identifier table for a long register
|
||||
* variable, determines whether regi is the high or low part, and returns
|
||||
* the other part */
|
||||
eReg otherLongRegi (eReg regi, int idx, LOCAL_ID *locTbl)
|
||||
eReg LOCAL_ID::getPairedRegisterAt(int idx,eReg regi) const
|
||||
{
|
||||
ID *id;
|
||||
|
||||
id = &locTbl->id_arr[idx];
|
||||
if ((id->loc == REG_FRAME) and ((id->type == TYPE_LONG_SIGN) or
|
||||
(id->type == TYPE_LONG_UNSIGN)))
|
||||
eReg res=rUNDEF; // Cristina: please check this!
|
||||
const ID *id = &id_arr[idx];
|
||||
if (id->isLongRegisterPair())
|
||||
{
|
||||
if (id->longId().h() == regi)
|
||||
return (id->longId().l());
|
||||
else if (id->longId().l() == regi)
|
||||
return (id->longId().h());
|
||||
res = id->getPairedRegister(regi);
|
||||
}
|
||||
return rUNDEF; // Cristina: please check this!
|
||||
qWarning() << "Cannot find paired register";
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the registers regL and regH have been used independently in
|
||||
/* Checks if the registers regL and regH have been used independently in
|
||||
* the local identifier table. If so, macros for these registers are
|
||||
* placed in the local identifier table, as these registers belong to a
|
||||
* long register identifier. */
|
||||
* long register identifier. */
|
||||
void LOCAL_ID::propLongId (uint8_t regL, uint8_t regH, const QString &name)
|
||||
{
|
||||
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)
|
||||
{
|
||||
strcpy (rid.macro, "LO");
|
||||
}
|
||||
}
|
||||
else // if (rid.id.regi == regH)
|
||||
{
|
||||
{
|
||||
strcpy (rid.macro, "HI");
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ static const QString szOps[] =
|
||||
"RCL", "RCR", "ROL", "ROR", "RET", "RETF", "SAHF", "SAR",
|
||||
"SHL", "SHR", "SBB", "SCAS", "REPNE SCAS","REPE SCAS", "CWD", "STC",
|
||||
"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 */
|
||||
static const QString szFlops1[] =
|
||||
|
||||
569
src/parser.cpp
569
src/parser.cpp
@ -2,40 +2,30 @@
|
||||
* dcc project procedure list builder
|
||||
* (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
|
||||
****************************************************************************/
|
||||
#include "parser.h"
|
||||
|
||||
#include "dcc.h"
|
||||
#include "project.h"
|
||||
#include "CallGraph.h"
|
||||
#include "msvc_fixes.h"
|
||||
#include "chklib.h"
|
||||
#include "FollowControlFlow.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> /* For exit() */
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <QMap>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
//TODO: The OS service resolution should be done iteratively:
|
||||
// for every unprocessed INT instruction, that calls OS service that does not terminate execution
|
||||
// mark INT as non-termination instruction
|
||||
// follow execution flow from next instruction
|
||||
// recheck OS services
|
||||
#include <inttypes.h>
|
||||
#include <cstring>
|
||||
#include <cstdlib> /* For exit() */
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//static void FollowCtrl (Function * pProc, CALL_GRAPH * pcallGraph, STATE * pstate);
|
||||
static void setBits(int16_t type, uint32_t start, uint32_t len);
|
||||
static void process_MOV(LLInst &ll, STATE * pstate);
|
||||
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph);
|
||||
static bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate);
|
||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||
//void interactDis(Function * initProc, int ic);
|
||||
static SYM * lookupAddr (LLOperand *pm, STATE * pstate, int size, uint16_t duFlag);
|
||||
void interactDis(Function * initProc, int ic);
|
||||
extern uint32_t SynthLab;
|
||||
|
||||
|
||||
/* Returns the size of the string pointed by sym and delimited by delim.
|
||||
* Size includes delimiter. */
|
||||
@ -46,158 +36,106 @@ int strSize (const uint8_t *sym, char delim)
|
||||
const uint8_t *end_ptr=std::find(sym,sym+(prog.cbImage-(till_end)),delim);
|
||||
return end_ptr-sym+1;
|
||||
}
|
||||
|
||||
static std::vector<ICODE> rewrite_DIV(LLInst *ll, ICODE &_Icode)
|
||||
ICODE * Function::translate_DIV(LLInst *ll, ICODE &_Icode)
|
||||
{
|
||||
ICODE synth_mov = ICODE(); // MOV rTMP, reg
|
||||
ICODE synth_mod = ICODE(); // MOD
|
||||
/* MOV rTMP, reg */
|
||||
|
||||
synth_mov.type = LOW_LEVEL_ICODE;
|
||||
synth_mov.ll()->set(iMOV,0,rTMP);
|
||||
ICODE eIcode = ICODE();
|
||||
|
||||
eIcode.type = LOW_LEVEL_ICODE;
|
||||
eIcode.ll()->set(iMOV,0,rTMP);
|
||||
if (ll->testFlags(B) )
|
||||
{
|
||||
synth_mov.ll()->setFlags( B );
|
||||
synth_mov.ll()->replaceSrc(rAX);
|
||||
eIcode.ll()->setFlags( B );
|
||||
eIcode.ll()->replaceSrc(rAX);
|
||||
}
|
||||
else /* implicit dx:ax */
|
||||
{
|
||||
synth_mov.ll()->setFlags( IM_SRC );
|
||||
synth_mov.setRegDU( rDX, eUSE);
|
||||
eIcode.ll()->setFlags( IM_SRC );
|
||||
eIcode.setRegDU( rDX, eUSE);
|
||||
}
|
||||
synth_mov.setRegDU( rAX, eUSE);
|
||||
synth_mov.setRegDU( rTMP, eDEF);
|
||||
synth_mov.ll()->setFlags( SYNTHETIC );
|
||||
/* eIcode.ll()->label = Project::get()->SynthLab++; */
|
||||
synth_mov.ll()->label = _Icode.ll()->label;
|
||||
eIcode.setRegDU( rAX, eUSE);
|
||||
eIcode.setRegDU( rTMP, eDEF);
|
||||
eIcode.ll()->setFlags( SYNTHETIC );
|
||||
/* eIcode.ll()->label = SynthLab++; */
|
||||
eIcode.ll()->label = _Icode.ll()->label;
|
||||
Icode.addIcode(&eIcode);
|
||||
|
||||
/* iDIV, iIDIV */
|
||||
Icode.addIcode(&_Icode);
|
||||
|
||||
/* iMOD */
|
||||
synth_mod.type = LOW_LEVEL_ICODE;
|
||||
synth_mod.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
|
||||
synth_mod.ll()->replaceSrc(_Icode.ll()->src());
|
||||
synth_mod.du = _Icode.du;
|
||||
synth_mod.ll()->label = Project::get()->SynthLab++;
|
||||
return {
|
||||
synth_mov,
|
||||
_Icode,
|
||||
synth_mod
|
||||
};
|
||||
eIcode = ICODE();
|
||||
eIcode.type = LOW_LEVEL_ICODE;
|
||||
eIcode.ll()->set(iMOD,ll->getFlag() | SYNTHETIC | IM_TMP_DST);
|
||||
eIcode.ll()->replaceSrc(_Icode.ll()->src());
|
||||
eIcode.du = _Icode.du;
|
||||
eIcode.ll()->label = SynthLab++;
|
||||
return Icode.addIcode(&eIcode);
|
||||
}
|
||||
static std::vector<ICODE> rewrite_XCHG(LLInst *ll,ICODE &_Icode)
|
||||
ICODE *Function::translate_XCHG(LLInst *ll,ICODE &_Icode)
|
||||
{
|
||||
/* MOV rTMP, regDst */
|
||||
ICODE mov_tmp_dst;
|
||||
mov_tmp_dst.type = LOW_LEVEL_ICODE;
|
||||
mov_tmp_dst.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
|
||||
mov_tmp_dst.setRegDU( rTMP, eDEF);
|
||||
if(mov_tmp_dst.ll()->src().getReg2())
|
||||
ICODE eIcode;
|
||||
eIcode.type = LOW_LEVEL_ICODE;
|
||||
eIcode.ll()->set(iMOV,SYNTHETIC,rTMP,ll->m_dst);
|
||||
eIcode.setRegDU( rTMP, eDEF);
|
||||
if(eIcode.ll()->src().getReg2())
|
||||
{
|
||||
eReg srcreg=mov_tmp_dst.ll()->src().getReg2();
|
||||
mov_tmp_dst.setRegDU( srcreg, eUSE);
|
||||
eReg srcreg=eIcode.ll()->src().getReg2();
|
||||
eIcode.setRegDU( srcreg, eUSE);
|
||||
if((srcreg>=rAL) and (srcreg<=rBH))
|
||||
mov_tmp_dst.ll()->setFlags( B );
|
||||
eIcode.ll()->setFlags( B );
|
||||
}
|
||||
mov_tmp_dst.ll()->label = ll->label;
|
||||
eIcode.ll()->label = ll->label;
|
||||
Icode.addIcode(&eIcode);
|
||||
|
||||
/* MOV regDst, regSrc */
|
||||
ICODE mov_dst_src = _Icode; // copy all XCHG things, but set opcode to iMOV and mark it as synthetic insn
|
||||
mov_dst_src.ll()->set(iMOV,SYNTHETIC|ll->getFlag());
|
||||
ll->set(iMOV,SYNTHETIC|ll->getFlag());
|
||||
Icode.addIcode(&_Icode);
|
||||
ll->setOpcode(iXCHG); /* for next case */
|
||||
|
||||
/* MOV regSrc, rTMP */
|
||||
|
||||
ICODE mov_src_tmp;
|
||||
mov_src_tmp.type = LOW_LEVEL_ICODE;
|
||||
mov_src_tmp.ll()->set(iMOV,SYNTHETIC);
|
||||
mov_src_tmp.ll()->replaceDst(ll->src());
|
||||
if(mov_src_tmp.ll()->m_dst.regi)
|
||||
eIcode = ICODE();
|
||||
eIcode.type = LOW_LEVEL_ICODE;
|
||||
eIcode.ll()->set(iMOV,SYNTHETIC);
|
||||
eIcode.ll()->replaceDst(ll->src());
|
||||
if(eIcode.ll()->m_dst.regi)
|
||||
{
|
||||
if((mov_src_tmp.ll()->m_dst.regi>=rAL) and (mov_src_tmp.ll()->m_dst.regi<=rBH))
|
||||
mov_src_tmp.ll()->setFlags( B );
|
||||
mov_src_tmp.setRegDU( mov_src_tmp.ll()->m_dst.regi, eDEF);
|
||||
if((eIcode.ll()->m_dst.regi>=rAL) and (eIcode.ll()->m_dst.regi<=rBH))
|
||||
eIcode.ll()->setFlags( B );
|
||||
eIcode.setRegDU( eIcode.ll()->m_dst.regi, eDEF);
|
||||
}
|
||||
mov_src_tmp.ll()->replaceSrc(rTMP);
|
||||
mov_src_tmp.setRegDU( rTMP, eUSE);
|
||||
mov_src_tmp.ll()->label = Project::get()->SynthLab++;
|
||||
return {
|
||||
mov_tmp_dst,
|
||||
mov_dst_src,
|
||||
mov_src_tmp
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @brief resolveOSServices
|
||||
* @param ll
|
||||
* @param pstate
|
||||
* @return true if given OS service will terminate the program
|
||||
*/
|
||||
//TODO: convert into Command class
|
||||
static bool resolveOSServices(LLInst *ll, STATE *pstate)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
SYMTAB &global_symbol_table(Project::get()->symtab);
|
||||
|
||||
bool terminates=false;
|
||||
if(pstate->isKnown(rAX))
|
||||
assert(pstate->isKnown(rAH));
|
||||
if (ll->src().getImm2() == 0x21 and pstate->isKnown(rAH))
|
||||
{
|
||||
int funcNum = pstate->r[rAH];
|
||||
int operand;
|
||||
int size;
|
||||
|
||||
/* Save function number */
|
||||
ll->m_dst.off = (int16_t)funcNum;
|
||||
//Icode.GetIcode(Icode.GetNumIcodes() - 1)->
|
||||
|
||||
/* Program termination: int21h, fn 00h, 31h, 4Ch */
|
||||
terminates = (bool)(funcNum == 0x00 or funcNum == 0x31 or funcNum == 0x4C);
|
||||
|
||||
/* String functions: int21h, fn 09h */
|
||||
/* offset goes into DX */
|
||||
if (pstate->isKnown(rDX))
|
||||
if (funcNum == 0x09)
|
||||
{
|
||||
operand = ((uint32_t)(uint16_t)pstate->r[rDS]<<4) + (uint32_t)(uint16_t)pstate->r[rDX];
|
||||
size = prog.fCOM ?
|
||||
strSize (&prog.image()[operand], '$') :
|
||||
strSize (&prog.image()[operand], '$'); // + 0x100
|
||||
global_symbol_table.updateSymType (operand, TypeContainer(TYPE_STR, size));
|
||||
}
|
||||
}
|
||||
else if ((ll->src().getImm2() == 0x2F) and pstate->isKnown(rAH))
|
||||
{
|
||||
ll->m_dst.off = pstate->r[rAH];
|
||||
}
|
||||
else /* Program termination: int20h, int27h */
|
||||
terminates = (ll->src().getImm2() == 0x20 or ll->src().getImm2() == 0x27);
|
||||
|
||||
return terminates;
|
||||
eIcode.ll()->replaceSrc(rTMP);
|
||||
eIcode.setRegDU( rTMP, eUSE);
|
||||
eIcode.ll()->label = SynthLab++;
|
||||
return Icode.addIcode(&eIcode);
|
||||
}
|
||||
|
||||
/** FollowCtrl - Given an initial procedure, state information and symbol table
|
||||
* builds a list of procedures reachable from the initial procedure
|
||||
* using a depth first search. */
|
||||
void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
void Function::FollowCtrl(CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
{
|
||||
Project *project(Project::get());
|
||||
PROG &prog(Project::get()->prog);
|
||||
ICODE _Icode, *pIcode; /* This gets copied to pProc->Icode[] later */
|
||||
SYM * psym;
|
||||
uint32_t offset;
|
||||
eErrorId err;
|
||||
bool done = false;
|
||||
|
||||
if (func.name.contains("chkstk"))
|
||||
SYMTAB &global_symbol_table(Project::get()->symtab);
|
||||
if (name.contains("chkstk"))
|
||||
{
|
||||
// Danger! Dcc will likely fall over in this code.
|
||||
// So we act as though we have done with this proc
|
||||
// pProc->flg &= ~TERMINATES; // Not sure about this
|
||||
done = true;
|
||||
// pProc->flg &= ~TERMINATES; // Not sure about this
|
||||
// And mark it as a library function, so structure() won't choke on it
|
||||
func.flg |= PROC_ISLIB;
|
||||
flg |= PROC_ISLIB;
|
||||
return;
|
||||
}
|
||||
if (option.VeryVerbose)
|
||||
{
|
||||
qDebug() << "Parsing proc" << func.name << "at"<< QString::number(pstate->IP,16).toUpper();
|
||||
qDebug() << "Parsing proc" << name << "at" << QString::number(pstate->IP,16).toUpper();
|
||||
}
|
||||
|
||||
while (not done )
|
||||
@ -207,37 +145,31 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
break;
|
||||
LLInst *ll = _Icode.ll();
|
||||
pstate->IP += (uint32_t)ll->numBytes;
|
||||
|
||||
setBits(BM_CODE, ll->label, (uint32_t)ll->numBytes);
|
||||
|
||||
func.process_operands(_Icode,pstate);
|
||||
process_operands(_Icode,pstate);
|
||||
|
||||
/* Keep track of interesting instruction flags in procedure */
|
||||
func.flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP));
|
||||
flg |= (ll->getFlag() & (NOT_HLL | FLOAT_OP));
|
||||
|
||||
/* Check if this instruction has already been parsed */
|
||||
iICODE labLoc = func.Icode.labelSrch(ll->label);
|
||||
if (func.Icode.end()!=labLoc)
|
||||
iICODE labLoc = Icode.labelSrch(ll->label);
|
||||
if (Icode.end()!=labLoc)
|
||||
{ /* Synthetic jump */
|
||||
_Icode.type = LOW_LEVEL_ICODE;
|
||||
ll->set(iJMP,I | SYNTHETIC | NO_OPS);
|
||||
ll->replaceSrc(LLOperand::CreateImm2(labLoc->ll()->GetLlLabel()));
|
||||
ll->label = Project::get()->SynthLab++;
|
||||
ll->label = SynthLab++;
|
||||
}
|
||||
|
||||
/* Copy Icode to Proc */
|
||||
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV)) {
|
||||
std::vector<ICODE> translated = rewrite_DIV(ll,_Icode);
|
||||
for(const ICODE &ic : translated)
|
||||
pIcode = func.Icode.addIcode(&ic);
|
||||
}
|
||||
else if (_Icode.ll()->getOpcode() == iXCHG) {
|
||||
std::vector<ICODE> translated = rewrite_XCHG(ll,_Icode);
|
||||
for(const ICODE &ic : translated)
|
||||
pIcode = func.Icode.addIcode(&ic);
|
||||
}
|
||||
else {
|
||||
pIcode = func.Icode.addIcode(&_Icode);
|
||||
}
|
||||
if ((ll->getOpcode() == iDIV) or (ll->getOpcode() == iIDIV))
|
||||
pIcode = translate_DIV(ll, _Icode);
|
||||
else if (_Icode.ll()->getOpcode() == iXCHG)
|
||||
pIcode = translate_XCHG(ll, _Icode);
|
||||
else
|
||||
pIcode = Icode.addIcode(&_Icode);
|
||||
|
||||
switch (ll->getOpcode()) {
|
||||
/*** Conditional jumps ***/
|
||||
@ -249,49 +181,51 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
case iJCXZ:
|
||||
{
|
||||
STATE StCopy;
|
||||
int ip = func.Icode.size()-1; /* Index of this jump */
|
||||
ICODE &prev(*(++func.Icode.rbegin())); /* Previous icode */
|
||||
uint32_t lastIp = pstate->IP - 2;
|
||||
int ip = Icode.size()-1; /* Index of this jump */
|
||||
ICODE &prev(*(++Icode.rbegin())); /* Previous icode */
|
||||
bool fBranch = false;
|
||||
|
||||
pstate->JCond.regi = 0;
|
||||
|
||||
/* This sets up range check for indexed JMPs hopefully
|
||||
* Handles JA/JAE for fall through and JB/JBE on branch
|
||||
*/
|
||||
if (ip > 0 and prev.ll()->match(iCMP,I) )
|
||||
* Handles JA/JAE for fall through and JB/JBE on branch
|
||||
*/
|
||||
if (ip > 0 and prev.ll()->getOpcode() == iCMP and (prev.ll()->testFlags(I)))
|
||||
{
|
||||
pstate->JCond.immed = (int16_t)prev.ll()->src().getImm2();
|
||||
if (ll->match(iJA) or ll->match(iJBE) )
|
||||
pstate->JCond.immed++;
|
||||
if (ll->getOpcode() == iJAE or ll->getOpcode() == iJA)
|
||||
pstate->JCond.regi = prev.ll()->m_dst.regi;
|
||||
fBranch = (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
|
||||
fBranch = (bool) (ll->getOpcode() == iJB or ll->getOpcode() == iJBE);
|
||||
}
|
||||
StCopy = *pstate;
|
||||
|
||||
//printf("From %X condJump to %X\n", lastIp, pstate->IP);
|
||||
|
||||
/* Straight line code */
|
||||
project->addCommand(func.shared_from_this(),new FollowControlFlow(StCopy)); // recurrent ?
|
||||
this->FollowCtrl (pcallGraph, &StCopy); // recurrent ?
|
||||
|
||||
if (fBranch) /* Do branching code */
|
||||
{
|
||||
pstate->JCond.regi = prev.ll()->m_dst.regi;
|
||||
}
|
||||
/* Next icode. Note: not the same as GetLastIcode() because of the call to FollowCtrl() */
|
||||
pIcode = func.Icode.GetIcode(ip);
|
||||
/* do the jump path */
|
||||
done = process_JMP(func.shared_from_this(),*pIcode, pstate, pcallGraph);
|
||||
break;
|
||||
}
|
||||
/* Next icode. Note: not the same as GetLastIcode() because of the call
|
||||
to FollowCtrl() */
|
||||
pIcode = Icode.GetIcode(ip);
|
||||
} /* Fall through to do the jump path */
|
||||
|
||||
/*** Jumps ***/
|
||||
case iJMP:
|
||||
case iJMPF: /* Returns true if we've run into a loop */
|
||||
done = process_JMP (func.shared_from_this(),*pIcode, pstate, pcallGraph);
|
||||
done = process_JMP (*pIcode, pstate, pcallGraph);
|
||||
break;
|
||||
|
||||
/*** Calls ***/
|
||||
case iCALL:
|
||||
case iCALLF:
|
||||
done = process_CALL(func.shared_from_this(),*pIcode, pcallGraph, pstate);
|
||||
done = process_CALL (*pIcode, pcallGraph, pstate);
|
||||
pstate->kill(rBX);
|
||||
pstate->kill(rCX);
|
||||
break;
|
||||
@ -299,17 +233,46 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
/*** Returns ***/
|
||||
case iRET:
|
||||
case iRETF:
|
||||
func.flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
|
||||
func.flg &= ~TERMINATES;
|
||||
done = true;
|
||||
break;
|
||||
this->flg |= (ll->getOpcode() == iRET)? PROC_NEAR:PROC_FAR;
|
||||
/* Fall through */
|
||||
case iIRET:
|
||||
func.flg &= ~TERMINATES;
|
||||
this->flg &= ~TERMINATES;
|
||||
done = true;
|
||||
break;
|
||||
|
||||
case iINT:
|
||||
done = resolveOSServices(ll, pstate);
|
||||
if (ll->src().getImm2() == 0x21 and pstate->f[rAH])
|
||||
{
|
||||
int funcNum = pstate->r[rAH];
|
||||
int operand;
|
||||
int size;
|
||||
|
||||
/* Save function number */
|
||||
Icode.back().ll()->m_dst.off = (int16_t)funcNum;
|
||||
//Icode.GetIcode(Icode.GetNumIcodes() - 1)->
|
||||
|
||||
/* Program termination: int21h, fn 00h, 31h, 4Ch */
|
||||
done = (bool)(funcNum == 0x00 or funcNum == 0x31 or
|
||||
funcNum == 0x4C);
|
||||
|
||||
/* String functions: int21h, fn 09h */
|
||||
if (pstate->f[rDX]) /* offset goes into DX */
|
||||
if (funcNum == 0x09)
|
||||
{
|
||||
operand = ((uint32_t)(uint16_t)pstate->r[rDS]<<4) +
|
||||
(uint32_t)(uint16_t)pstate->r[rDX];
|
||||
size = prog.fCOM ?
|
||||
strSize (&prog.image()[operand], '$') :
|
||||
strSize (&prog.image()[operand], '$'); // + 0x100
|
||||
global_symbol_table.updateSymType (operand, TypeContainer(TYPE_STR, size));
|
||||
}
|
||||
}
|
||||
else if ((ll->src().getImm2() == 0x2F) and (pstate->f[rAH]))
|
||||
{
|
||||
Icode.back().ll()->m_dst.off = pstate->r[rAH];
|
||||
}
|
||||
else /* Program termination: int20h, int27h */
|
||||
done = (ll->src().getImm2() == 0x20 or ll->src().getImm2() == 0x27);
|
||||
if (done)
|
||||
pIcode->ll()->setFlags(TERMINATES);
|
||||
break;
|
||||
@ -317,10 +280,16 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
case iMOV:
|
||||
process_MOV(*pIcode->ll(), pstate);
|
||||
break;
|
||||
|
||||
/* case iXCHG:
|
||||
process_MOV (pIcode, pstate);
|
||||
|
||||
break; **** HERE ***/
|
||||
|
||||
case iSHL:
|
||||
if (pstate->JCond.regi == ll->m_dst.regi)
|
||||
{
|
||||
if (ll->srcIsImmed() and ll->src().getImm2() == 1)
|
||||
if ((ll->testFlags(I)) and ll->src().getImm2() == 1)
|
||||
pstate->JCond.immed *= 2;
|
||||
else
|
||||
pstate->JCond.regi = 0;
|
||||
@ -337,7 +306,7 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
/* and (Icode.ll()->flg & SEG_IMMED) */ )
|
||||
{
|
||||
offset = LH(&prog.image()[psym->label]);
|
||||
pstate->setState( (ll->getOpcode() == iLDS)? rDS : rES,
|
||||
pstate->setState( (ll->getOpcode() == iLDS)? rDS: rES,
|
||||
LH(&prog.image()[psym->label + 2]));
|
||||
pstate->setState( ll->m_dst.regi, (int16_t)offset);
|
||||
psym->type = TYPE_PTR;
|
||||
@ -347,12 +316,12 @@ void FollowCtrl(Function &func,CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
}
|
||||
|
||||
if (err) {
|
||||
func.flg &= ~TERMINATES;
|
||||
this->flg &= ~TERMINATES;
|
||||
|
||||
if (err == INVALID_386OP or err == INVALID_OPCODE)
|
||||
{
|
||||
fatalError(err, prog.image()[_Icode.ll()->label], _Icode.ll()->label);
|
||||
func.flg |= PROC_BADINST;
|
||||
this->flg |= PROC_BADINST;
|
||||
}
|
||||
else if (err == IP_OUT_OF_RANGE)
|
||||
fatalError (err, _Icode.ll()->label);
|
||||
@ -376,7 +345,34 @@ void Function::extractJumpTableRange(ICODE& pIcode, STATE *pstate, JumpTable &ta
|
||||
table.finish = table.start + 2;
|
||||
}
|
||||
|
||||
static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
|
||||
/* process_JMP - Handles JMPs, returns true if we should end recursion */
|
||||
bool Function::followAllTableEntries(JumpTable &table, uint32_t cs, ICODE& pIcode, CALL_GRAPH* pcallGraph, STATE *pstate)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
STATE StCopy;
|
||||
|
||||
setBits(BM_DATA, table.start, table.size()*table.entrySize());
|
||||
|
||||
pIcode.ll()->setFlags(SWITCH);
|
||||
pIcode.ll()->caseTbl2.resize( table.size() );
|
||||
assert(pIcode.ll()->caseTbl2.size()<512);
|
||||
uint32_t k=0;
|
||||
for (size_t i = table.start; i < table.finish; i += 2)
|
||||
{
|
||||
StCopy = *pstate;
|
||||
StCopy.IP = cs + LH(&prog.image()[i]);
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
|
||||
FollowCtrl (pcallGraph, &StCopy);
|
||||
|
||||
++last_current_insn; // incremented here because FollowCtrl might have adde more instructions after the Jmp
|
||||
last_current_insn->ll()->caseEntry = k++;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool Function::decodeIndirectJMP(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
// mov cx,NUM_CASES
|
||||
@ -393,9 +389,9 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
|
||||
// jmp word ptr [bx+2*NUM_CASES]
|
||||
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
|
||||
|
||||
if(func->Icode.size()<8)
|
||||
if(Icode.size()<8)
|
||||
return false;
|
||||
if(&func->Icode.back()!=&pIcode) // not the last insn in the list skip it
|
||||
if(&Icode.back()!=&pIcode) // not the last insn in the list skip it
|
||||
return false;
|
||||
if(pIcode.ll()->src().regi != INDEX_BX) {
|
||||
return false;
|
||||
@ -403,7 +399,7 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
|
||||
// find address-wise predecessors of the icode
|
||||
std::deque<ICODE *> matched;
|
||||
QMap<uint32_t,ICODE *> addrmap;
|
||||
for(ICODE & ic : func->Icode) {
|
||||
for(ICODE & ic : Icode) {
|
||||
addrmap[ic.ll()->GetLlLabel()] = ⁣
|
||||
}
|
||||
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
|
||||
@ -416,11 +412,11 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
|
||||
// pattern starts at the last jmp
|
||||
ICODE *load_num_cases = matched[0];
|
||||
ICODE *load_jump_table_addr = matched[1];
|
||||
// ICODE *read_case_entry_insn = matched[2];
|
||||
// ICODE *cmp_case_val_insn = matched[3];
|
||||
// ICODE *exit_loop_insn = matched[4];
|
||||
// ICODE *add_bx_insn = matched[5];
|
||||
// ICODE *loop_insn = matched[6];
|
||||
ICODE *read_case_entry_insn = matched[2];
|
||||
ICODE *cmp_case_val_insn = matched[3];
|
||||
ICODE *exit_loop_insn = matched[4];
|
||||
ICODE *add_bx_insn = matched[5];
|
||||
ICODE *loop_insn = matched[6];
|
||||
ICODE *default_jmp = matched[7];
|
||||
ICODE *last_jmp = matched[8];
|
||||
for(int i=0; i<8; ++i) {
|
||||
@ -453,12 +449,16 @@ static bool decodeIndirectJMP(const PtrFunction &func,ICODE & pIcode, STATE *pst
|
||||
STATE StCopy = *pstate;
|
||||
uint32_t jump_target_location = table_addr + num_cases*2 + i*2;
|
||||
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
FollowCtrl (pcallGraph, &StCopy);
|
||||
++last_current_insn;
|
||||
last_current_insn->ll()->caseEntry = i;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *pstate)
|
||||
bool Function::decodeIndirectJMP2(ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
// mov cx,NUM_CASES
|
||||
@ -479,9 +479,9 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
// jmp word ptr [bx+2*NUM_CASES]
|
||||
static const llIcode match_seq[] = {iMOV,iMOV,iMOV,iCMP,iJNE,iMOV,iCMP,iJE,iADD,iLOOP,iJMP,iJMP};
|
||||
|
||||
if(func->Icode.size()<12)
|
||||
if(Icode.size()<12)
|
||||
return false;
|
||||
if(&func->Icode.back() != &pIcode) // not the last insn in the list skip it
|
||||
if(&Icode.back() != &pIcode) // not the last insn in the list skip it
|
||||
return false;
|
||||
if(pIcode.ll()->src().regi != INDEX_BX) {
|
||||
return false;
|
||||
@ -489,7 +489,7 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
// find address-wise predecessors of the icode
|
||||
std::deque<ICODE *> matched;
|
||||
QMap<uint32_t,ICODE *> addrmap;
|
||||
for(ICODE & ic : func->Icode) {
|
||||
for(ICODE & ic : Icode) {
|
||||
addrmap[ic.ll()->GetLlLabel()] = ⁣
|
||||
}
|
||||
auto iter = addrmap.find(pIcode.ll()->GetLlLabel());
|
||||
@ -535,19 +535,54 @@ static bool decodeIndirectJMP2(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
STATE StCopy = *pstate;
|
||||
uint32_t jump_target_location = table_addr + num_cases*4 + i*2;
|
||||
StCopy.IP = cs + *(uint16_t *)(prog.image()+jump_target_location);
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,i));
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
FollowCtrl (pcallGraph, &StCopy);
|
||||
++last_current_insn;
|
||||
last_current_insn->ll()->caseEntry = i;
|
||||
last_current_insn->ll()->setFlags(CASE);
|
||||
pIcode.ll()->caseTbl2.push_back( last_current_insn->ll()->GetLlLabel() );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Look for switch() stmt. idiom of the form
|
||||
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
|
||||
static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *pstate) {
|
||||
const static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
|
||||
|
||||
uint32_t seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
|
||||
bool Function::process_JMP (ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
static uint8_t i2r[4] = {rSI, rDI, rBP, rBX};
|
||||
ICODE _Icode;
|
||||
uint32_t lastIp = pstate->IP - 1;
|
||||
uint32_t cs, offTable, endTable;
|
||||
uint32_t i, k, seg, target;
|
||||
|
||||
if (pIcode.ll()->testFlags(I))
|
||||
{
|
||||
if (pIcode.ll()->getOpcode() == iJMPF)
|
||||
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
|
||||
|
||||
pstate->IP = pIcode.ll()->src().getImm2();
|
||||
|
||||
//printf("From seg:%04X JMP(F) to %X\n", lastIp, pstate->IP);
|
||||
|
||||
if (pstate->IP == 0xFFFF0)
|
||||
{
|
||||
/* Nasty (wrong) trick use to reset, consider it as terminating */
|
||||
pIcode.ll()->setFlags(TERMINATES);
|
||||
pstate->setState( rCS, 0);
|
||||
pstate->IP = 0;
|
||||
}
|
||||
|
||||
int64_t i = pIcode.ll()->src().getImm2();
|
||||
if (i < 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Return true if jump target is already parsed */
|
||||
return Icode.alreadyDecoded(i);
|
||||
}
|
||||
/* We've got an indirect JMP - look for switch() stmt. idiom of the form
|
||||
* JMP uint16_t ptr word_offset[rBX | rSI | rDI] */
|
||||
seg = (pIcode.ll()->src().seg)? pIcode.ll()->src().seg: rDS;
|
||||
|
||||
/* Ensure we have a uint16_t offset & valid seg */
|
||||
if (pIcode.ll()->match(iJMP) and (pIcode.ll()->testFlags(WORD_OFF)) and
|
||||
@ -557,9 +592,8 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
pIcode.ll()->src().regi == INDEX_BX))
|
||||
{
|
||||
|
||||
uint32_t offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
|
||||
uint32_t endTable;
|
||||
uint32_t i;
|
||||
offTable = ((uint32_t)(uint16_t)pstate->r[seg] << 4) + pIcode.ll()->src().off;
|
||||
|
||||
/* Firstly look for a leading range check of the form:-
|
||||
* CMP {BX | SI | DI}, immed
|
||||
* JA | JAE | JB | JBE
|
||||
@ -580,10 +614,10 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
/* Now do some heuristic pruning. Look for ptrs. into the table
|
||||
* and for addresses that don't appear to point to valid code.
|
||||
*/
|
||||
uint32_t cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
|
||||
cs = (uint32_t)(uint16_t)pstate->r[rCS] << 4;
|
||||
for (i = offTable; i < endTable; i += 2)
|
||||
{
|
||||
uint32_t target = cs + LH(&prog.image()[i]);
|
||||
target = cs + LH(&prog.image()[i]);
|
||||
if (target < endTable and target >= offTable)
|
||||
endTable = target;
|
||||
else if (target >= (uint32_t)prog.cbImage)
|
||||
@ -592,10 +626,10 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
|
||||
for (i = offTable; i < endTable; i += 2)
|
||||
{
|
||||
uint32_t target = cs + LH(&prog.image()[i]);
|
||||
target = cs + LH(&prog.image()[i]);
|
||||
/* Be wary of 00 00 as code - it's probably data */
|
||||
ICODE _Icode;
|
||||
if (not (prog.image()[target] or prog.image()[target+1]) or scan(target, _Icode)!=NO_ERR)
|
||||
if (not (prog.image()[target] or prog.image()[target+1]) or
|
||||
scan(target, _Icode))
|
||||
endTable = i;
|
||||
}
|
||||
|
||||
@ -611,56 +645,37 @@ static bool decodeIndirectJMP0(const PtrFunction &func,ICODE & pIcode, STATE *ps
|
||||
setBits(BM_DATA, offTable, endTable - offTable);
|
||||
|
||||
pIcode.ll()->setFlags(SWITCH);
|
||||
//pIcode.ll()->caseTbl2.numEntries = (endTable - offTable) / 2;
|
||||
|
||||
uint32_t k;
|
||||
for (i = offTable, k = 0; i < endTable; i += 2)
|
||||
{
|
||||
StCopy = *pstate;
|
||||
StCopy.IP = cs + LH(&prog.image()[i]);
|
||||
Project::get()->addCommand(func,new FollowControlFlow(StCopy));
|
||||
Project::get()->addCommand(func,new MarkAsSwitchCase(pIcode.ll()->label,StCopy.IP,k++));
|
||||
iICODE last_current_insn = (++Icode.rbegin()).base();
|
||||
//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 false;
|
||||
}
|
||||
/* process_JMP - Handles JMPs, returns true if we should end recursion */
|
||||
static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, CALL_GRAPH * pcallGraph)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
|
||||
if (pIcode.ll()->srcIsImmed())
|
||||
{
|
||||
if (pIcode.ll()->getOpcode() == iJMPF)
|
||||
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
|
||||
pstate->IP = pIcode.ll()->src().getImm2();
|
||||
int64_t i = pIcode.ll()->src().getImm2();
|
||||
if (i < 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Return true if jump target is already parsed */
|
||||
return func->Icode.alreadyDecoded(i);
|
||||
}
|
||||
/* We've got an indirect JMP */
|
||||
if(decodeIndirectJMP0(func,pIcode,pstate)) {
|
||||
if(decodeIndirectJMP(pIcode,pstate,pcallGraph)) {
|
||||
return true;
|
||||
}
|
||||
if(decodeIndirectJMP(func,pIcode,pstate)) {
|
||||
return true;
|
||||
}
|
||||
if(decodeIndirectJMP2(func,pIcode,pstate)) {
|
||||
if(decodeIndirectJMP2(pIcode,pstate,pcallGraph)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Can't do anything with this jump */
|
||||
|
||||
func->flg |= PROC_IJMP;
|
||||
func->flg &= ~TERMINATES;
|
||||
// TODO: consider adding a new user-interactive command ResolveControlFlowFailure ?
|
||||
interactDis(func, func->Icode.size()-1);
|
||||
flg |= PROC_IJMP;
|
||||
flg &= ~TERMINATES;
|
||||
interactDis(this, this->Icode.size()-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -674,16 +689,17 @@ static bool process_JMP(const PtrFunction &func,ICODE & pIcode, STATE *pstate, C
|
||||
* programmer expected it to come back - otherwise surely a JMP would
|
||||
* have been used. */
|
||||
|
||||
bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
bool Function::process_CALL(ICODE & pIcode, CALL_GRAPH * pcallGraph, STATE *pstate)
|
||||
{
|
||||
Project &project(*Project::get());
|
||||
PROG &prog(Project::get()->prog);
|
||||
ICODE &last_insn(func->Icode.back());
|
||||
ICODE &last_insn(Icode.back());
|
||||
STATE localState; /* Local copy of the machine state */
|
||||
uint32_t lastIp = pstate->IP - 2;
|
||||
uint32_t off;
|
||||
/* For Indirect Calls, find the function address */
|
||||
bool indirect = false;
|
||||
//pIcode.ll()->immed.proc.proc=fakeproc;
|
||||
if ( not pIcode.ll()->srcIsImmed() )
|
||||
if ( not pIcode.ll()->testFlags(I) )
|
||||
{
|
||||
/* Not immediate, i.e. indirect call */
|
||||
|
||||
@ -728,30 +744,30 @@ bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGrap
|
||||
if (pIcode.ll()->getOpcode() == iCALLF)
|
||||
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(LH(&prog.image()[off+2])) << 4);
|
||||
else
|
||||
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)pstate->r[rCS] << 4);
|
||||
tgtAddr= LH(&prog.image()[off]) + ((uint32_t)(uint16_t)state.r[rCS] << 4);
|
||||
pIcode.ll()->replaceSrc(LLOperand::CreateImm2( tgtAddr ) );
|
||||
pIcode.ll()->setFlags(I);
|
||||
indirect = true;
|
||||
}
|
||||
|
||||
/* Process CALL. Function address is located in pIcode.ll()->immed.op */
|
||||
if (pIcode.ll()->srcIsImmed())
|
||||
if (pIcode.ll()->testFlags(I))
|
||||
{
|
||||
/* Search procedure list for one with appropriate entry point */
|
||||
PtrFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
|
||||
ilFunction iter = Project::get()->findByEntry(pIcode.ll()->src().getImm2());
|
||||
|
||||
/* Create a new procedure node and save copy of the state */
|
||||
if ( iter == nullptr )
|
||||
if ( not Project::get()->valid(iter) )
|
||||
{
|
||||
iter = Project::get()->createFunction(0,"",{0,pIcode.ll()->src().getImm2()});
|
||||
iter = Project::get()->createFunction(0,"");
|
||||
Function &x(*iter);
|
||||
if(project.m_pattern_locator)
|
||||
project.m_pattern_locator->LibCheck(x);
|
||||
x.procEntry = pIcode.ll()->src().getImm2();
|
||||
LibCheck(x);
|
||||
|
||||
if (x.flg & PROC_ISLIB)
|
||||
{
|
||||
/* A library function. No need to do any more to it */
|
||||
pcallGraph->insertCallGraph (func, iter);
|
||||
pcallGraph->insertCallGraph (this, iter);
|
||||
//iter = (++pProcList.rbegin()).base();
|
||||
last_insn.ll()->src().proc.proc = &x;
|
||||
return false;
|
||||
@ -767,27 +783,38 @@ bool process_CALL(const PtrFunction &func,ICODE & pIcode, CALL_GRAPH * pcallGrap
|
||||
x.depth = x.depth + 1;
|
||||
x.flg |= TERMINATES;
|
||||
|
||||
/* Save machine state in localState, load up IP and CS.*/
|
||||
localState = *pstate;
|
||||
pstate->IP = pIcode.ll()->src().getImm2();
|
||||
if (pIcode.ll()->getOpcode() == iCALLF)
|
||||
pstate->setState( rCS, LH(prog.image() + pIcode.ll()->label + 3));
|
||||
|
||||
x.state = *pstate;
|
||||
|
||||
/* Insert new procedure in call graph */
|
||||
pcallGraph->insertCallGraph (func, iter);
|
||||
- pcallGraph->insertCallGraph (this, iter);
|
||||
|
||||
//printf("From %X CALL to %X\n", lastIp, pstate->IP);
|
||||
|
||||
/* Process new procedure */
|
||||
Project::get()->addCommand(iter,new FollowControlFlow(*pstate));
|
||||
x.FollowCtrl (pcallGraph, pstate);
|
||||
|
||||
/* Restore segment registers & IP from localState */
|
||||
pstate->IP = localState.IP;
|
||||
pstate->setState( rCS, localState.r[rCS]);
|
||||
pstate->setState( rDS, localState.r[rDS]);
|
||||
pstate->setState( rES, localState.r[rES]);
|
||||
pstate->setState( rSS, localState.r[rSS]);
|
||||
|
||||
}
|
||||
else
|
||||
Project::get()->callGraph->insertCallGraph (func, iter);
|
||||
Project::get()->callGraph->insertCallGraph (this, iter);
|
||||
|
||||
last_insn.ll()->src().proc.proc = &(*iter); // ^ target proc
|
||||
|
||||
/* 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;
|
||||
if (dstReg > 0 and dstReg < INDEX_BX_SI)
|
||||
{
|
||||
if (ll.srcIsImmed())
|
||||
if (ll.testFlags(I))
|
||||
pstate->setState( dstReg, (int16_t)ll.src().getImm2());
|
||||
else if (srcReg == 0) /* direct memory offset */
|
||||
{
|
||||
@ -857,7 +884,7 @@ static void process_MOV(LLInst & ll, STATE * pstate)
|
||||
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]);
|
||||
if(psym->size>1)
|
||||
{
|
||||
pstate->setMemoryByte(psym->label,uint8_t(pstate->r[srcReg]>>8));
|
||||
pstate->setMemoryByte(psym->label,(uint8_t)pstate->r[srcReg]>>8);
|
||||
//prog.image()[psym->label+1] = (uint8_t)(pstate->r[srcReg] >> 8);
|
||||
}
|
||||
psym->duVal.setFlags(eDuVal::DEF);
|
||||
@ -905,8 +932,8 @@ void STKFRAME::updateFrameOff ( int16_t off, int _size, uint16_t duFlag)
|
||||
}
|
||||
|
||||
/* Save maximum argument offset */
|
||||
if ((uint32_t)this->m_maxOff < (off + (uint32_t)_size))
|
||||
this->m_maxOff = off + (int16_t)_size;
|
||||
if ((uint32_t)this->maxOff < (off + (uint32_t)_size))
|
||||
this->maxOff = off + (int16_t)_size;
|
||||
}
|
||||
|
||||
|
||||
@ -1005,7 +1032,7 @@ static void setBits(int16_t type, uint32_t start, uint32_t len)
|
||||
for (i = start + len - 1; i >= start; i--)
|
||||
{
|
||||
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->off >= 2) {
|
||||
if (pm->off >= 2)
|
||||
pProc->args.updateFrameOff ( pm->off, size, eDuVal::USE);
|
||||
}
|
||||
else if (pm->off < 0)
|
||||
pProc->localId.newByteWordStk (TYPE_WORD_SIGN, pm->off, 0);
|
||||
}
|
||||
@ -1062,7 +1088,7 @@ static void use (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
|
||||
}
|
||||
|
||||
/* Use of register */
|
||||
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
|
||||
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I))))
|
||||
pIcode.du.use.addReg(pm->regi);
|
||||
}
|
||||
|
||||
@ -1111,7 +1137,7 @@ static void def (opLoc d, ICODE & pIcode, Function * pProc, STATE * pstate, int
|
||||
}
|
||||
}
|
||||
/* Definition of register */
|
||||
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->srcIsImmed())))
|
||||
else if ((d == DST) or ((d == SRC) and (not pIcode.ll()->testFlags(I))))
|
||||
{
|
||||
assert(not pIcode.ll()->match(iPUSH));
|
||||
pIcode.du1.addDef(pm->regi);
|
||||
@ -1148,7 +1174,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
|
||||
int sseg = (ll_ins.src().seg)? ll_ins.src().seg: rDS;
|
||||
int cb = pIcode.ll()->testFlags(B) ? 1: 2;
|
||||
//x86_op_t *im= pIcode.insn.x86_get_imm();
|
||||
bool Imm = (pIcode.ll()->srcIsImmed());
|
||||
bool Imm = (pIcode.ll()->testFlags(I));
|
||||
|
||||
switch (pIcode.ll()->getOpcode()) {
|
||||
case iAND: case iOR: case iXOR:
|
||||
@ -1166,8 +1192,8 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
|
||||
|
||||
case iXCHG:
|
||||
/* This instruction is replaced by 3 instructions, only need
|
||||
* to define the src operand and use the destination operand
|
||||
* in the mean time.*/
|
||||
* to define the src operand and use the destination operand
|
||||
* in the mean time. */
|
||||
use(SRC, pIcode, this, pstate, cb);
|
||||
def(DST, pIcode, this, pstate, cb);
|
||||
break;
|
||||
@ -1265,9 +1291,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
|
||||
use(SRC, pIcode, this, pstate, cb);
|
||||
break;
|
||||
|
||||
case iLOOP:
|
||||
case iLOOPE:
|
||||
case iLOOPNE:
|
||||
case iLOOP: case iLOOPE: case iLOOPNE:
|
||||
pIcode.du.def.addReg(rCX);
|
||||
pIcode.du1.addDef(rCX);
|
||||
case iJCXZ:
|
||||
@ -1322,8 +1346,7 @@ void Function::process_operands(ICODE & pIcode, STATE * pstate)
|
||||
pIcode.du.use.addReg(rDX).addReg(sseg);
|
||||
break;
|
||||
|
||||
case iIN:
|
||||
case iOUT:
|
||||
case iIN: case iOUT:
|
||||
def(DST, pIcode, this, pstate, cb);
|
||||
if (not Imm)
|
||||
{
|
||||
|
||||
@ -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
|
||||
@ -14,6 +14,7 @@
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
extern Project g_proj;
|
||||
/* Static indentation buffer */
|
||||
static constexpr int indSize=81; /* size of indentation buffer; max 20 */
|
||||
static char indentBuf[indSize] =
|
||||
@ -27,7 +28,7 @@ const char *indentStr(int indLevel) // Indentation according to the depth of the
|
||||
|
||||
/* Inserts an outEdge at the current callGraph pointer if the newProc does
|
||||
* not exist. */
|
||||
void CALL_GRAPH::insertArc (PtrFunction newProc)
|
||||
void CALL_GRAPH::insertArc (ilFunction newProc)
|
||||
{
|
||||
|
||||
|
||||
@ -43,23 +44,23 @@ void CALL_GRAPH::insertArc (PtrFunction newProc)
|
||||
|
||||
|
||||
/* Inserts a (caller, callee) arc in the call graph tree. */
|
||||
bool CALL_GRAPH::insertCallGraph(PtrFunction caller, PtrFunction callee)
|
||||
bool CALL_GRAPH::insertCallGraph(ilFunction caller, ilFunction callee)
|
||||
{
|
||||
if (proc == caller)
|
||||
{
|
||||
insertArc (callee);
|
||||
return true;
|
||||
}
|
||||
for (CALL_GRAPH *edg : outEdges)
|
||||
if (edg->insertCallGraph (caller, callee))
|
||||
return true;
|
||||
for (CALL_GRAPH *edg : outEdges)
|
||||
if (edg->insertCallGraph (caller, callee))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//bool CALL_GRAPH::insertCallGraph(PtrFunction &caller, PtrFunction &callee)
|
||||
//{
|
||||
// return insertCallGraph(caller,callee);
|
||||
//}
|
||||
bool CALL_GRAPH::insertCallGraph(Function *caller, ilFunction callee)
|
||||
{
|
||||
return insertCallGraph(Project::get()->funcIter(caller),callee);
|
||||
}
|
||||
|
||||
|
||||
/* Displays the current node of the call graph, and invokes recursively on
|
||||
@ -87,7 +88,7 @@ void CALL_GRAPH::write()
|
||||
/* Updates the argument table by including the register(s) (ie. lhs of
|
||||
* picode) and the actual expression (ie. rhs of picode).
|
||||
* Note: register(s) are only included once in the table. */
|
||||
void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
|
||||
void LOCAL_ID::newRegArg(ICODE &picode, ICODE &ticode) const
|
||||
{
|
||||
AstIdent *lhs;
|
||||
STKFRAME * call_args_stackframe, *target_stackframe;
|
||||
@ -97,16 +98,16 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
|
||||
condId type;
|
||||
Function * tproc;
|
||||
eReg regL = rUNDEF;
|
||||
eReg regH; /* Registers involved in arguments */
|
||||
eReg regH; /* Registers involved in arguments */
|
||||
|
||||
/* Flag ticode as having register arguments */
|
||||
tproc = ticode->hl()->call.proc;
|
||||
tproc = ticode.hl()->call.proc;
|
||||
tproc->flg |= REG_ARGS;
|
||||
|
||||
/* Get registers and index into target procedure's local list */
|
||||
call_args_stackframe = ticode->hl()->call.args;
|
||||
call_args_stackframe = ticode.hl()->call.args;
|
||||
target_stackframe = &tproc->args;
|
||||
lhs = dynamic_cast<AstIdent *>(picode->hl()->asgn.lhs());
|
||||
lhs = dynamic_cast<AstIdent *>(picode.hl()->asgn.lhs());
|
||||
RegisterNode *lhs_reg = dynamic_cast<RegisterNode *>(lhs);
|
||||
assert(lhs);
|
||||
type = lhs->ident.type();
|
||||
@ -187,13 +188,13 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
|
||||
/* Do ps (actual arguments) */
|
||||
STKSYM newsym;
|
||||
newsym.setArgName(call_args_stackframe->size());
|
||||
newsym.actual = picode->hl()->asgn.m_rhs;
|
||||
newsym.actual = picode.hl()->asgn.m_rhs;
|
||||
newsym.regs = lhs;
|
||||
/* Mask off high and low register(s) in picode */
|
||||
switch (type) {
|
||||
case REGISTER:
|
||||
id = &id_arr[lhs_reg->regiIdx];
|
||||
picode->du.def.clrReg(id->id.regi);
|
||||
picode.du.def.clrReg(id->id.regi);
|
||||
if (id->id.regi < rAL)
|
||||
newsym.type = TYPE_WORD_SIGN;
|
||||
else
|
||||
@ -201,8 +202,8 @@ void LOCAL_ID::newRegArg(iICODE picode, iICODE ticode) const
|
||||
break;
|
||||
case LONG_VAR:
|
||||
id = &id_arr[lhs->ident.idNode.longIdx];
|
||||
picode->du.def.clrReg(id->longId().h());
|
||||
picode->du.def.clrReg(id->longId().l());
|
||||
picode.du.def.clrReg(id->longId().h());
|
||||
picode.du.def.clrReg(id->longId().l());
|
||||
newsym.type = TYPE_LONG_SIGN;
|
||||
break;
|
||||
default:
|
||||
@ -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
|
||||
* argument list of picode. */
|
||||
* argument list of picode. */
|
||||
void CallType::placeStkArg (Expr *exp, int pos)
|
||||
{
|
||||
(*args)[pos].actual = exp;
|
||||
@ -289,7 +290,7 @@ Expr *Function::adjustActArgType (Expr *_exp, hlType forType)
|
||||
case TYPE_STR:
|
||||
switch (actType) {
|
||||
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);
|
||||
assert(c);
|
||||
|
||||
160
src/project.cpp
160
src/project.cpp
@ -1,37 +1,27 @@
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QDir>
|
||||
#include <utility>
|
||||
#include "dcc.h"
|
||||
#include "CallGraph.h"
|
||||
#include "project.h"
|
||||
#include "Procedure.h"
|
||||
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QDebug>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
|
||||
QString asm1_name, asm2_name; /* Assembler output filenames */
|
||||
SYMTAB symtab; /* Global symbol table */
|
||||
STATS stats; /* cfg statistics */
|
||||
//PROG prog; /* programs fields */
|
||||
OPTION option; /* Command line options */
|
||||
Project *Project::s_instance = nullptr;
|
||||
Project::Project() :
|
||||
m_selected_loader(nullptr),
|
||||
callGraph(nullptr),
|
||||
m_pattern_locator(nullptr)
|
||||
Project::Project() : callGraph(nullptr)
|
||||
{
|
||||
m_project_command_stream.setMaximumCommandCount(10);
|
||||
connect(&m_project_command_stream,SIGNAL(streamCompleted(bool)),SLOT(onCommandStreamFinished(bool)));
|
||||
}
|
||||
void Project::initialize()
|
||||
{
|
||||
resetCommandsAndErrorState();
|
||||
delete callGraph;
|
||||
callGraph = nullptr;
|
||||
}
|
||||
void Project::create(const QString &a)
|
||||
{
|
||||
// TODO: reset all state.
|
||||
initialize();
|
||||
QFileInfo fi(a);
|
||||
m_fname=a;
|
||||
@ -49,52 +39,26 @@ bool Project::valid(ilFunction iter)
|
||||
ilFunction Project::funcIter(Function *to_find)
|
||||
{
|
||||
auto iter=std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[to_find](const PtrFunction &f)->bool {return to_find->shared_from_this()==f;});
|
||||
[to_find](const Function &f)->bool {return to_find==&f;});
|
||||
assert(iter!=pProcList.end());
|
||||
return iter;
|
||||
}
|
||||
|
||||
PtrFunction Project::findByEntry(uint32_t entry)
|
||||
ilFunction Project::findByEntry(uint32_t entry)
|
||||
{
|
||||
/* Search procedure list for one with appropriate entry point */
|
||||
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[entry](const PtrFunction &f) { return f->procEntry==entry; });
|
||||
if(iter==pProcList.end())
|
||||
return nullptr;
|
||||
return *iter;
|
||||
[entry](const Function &f) { return f.procEntry==entry; });
|
||||
return iter;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Search procedure list for one with given name
|
||||
*/
|
||||
PtrFunction Project::findByName(const QString &name)
|
||||
ilFunction Project::createFunction(FunctionType *f,const QString &name)
|
||||
{
|
||||
ilFunction iter= std::find_if(pProcList.begin(),pProcList.end(),
|
||||
[name](const PtrFunction &f) { return f->name==name; });
|
||||
if(iter==pProcList.end())
|
||||
return nullptr;
|
||||
return *iter;
|
||||
}
|
||||
PtrFunction Project::createFunction(FunctionType *f,const QString &name,SegOffAddr addr)
|
||||
{
|
||||
PtrFunction func(Function::Create(f,0,name,0));
|
||||
pProcList.push_back(func);
|
||||
// FIXME: use provided segment addr !
|
||||
func->procEntry = addr.addr;
|
||||
if(!callGraph) {
|
||||
/* Set up call graph initial node */
|
||||
callGraph = new CALL_GRAPH;
|
||||
callGraph->proc = func;
|
||||
/* The entry state info is for the first procedure */
|
||||
func->state = m_entry_state;
|
||||
|
||||
}
|
||||
|
||||
emit newFunctionCreated(func);
|
||||
return func;
|
||||
pProcList.push_back(*Function::Create(f,0,name,0));
|
||||
return (++pProcList.rbegin()).base();
|
||||
}
|
||||
|
||||
int Project::getSymIdxByAdd(uint32_t adr)
|
||||
int Project::getSymIdxByAddr(uint32_t adr)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < symtab.size(); i++)
|
||||
@ -133,106 +97,8 @@ Project *Project::get()
|
||||
s_instance=new Project;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
|
||||
SourceMachine *Project::machine()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Project::addCommand(Command *cmd) {
|
||||
bool res = m_project_command_stream.add(cmd);
|
||||
emit commandListChanged();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Project::addCommand(PtrFunction f, Command *cmd)
|
||||
{
|
||||
bool res = m_function_streams[f].add(cmd);
|
||||
emit commandListChanged();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Project::hasCommands(const PtrFunction & f)
|
||||
{
|
||||
auto iter = m_function_streams.find(f);
|
||||
if(iter!=m_function_streams.end()) {
|
||||
return not iter->second.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandStream *Project::functionCommands(const PtrFunction & f)
|
||||
{
|
||||
if(f==nullptr)
|
||||
return nullptr;
|
||||
auto iter = m_function_streams.find(f);
|
||||
if(iter!=m_function_streams.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Project::onCommandStreamFinished(bool state)
|
||||
{
|
||||
if(false==state) {
|
||||
m_error_state = true;
|
||||
}
|
||||
}
|
||||
void Project::dumpAllErrors() {
|
||||
for(QPair<Command *,QString> v : m_command_ctx.m_failures) {
|
||||
qDebug() << QString("%1 command failed with : %2").arg(v.first->name()).arg(v.second);
|
||||
}
|
||||
}
|
||||
|
||||
void Project::setLoader(DosLoader * ldr)
|
||||
{
|
||||
m_selected_loader = ldr;
|
||||
emit loaderSelected();
|
||||
}
|
||||
bool Project::addLoadCommands(QString fname)
|
||||
{
|
||||
if(!addCommand(new LoaderSelection(fname)))
|
||||
return false;
|
||||
if(!addCommand(new LoaderApplication(fname))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Project::processAllCommands()
|
||||
{
|
||||
m_command_ctx.m_project = this;
|
||||
m_project_command_stream.processAll(&m_command_ctx);
|
||||
emit commandListChanged();
|
||||
}
|
||||
void Project::processCommands(int count) {
|
||||
m_command_ctx.m_project = this;
|
||||
while(count--) {
|
||||
if(false==m_project_command_stream.processOne(&m_command_ctx)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit commandListChanged();
|
||||
}
|
||||
void Project::processFunctionCommands(const PtrFunction &func,int count) {
|
||||
m_command_ctx.m_project = this;
|
||||
m_command_ctx.m_func = func;
|
||||
CommandStream *cs = functionCommands(func);
|
||||
if(nullptr==cs)
|
||||
return;
|
||||
while(count--) {
|
||||
if(false==cs->processOne(&m_command_ctx)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
emit commandListChanged();
|
||||
emit functionUpdate(func);
|
||||
}
|
||||
void Project::resetCommandsAndErrorState()
|
||||
{
|
||||
m_error_state = false;
|
||||
m_command_ctx.reset();
|
||||
m_command_ctx.m_project = this;
|
||||
m_project_command_stream.clear();
|
||||
}
|
||||
|
||||
@ -69,8 +69,8 @@ static bool isLong22 (iICODE pIcode, iICODE pEnd, iICODE &off)
|
||||
// preincrement because pIcode is not checked here
|
||||
iICODE icodes[] = { ++pIcode,++pIcode,++pIcode };
|
||||
if ( icodes[1]->ll()->match(iCMP) and
|
||||
(isJCond ((llIcode)icodes[0]->ll()->getOpcode())) and
|
||||
(isJCond ((llIcode)icodes[2]->ll()->getOpcode())))
|
||||
(isJCond (icodes[0]->ll()->getOpcode())) and
|
||||
(isJCond (icodes[2]->ll()->getOpcode())))
|
||||
{
|
||||
off = initial_icode;
|
||||
advance(off,2);
|
||||
@ -500,7 +500,7 @@ int Function::findForwardLongUses(int loc_ident_idx, const ID &pLocId, iICODE be
|
||||
* JX lab
|
||||
* => HLI_JCOND (regH:regL X 0) lab
|
||||
* This is better code than HLI_JCOND (HI(regH:regL) | LO(regH:regL)) */
|
||||
else if (pIcode->ll()->match(iOR) and (next1 != pEnd) and (isJCond ((llIcode)next1->ll()->getOpcode())))
|
||||
else if (pIcode->ll()->match(iOR) and (next1 != pEnd) and (isJCond (next1->ll()->getOpcode())))
|
||||
{
|
||||
if (pLocId.longId().srcDstRegMatch(pIcode,pIcode))
|
||||
{
|
||||
|
||||
582
src/scanner.cpp
582
src/scanner.cpp
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*****************************************************************************
|
||||
* dcc project scanner module
|
||||
* Implements a simple state driven scanner to convert 8086 machine code into
|
||||
* I-code
|
||||
@ -19,7 +19,6 @@
|
||||
#define S_EXT 0x000200 /* sign extend */
|
||||
#define OP386 0x000400 /* 386 op-code */
|
||||
#define NSP 0x000800 /* NOT_HLL if SP is src or dst */
|
||||
// defined in Enums.h #define ICODEMASK 0xFF00FF /* Masks off parser flags */
|
||||
|
||||
static void rm(int i);
|
||||
static void modrm(int i);
|
||||
@ -51,15 +50,15 @@ static void none1(int i);
|
||||
static void none2(int i);
|
||||
static void checkInt(int i);
|
||||
|
||||
#define iZERO (llIcode)0 // For neatness
|
||||
#define IC llIcode
|
||||
|
||||
static struct {
|
||||
struct StateTabelEntry {
|
||||
void (*state1)(int);
|
||||
void (*state2)(int);
|
||||
uint32_t flg;
|
||||
llIcode opcode;
|
||||
} stateTable[] = {
|
||||
};
|
||||
static const StateTabelEntry stateTable[] = {
|
||||
{ modrm, none2, B , iADD }, /* 00 */
|
||||
{ modrm, none2, 0 , iADD }, /* 01 */
|
||||
{ modrm, none2, TO_REG | B , iADD }, /* 02 */
|
||||
@ -69,258 +68,258 @@ static struct {
|
||||
{ segop, none2, NO_SRC , iPUSH }, /* 06 */
|
||||
{ segop, none2, NO_SRC , iPOP }, /* 07 */
|
||||
{ modrm, none2, B , iOR }, /* 08 */
|
||||
{ modrm, none2, NSP , iOR }, /* 09 */
|
||||
{ modrm, none2, TO_REG | B , iOR }, /* 0A */
|
||||
{ modrm, none2, TO_REG | NSP , iOR }, /* 0B */
|
||||
{ data1, axImp, B , iOR }, /* 0C */
|
||||
{ data2, axImp, 0 , iOR }, /* 0D */
|
||||
{ segop, none2, NO_SRC , iPUSH }, /* 0E */
|
||||
{ none1, none2, OP386 , iZERO }, /* 0F */
|
||||
{ modrm, none2, B , iADC }, /* 10 */
|
||||
{ modrm, none2, NSP , iADC }, /* 11 */
|
||||
{ modrm, none2, TO_REG | B , iADC }, /* 12 */
|
||||
{ modrm, none2, TO_REG | NSP , iADC }, /* 13 */
|
||||
{ data1, axImp, B , iADC }, /* 14 */
|
||||
{ data2, axImp, 0 , iADC }, /* 15 */
|
||||
{ segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */
|
||||
{ segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */
|
||||
{ modrm, none2, B , iSBB }, /* 18 */
|
||||
{ modrm, none2, NSP , iSBB }, /* 19 */
|
||||
{ modrm, none2, TO_REG | B , iSBB }, /* 1A */
|
||||
{ modrm, none2, TO_REG | NSP , iSBB }, /* 1B */
|
||||
{ data1, axImp, B , iSBB }, /* 1C */
|
||||
{ data2, axImp, 0 , iSBB }, /* 1D */
|
||||
{ segop, none2, NO_SRC , iPUSH }, /* 1E */
|
||||
{ segop, none2, NO_SRC , iPOP }, /* 1F */
|
||||
{ modrm, none2, B , iAND }, /* 20 */
|
||||
{ modrm, none2, NSP , iAND }, /* 21 */
|
||||
{ modrm, none2, TO_REG | B , iAND }, /* 22 */
|
||||
{ modrm, none2, TO_REG | NSP , iAND }, /* 23 */
|
||||
{ data1, axImp, B , iAND }, /* 24 */
|
||||
{ data2, axImp, 0 , iAND }, /* 25 */
|
||||
{ prefix, none2, 0 , (IC)rES}, /* 26 */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */
|
||||
{ modrm, none2, B , iSUB }, /* 28 */
|
||||
{ modrm, none2, 0 , iSUB }, /* 29 */
|
||||
{ modrm, none2, TO_REG | B , iSUB }, /* 2A */
|
||||
{ modrm, none2, TO_REG , iSUB }, /* 2B */
|
||||
{ data1, axImp, B , iSUB }, /* 2C */
|
||||
{ data2, axImp, 0 , iSUB }, /* 2D */
|
||||
{ prefix, none2, 0 , (IC)rCS}, /* 2E */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */
|
||||
{ modrm, none2, B , iXOR }, /* 30 */
|
||||
{ modrm, none2, NSP , iXOR }, /* 31 */
|
||||
{ modrm, none2, TO_REG | B , iXOR }, /* 32 */
|
||||
{ modrm, none2, TO_REG | NSP , iXOR }, /* 33 */
|
||||
{ data1, axImp, B , iXOR }, /* 34 */
|
||||
{ data2, axImp, 0 , iXOR }, /* 35 */
|
||||
{ prefix, none2, 0 , (IC)rSS}, /* 36 */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */
|
||||
{ modrm, none2, B , iCMP }, /* 38 */
|
||||
{ modrm, none2, NSP , iCMP }, /* 39 */
|
||||
{ modrm, none2, TO_REG | B , iCMP }, /* 3A */
|
||||
{ modrm, none2, TO_REG | NSP , iCMP }, /* 3B */
|
||||
{ data1, axImp, B , iCMP }, /* 3C */
|
||||
{ data2, axImp, 0 , iCMP }, /* 3D */
|
||||
{ prefix, none2, 0 , (IC)rDS}, /* 3E */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */
|
||||
{ regop, none2, 0 , iINC }, /* 40 */
|
||||
{ regop, none2, 0 , iINC }, /* 41 */
|
||||
{ regop, none2, 0 , iINC }, /* 42 */
|
||||
{ regop, none2, 0 , iINC }, /* 43 */
|
||||
{ regop, none2, NOT_HLL , iINC }, /* 44 */
|
||||
{ regop, none2, 0 , iINC }, /* 45 */
|
||||
{ regop, none2, 0 , iINC }, /* 46 */
|
||||
{ regop, none2, 0 , iINC }, /* 47 */
|
||||
{ regop, none2, 0 , iDEC }, /* 48 */
|
||||
{ regop, none2, 0 , iDEC }, /* 49 */
|
||||
{ regop, none2, 0 , iDEC }, /* 4A */
|
||||
{ regop, none2, 0 , iDEC }, /* 4B */
|
||||
{ regop, none2, NOT_HLL , iDEC }, /* 4C */
|
||||
{ regop, none2, 0 , iDEC }, /* 4D */
|
||||
{ regop, none2, 0 , iDEC }, /* 4E */
|
||||
{ regop, none2, 0 , iDEC }, /* 4F */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 50 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 51 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 52 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 53 */
|
||||
{ regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 55 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 56 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 57 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 58 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 59 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5A */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5B */
|
||||
{ regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5D */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5E */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5F */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */
|
||||
{ none1, none2, OP386 , iZERO }, /* 63 */
|
||||
{ none1, none2, OP386 , iZERO }, /* 64 */
|
||||
{ none1, none2, OP386 , iZERO }, /* 65 */
|
||||
{ none1, none2, OP386 , iZERO }, /* 66 */
|
||||
{ none1, none2, OP386 , iZERO }, /* 67 */
|
||||
{ data2, none2, NO_SRC , iPUSH }, /* 68 */
|
||||
{ modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */
|
||||
{ data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */
|
||||
{ modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */
|
||||
{ strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */
|
||||
{ strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */
|
||||
{ strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */
|
||||
{ strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */
|
||||
{ dispS, none2, NOT_HLL , iJO }, /* 70 */
|
||||
{ dispS, none2, NOT_HLL , iJNO }, /* 71 */
|
||||
{ dispS, none2, 0 , iJB }, /* 72 */
|
||||
{ dispS, none2, 0 , iJAE }, /* 73 */
|
||||
{ dispS, none2, 0 , iJE }, /* 74 */
|
||||
{ dispS, none2, 0 , iJNE }, /* 75 */
|
||||
{ dispS, none2, 0 , iJBE }, /* 76 */
|
||||
{ dispS, none2, 0 , iJA }, /* 77 */
|
||||
{ dispS, none2, 0 , iJS }, /* 78 */
|
||||
{ dispS, none2, 0 , iJNS }, /* 79 */
|
||||
{ dispS, none2, NOT_HLL , iJP }, /* 7A */
|
||||
{ dispS, none2, NOT_HLL , iJNP }, /* 7B */
|
||||
{ dispS, none2, 0 , iJL }, /* 7C */
|
||||
{ dispS, none2, 0 , iJGE }, /* 7D */
|
||||
{ dispS, none2, 0 , iJLE }, /* 7E */
|
||||
{ dispS, none2, 0 , iJG }, /* 7F */
|
||||
{ immed, data1, B , iZERO }, /* 80 */
|
||||
{ immed, data2, NSP , iZERO }, /* 81 */
|
||||
{ immed, data1, B , iZERO }, /* 82 */ /* ?? */
|
||||
{ immed, data1, NSP | S_EXT , iZERO }, /* 83 */
|
||||
{ modrm, none2, TO_REG | B , iTEST }, /* 84 */
|
||||
{ modrm, none2, TO_REG | NSP , iTEST }, /* 85 */
|
||||
{ modrm, none2, TO_REG | B , iXCHG }, /* 86 */
|
||||
{ modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */
|
||||
{ modrm, none2, B , iMOV }, /* 88 */
|
||||
{ modrm, none2, 0 , iMOV }, /* 89 */
|
||||
{ modrm, none2, TO_REG | B , iMOV }, /* 8A */
|
||||
{ modrm, none2, TO_REG , iMOV }, /* 8B */
|
||||
{ segrm, none2, NSP , iMOV }, /* 8C */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */
|
||||
{ segrm, none2, TO_REG | NSP , iMOV }, /* 8E */
|
||||
{ memReg0, none2, NO_SRC , iPOP }, /* 8F */
|
||||
{ none1, none2, NO_OPS , iNOP }, /* 90 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 91 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 92 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 93 */
|
||||
{ regop, axImp, NOT_HLL , iXCHG }, /* 94 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 95 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 96 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 97 */
|
||||
{ alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */
|
||||
{axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */
|
||||
{ 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, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */
|
||||
{ dispM, axImp, B , iMOV }, /* A0 */
|
||||
{ dispM, axImp, 0 , iMOV }, /* A1 */
|
||||
{ dispM, axImp, TO_REG | B , iMOV }, /* A2 */
|
||||
{ dispM, axImp, TO_REG , iMOV }, /* A3 */
|
||||
{ strop, memImp, B | IM_OPS , iMOVS }, /* A4 */
|
||||
{ strop, memImp, IM_OPS , iMOVS }, /* A5 */
|
||||
{ strop, memImp, B | IM_OPS , iCMPS }, /* A6 */
|
||||
{ strop, memImp, IM_OPS , iCMPS }, /* A7 */
|
||||
{ data1, axImp, B , iTEST }, /* A8 */
|
||||
{ data2, axImp, 0 , iTEST }, /* A9 */
|
||||
{ strop, memImp, B | IM_OPS , iSTOS }, /* AA */
|
||||
{ strop, memImp, IM_OPS , iSTOS }, /* AB */
|
||||
{ strop, memImp, B | IM_OPS , iLODS }, /* AC */
|
||||
{ strop, memImp, IM_OPS , iLODS }, /* AD */
|
||||
{ strop, memImp, B | IM_OPS , iSCAS }, /* AE */
|
||||
{ strop, memImp, IM_OPS , iSCAS }, /* AF */
|
||||
{ regop, data1, B , iMOV }, /* B0 */
|
||||
{ regop, data1, B , iMOV }, /* B1 */
|
||||
{ regop, data1, B , iMOV }, /* B2 */
|
||||
{ regop, data1, B , iMOV }, /* B3 */
|
||||
{ regop, data1, B , iMOV }, /* B4 */
|
||||
{ regop, data1, B , iMOV }, /* B5 */
|
||||
{ regop, data1, B , iMOV }, /* B6 */
|
||||
{ regop, data1, B , iMOV }, /* B7 */
|
||||
{ regop, data2, 0 , iMOV }, /* B8 */
|
||||
{ regop, data2, 0 , iMOV }, /* B9 */
|
||||
{ regop, data2, 0 , iMOV }, /* BA */
|
||||
{ regop, data2, 0 , iMOV }, /* BB */
|
||||
{ regop, data2, NOT_HLL , iMOV }, /* BC */
|
||||
{ regop, data2, 0 , iMOV }, /* BD */
|
||||
{ regop, data2, 0 , iMOV }, /* BE */
|
||||
{ regop, data2, 0 , iMOV }, /* BF */
|
||||
{ shift, data1, B , iZERO }, /* C0 */
|
||||
{ shift, data1, NSP | SRC_B , iZERO }, /* C1 */
|
||||
{ data2, none2, 0 , iRET }, /* C2 */
|
||||
{ none1, none2, NO_OPS , iRET }, /* C3 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */
|
||||
{ memReg0, data1, B , iMOV }, /* C6 */
|
||||
{ memReg0, data2, 0 , iMOV }, /* C7 */
|
||||
{ data2, data1, 0 , iENTER}, /* C8 */
|
||||
{ none1, none2, NO_OPS , iLEAVE}, /* C9 */
|
||||
{ data2, none2, 0 , iRETF }, /* CA */
|
||||
{ none1, none2, NO_OPS , iRETF }, /* CB */
|
||||
{ const3, none2, NOT_HLL , iINT }, /* CC */
|
||||
{ data1,checkInt, NOT_HLL , iINT }, /* CD */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */
|
||||
{ shift, const1, B , iZERO }, /* D0 */
|
||||
{ shift, const1, SRC_B , iZERO }, /* D1 */
|
||||
{ shift, none1, B , iZERO }, /* D2 */
|
||||
{ shift, none1, SRC_B , iZERO }, /* D3 */
|
||||
{ data1, axImp, NOT_HLL , iAAM }, /* D4 */
|
||||
{ data1, axImp, NOT_HLL , iAAD }, /* D5 */
|
||||
{ none1, none2, 0 , iZERO }, /* D6 */
|
||||
{ memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* D8 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* D9 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DA */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DB */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DC */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DD */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DE */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* Df */
|
||||
{ dispS, none2, 0 , iLOOPNE}, /* E0 */
|
||||
{ dispS, none2, 0 , iLOOPE}, /* E1 */
|
||||
{ dispS, none2, 0 , iLOOP }, /* E2 */
|
||||
{ dispS, none2, 0 , iJCXZ }, /* E3 */
|
||||
{ data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */
|
||||
{ data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */
|
||||
{ data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */
|
||||
{ data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */
|
||||
{ dispN, none2, 0 , iCALL }, /* E8 */
|
||||
{ dispN, none2, 0 , iJMP }, /* E9 */
|
||||
{ dispF, none2, 0 , iJMPF }, /* EA */
|
||||
{ dispS, none2, 0 , iJMP }, /* EB */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */
|
||||
{ none1, none2, 0 , iZERO }, /* F1 */
|
||||
{ prefix, none2, 0 , iREPNE}, /* F2 */
|
||||
{ prefix, none2, 0 , iREPE }, /* F3 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */
|
||||
{ none1, none2, NO_OPS , iCMC }, /* F5 */
|
||||
{ arith, none1, B , iZERO }, /* F6 */
|
||||
{ arith, none1, NSP , iZERO }, /* F7 */
|
||||
{ none1, none2, NO_OPS , iCLC }, /* F8 */
|
||||
{ none1, none2, NO_OPS , iSTC }, /* F9 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */
|
||||
{ none1, none2, NO_OPS , iCLD }, /* FC */
|
||||
{ none1, none2, NO_OPS , iSTD }, /* FD */
|
||||
{ trans, none1, B , iZERO }, /* FE */
|
||||
{ trans, none1, NSP , iZERO } /* FF */
|
||||
{ modrm, none2, NSP , iOR }, /* 09 */
|
||||
{ modrm, none2, TO_REG | B , iOR }, /* 0A */
|
||||
{ modrm, none2, TO_REG | NSP , iOR }, /* 0B */
|
||||
{ data1, axImp, B , iOR }, /* 0C */
|
||||
{ data2, axImp, 0 , iOR }, /* 0D */
|
||||
{ segop, none2, NO_SRC , iPUSH }, /* 0E */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 0F */
|
||||
{ modrm, none2, B , iADC }, /* 10 */
|
||||
{ modrm, none2, NSP , iADC }, /* 11 */
|
||||
{ modrm, none2, TO_REG | B , iADC }, /* 12 */
|
||||
{ modrm, none2, TO_REG | NSP , iADC }, /* 13 */
|
||||
{ data1, axImp, B , iADC }, /* 14 */
|
||||
{ data2, axImp, 0 , iADC }, /* 15 */
|
||||
{ segop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 16 */
|
||||
{ segop, none2, NOT_HLL | NO_SRC , iPOP }, /* 17 */
|
||||
{ modrm, none2, B , iSBB }, /* 18 */
|
||||
{ modrm, none2, NSP , iSBB }, /* 19 */
|
||||
{ modrm, none2, TO_REG | B , iSBB }, /* 1A */
|
||||
{ modrm, none2, TO_REG | NSP , iSBB }, /* 1B */
|
||||
{ data1, axImp, B , iSBB }, /* 1C */
|
||||
{ data2, axImp, 0 , iSBB }, /* 1D */
|
||||
{ segop, none2, NO_SRC , iPUSH }, /* 1E */
|
||||
{ segop, none2, NO_SRC , iPOP }, /* 1F */
|
||||
{ modrm, none2, B , iAND }, /* 20 */
|
||||
{ modrm, none2, NSP , iAND }, /* 21 */
|
||||
{ modrm, none2, TO_REG | B , iAND }, /* 22 */
|
||||
{ modrm, none2, TO_REG | NSP , iAND }, /* 23 */
|
||||
{ data1, axImp, B , iAND }, /* 24 */
|
||||
{ data2, axImp, 0 , iAND }, /* 25 */
|
||||
{ prefix, none2, 0 , (IC)rES}, /* 26 */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAA }, /* 27 */
|
||||
{ modrm, none2, B , iSUB }, /* 28 */
|
||||
{ modrm, none2, 0 , iSUB }, /* 29 */
|
||||
{ modrm, none2, TO_REG | B , iSUB }, /* 2A */
|
||||
{ modrm, none2, TO_REG , iSUB }, /* 2B */
|
||||
{ data1, axImp, B , iSUB }, /* 2C */
|
||||
{ data2, axImp, 0 , iSUB }, /* 2D */
|
||||
{ prefix, none2, 0 , (IC)rCS}, /* 2E */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iDAS }, /* 2F */
|
||||
{ modrm, none2, B , iXOR }, /* 30 */
|
||||
{ modrm, none2, NSP , iXOR }, /* 31 */
|
||||
{ modrm, none2, TO_REG | B , iXOR }, /* 32 */
|
||||
{ modrm, none2, TO_REG | NSP , iXOR }, /* 33 */
|
||||
{ data1, axImp, B , iXOR }, /* 34 */
|
||||
{ data2, axImp, 0 , iXOR }, /* 35 */
|
||||
{ prefix, none2, 0 , (IC)rSS}, /* 36 */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iAAA }, /* 37 */
|
||||
{ modrm, none2, B , iCMP }, /* 38 */
|
||||
{ modrm, none2, NSP , iCMP }, /* 39 */
|
||||
{ modrm, none2, TO_REG | B , iCMP }, /* 3A */
|
||||
{ modrm, none2, TO_REG | NSP , iCMP }, /* 3B */
|
||||
{ data1, axImp, B , iCMP }, /* 3C */
|
||||
{ data2, axImp, 0 , iCMP }, /* 3D */
|
||||
{ prefix, none2, 0 , (IC)rDS}, /* 3E */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iAAS }, /* 3F */
|
||||
{ regop, none2, 0 , iINC }, /* 40 */
|
||||
{ regop, none2, 0 , iINC }, /* 41 */
|
||||
{ regop, none2, 0 , iINC }, /* 42 */
|
||||
{ regop, none2, 0 , iINC }, /* 43 */
|
||||
{ regop, none2, NOT_HLL , iINC }, /* 44 */
|
||||
{ regop, none2, 0 , iINC }, /* 45 */
|
||||
{ regop, none2, 0 , iINC }, /* 46 */
|
||||
{ regop, none2, 0 , iINC }, /* 47 */
|
||||
{ regop, none2, 0 , iDEC }, /* 48 */
|
||||
{ regop, none2, 0 , iDEC }, /* 49 */
|
||||
{ regop, none2, 0 , iDEC }, /* 4A */
|
||||
{ regop, none2, 0 , iDEC }, /* 4B */
|
||||
{ regop, none2, NOT_HLL , iDEC }, /* 4C */
|
||||
{ regop, none2, 0 , iDEC }, /* 4D */
|
||||
{ regop, none2, 0 , iDEC }, /* 4E */
|
||||
{ regop, none2, 0 , iDEC }, /* 4F */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 50 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 51 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 52 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 53 */
|
||||
{ regop, none2, NOT_HLL | NO_SRC , iPUSH }, /* 54 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 55 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 56 */
|
||||
{ regop, none2, NO_SRC , iPUSH }, /* 57 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 58 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 59 */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5A */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5B */
|
||||
{ regop, none2, NOT_HLL | NO_SRC , iPOP }, /* 5C */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5D */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5E */
|
||||
{ regop, none2, NO_SRC , iPOP }, /* 5F */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPUSHA}, /* 60 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPOPA }, /* 61 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iBOUND}, /* 62 */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 63 */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 64 */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 65 */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 66 */
|
||||
{ none1, none2, OP386 , iINVALID }, /* 67 */
|
||||
{ data2, none2, NO_SRC , iPUSH }, /* 68 */
|
||||
{ modrm, data2, TO_REG | NSP , iIMUL }, /* 69 */
|
||||
{ data1, none2, S_EXT | NO_SRC , iPUSH }, /* 6A */
|
||||
{ modrm, data1, TO_REG | NSP | S_EXT , iIMUL }, /* 6B */
|
||||
{ strop, memImp, NOT_HLL | B|IM_OPS , iINS }, /* 6C */
|
||||
{ strop, memImp, NOT_HLL | IM_OPS , iINS }, /* 6D */
|
||||
{ strop, memImp, NOT_HLL | B|IM_OPS , iOUTS }, /* 6E */
|
||||
{ strop, memImp, NOT_HLL | IM_OPS , iOUTS }, /* 6F */
|
||||
{ dispS, none2, NOT_HLL , iJO }, /* 70 */
|
||||
{ dispS, none2, NOT_HLL , iJNO }, /* 71 */
|
||||
{ dispS, none2, 0 , iJB }, /* 72 */
|
||||
{ dispS, none2, 0 , iJAE }, /* 73 */
|
||||
{ dispS, none2, 0 , iJE }, /* 74 */
|
||||
{ dispS, none2, 0 , iJNE }, /* 75 */
|
||||
{ dispS, none2, 0 , iJBE }, /* 76 */
|
||||
{ dispS, none2, 0 , iJA }, /* 77 */
|
||||
{ dispS, none2, 0 , iJS }, /* 78 */
|
||||
{ dispS, none2, 0 , iJNS }, /* 79 */
|
||||
{ dispS, none2, NOT_HLL , iJP }, /* 7A */
|
||||
{ dispS, none2, NOT_HLL , iJNP }, /* 7B */
|
||||
{ dispS, none2, 0 , iJL }, /* 7C */
|
||||
{ dispS, none2, 0 , iJGE }, /* 7D */
|
||||
{ dispS, none2, 0 , iJLE }, /* 7E */
|
||||
{ dispS, none2, 0 , iJG }, /* 7F */
|
||||
{ immed, data1, B , iINVALID }, /* 80 */
|
||||
{ immed, data2, NSP , iINVALID }, /* 81 */
|
||||
{ immed, data1, B , iINVALID }, /* 82 */ /* ?? */
|
||||
{ immed, data1, NSP | S_EXT , iINVALID }, /* 83 */
|
||||
{ modrm, none2, TO_REG | B , iTEST }, /* 84 */
|
||||
{ modrm, none2, TO_REG | NSP , iTEST }, /* 85 */
|
||||
{ modrm, none2, TO_REG | B , iXCHG }, /* 86 */
|
||||
{ modrm, none2, TO_REG | NSP , iXCHG }, /* 87 */
|
||||
{ modrm, none2, B , iMOV }, /* 88 */
|
||||
{ modrm, none2, 0 , iMOV }, /* 89 */
|
||||
{ modrm, none2, TO_REG | B , iMOV }, /* 8A */
|
||||
{ modrm, none2, TO_REG , iMOV }, /* 8B */
|
||||
{ segrm, none2, NSP , iMOV }, /* 8C */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLEA }, /* 8D */
|
||||
{ segrm, none2, TO_REG | NSP , iMOV }, /* 8E */
|
||||
{ memReg0, none2, NO_SRC , iPOP }, /* 8F */
|
||||
{ none1, none2, NO_OPS , iNOP }, /* 90 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 91 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 92 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 93 */
|
||||
{ regop, axImp, NOT_HLL , iXCHG }, /* 94 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 95 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 96 */
|
||||
{ regop, axImp, 0 , iXCHG }, /* 97 */
|
||||
{ alImp, axImp, SRC_B | S_EXT , iSIGNEX}, /* 98 */
|
||||
{axSrcIm, axImp, IM_DST | S_EXT , iSIGNEX}, /* 99 */
|
||||
{ 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, NOT_HLL | NO_OPS , iPUSHF}, /* 9C */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iPOPF }, /* 9D */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iSAHF }, /* 9E */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iLAHF }, /* 9F */
|
||||
{ dispM, axImp, B , iMOV }, /* A0 */
|
||||
{ dispM, axImp, 0 , iMOV }, /* A1 */
|
||||
{ dispM, axImp, TO_REG | B , iMOV }, /* A2 */
|
||||
{ dispM, axImp, TO_REG , iMOV }, /* A3 */
|
||||
{ strop, memImp, B | IM_OPS , iMOVS }, /* A4 */
|
||||
{ strop, memImp, IM_OPS , iMOVS }, /* A5 */
|
||||
{ strop, memImp, B | IM_OPS , iCMPS }, /* A6 */
|
||||
{ strop, memImp, IM_OPS , iCMPS }, /* A7 */
|
||||
{ data1, axImp, B , iTEST }, /* A8 */
|
||||
{ data2, axImp, 0 , iTEST }, /* A9 */
|
||||
{ strop, memImp, B | IM_OPS , iSTOS }, /* AA */
|
||||
{ strop, memImp, IM_OPS , iSTOS }, /* AB */
|
||||
{ strop, memImp, B | IM_OPS , iLODS }, /* AC */
|
||||
{ strop, memImp, IM_OPS , iLODS }, /* AD */
|
||||
{ strop, memImp, B | IM_OPS , iSCAS }, /* AE */
|
||||
{ strop, memImp, IM_OPS , iSCAS }, /* AF */
|
||||
{ regop, data1, B , iMOV }, /* B0 */
|
||||
{ regop, data1, B , iMOV }, /* B1 */
|
||||
{ regop, data1, B , iMOV }, /* B2 */
|
||||
{ regop, data1, B , iMOV }, /* B3 */
|
||||
{ regop, data1, B , iMOV }, /* B4 */
|
||||
{ regop, data1, B , iMOV }, /* B5 */
|
||||
{ regop, data1, B , iMOV }, /* B6 */
|
||||
{ regop, data1, B , iMOV }, /* B7 */
|
||||
{ regop, data2, 0 , iMOV }, /* B8 */
|
||||
{ regop, data2, 0 , iMOV }, /* B9 */
|
||||
{ regop, data2, 0 , iMOV }, /* BA */
|
||||
{ regop, data2, 0 , iMOV }, /* BB */
|
||||
{ regop, data2, NOT_HLL , iMOV }, /* BC */
|
||||
{ regop, data2, 0 , iMOV }, /* BD */
|
||||
{ regop, data2, 0 , iMOV }, /* BE */
|
||||
{ regop, data2, 0 , iMOV }, /* BF */
|
||||
{ shift, data1, B , iINVALID }, /* C0 */
|
||||
{ shift, data1, NSP | SRC_B , iINVALID }, /* C1 */
|
||||
{ data2, none2, 0 , iRET }, /* C2 */
|
||||
{ none1, none2, NO_OPS , iRET }, /* C3 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLES }, /* C4 */
|
||||
{ memOnly, modrm, TO_REG | NSP , iLDS }, /* C5 */
|
||||
{ memReg0, data1, B , iMOV }, /* C6 */
|
||||
{ memReg0, data2, 0 , iMOV }, /* C7 */
|
||||
{ data2, data1, 0 , iENTER}, /* C8 */
|
||||
{ none1, none2, NO_OPS , iLEAVE}, /* C9 */
|
||||
{ data2, none2, 0 , iRETF }, /* CA */
|
||||
{ none1, none2, NO_OPS , iRETF }, /* CB */
|
||||
{ const3, none2, NOT_HLL , iINT }, /* CC */
|
||||
{ data1,checkInt, NOT_HLL , iINT }, /* CD */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iINTO }, /* CE */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iIRET }, /* Cf */
|
||||
{ shift, const1, B , iINVALID }, /* D0 */
|
||||
{ shift, const1, SRC_B , iINVALID }, /* D1 */
|
||||
{ shift, none1, B , iINVALID }, /* D2 */
|
||||
{ shift, none1, SRC_B , iINVALID }, /* D3 */
|
||||
{ data1, axImp, NOT_HLL , iAAM }, /* D4 */
|
||||
{ data1, axImp, NOT_HLL , iAAD }, /* D5 */
|
||||
{ none1, none2, 0 , iINVALID }, /* D6 */
|
||||
{ memImp, axImp, NOT_HLL | B| IM_OPS , iXLAT }, /* D7 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* D8 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* D9 */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DA */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DB */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DC */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DD */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* DE */
|
||||
{ escop, none2, FLOAT_OP , iESC }, /* Df */
|
||||
{ dispS, none2, 0 , iLOOPNE}, /* E0 */
|
||||
{ dispS, none2, 0 , iLOOPE}, /* E1 */
|
||||
{ dispS, none2, 0 , iLOOP }, /* E2 */
|
||||
{ dispS, none2, 0 , iJCXZ }, /* E3 */
|
||||
{ data1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* E4 */
|
||||
{ data1, axImp, NOT_HLL | NO_SRC , iIN }, /* E5 */
|
||||
{ data1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* E6 */
|
||||
{ data1, axImp, NOT_HLL | NO_SRC , iOUT }, /* E7 */
|
||||
{ dispN, none2, 0 , iCALL }, /* E8 */
|
||||
{ dispN, none2, 0 , iJMP }, /* E9 */
|
||||
{ dispF, none2, 0 , iJMPF }, /* EA */
|
||||
{ dispS, none2, 0 , iJMP }, /* EB */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iIN }, /* EC */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iIN }, /* ED */
|
||||
{ none1, axImp, NOT_HLL | B|NO_SRC , iOUT }, /* EE */
|
||||
{ none1, axImp, NOT_HLL | NO_SRC , iOUT }, /* EF */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iLOCK }, /* F0 */
|
||||
{ none1, none2, 0 , iINVALID }, /* F1 */
|
||||
{ prefix, none2, 0 , iREPNE}, /* F2 */
|
||||
{ prefix, none2, 0 , iREPE }, /* F3 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iHLT }, /* F4 */
|
||||
{ none1, none2, NO_OPS , iCMC }, /* F5 */
|
||||
{ arith, none1, B , iINVALID }, /* F6 */
|
||||
{ arith, none1, NSP , iINVALID }, /* F7 */
|
||||
{ none1, none2, NO_OPS , iCLC }, /* F8 */
|
||||
{ none1, none2, NO_OPS , iSTC }, /* F9 */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iCLI }, /* FA */
|
||||
{ none1, none2, NOT_HLL | NO_OPS , iSTI }, /* FB */
|
||||
{ none1, none2, NO_OPS , iCLD }, /* FC */
|
||||
{ none1, none2, NO_OPS , iSTD }, /* FD */
|
||||
{ trans, none1, B , iINVALID }, /* FE */
|
||||
{ trans, none1, NSP , iINVALID } /* FF */
|
||||
} ;
|
||||
|
||||
static uint16_t SegPrefix, RepPrefix;
|
||||
static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */
|
||||
static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */
|
||||
static const uint8_t *pInst; /* Ptr. to current uint8_t of instruction */
|
||||
static ICODE * pIcode; /* Ptr to Icode record filled in by scan() */
|
||||
|
||||
|
||||
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()->setFlags(I);
|
||||
// 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())));
|
||||
|
||||
}
|
||||
@ -538,7 +537,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
|
||||
int op;
|
||||
p = 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)
|
||||
{
|
||||
return (IP_OUT_OF_RANGE);
|
||||
@ -557,13 +556,13 @@ eErrorId scan(uint32_t ip, ICODE &p)
|
||||
|
||||
do
|
||||
{
|
||||
op = *pInst++; /* First state - trivial */
|
||||
op = *pInst++; /* First state - trivial */
|
||||
/* Convert to Icode.opcode */
|
||||
p.ll()->set(stateTable[op].opcode,stateTable[op].flg & ICODEMASK);
|
||||
(*stateTable[op].state1)(op); /* Second state */
|
||||
(*stateTable[op].state2)(op); /* Third state */
|
||||
(*stateTable[op].state1)(op); /* Second 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.x86_get_branch_target())
|
||||
@ -571,7 +570,7 @@ eErrorId scan(uint32_t ip, ICODE &p)
|
||||
}
|
||||
// LLOperand conv = convertOperand(*p.insn.get_dest());
|
||||
// assert(conv==p.ll()->dst);
|
||||
if (p.ll()->getOpcode())
|
||||
if (p.ll()->getOpcode()!=iINVALID)
|
||||
{
|
||||
/* Save bytes of image used */
|
||||
p.ll()->numBytes = (uint8_t)((pInst - prog.image()) - ip);
|
||||
@ -591,9 +590,10 @@ eErrorId scan(uint32_t ip, ICODE &p)
|
||||
static bool relocItem(const uint8_t *p)
|
||||
{
|
||||
PROG &prog(Project::get()->prog);
|
||||
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)
|
||||
return true;
|
||||
return false;
|
||||
@ -620,33 +620,33 @@ static int signex(uint8_t b)
|
||||
return ((b & 0x80)? (int)(0xFFFFFF00 | s): (int)s);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Updates the source or destination field for the current
|
||||
* icode, based on fdst and the TO_REG flag.
|
||||
* \note fdst == true is for the r/m part of the field (dest, unless TO_REG)
|
||||
* fdst == false is for reg part of the field
|
||||
/****************************************************************************
|
||||
* setAddress - Updates the source or destination field for the current
|
||||
* icode, based on fdst and the TO_REG flag.
|
||||
* Note: fdst == true is for the r/m part of the field (dest, unless TO_REG)
|
||||
* fdst == false is for reg part of the field
|
||||
***************************************************************************/
|
||||
static void setAddress(int i, bool fdst, uint16_t seg, int16_t reg, uint16_t off)
|
||||
{
|
||||
/* If not to register (i.e. to r/m), and talking about r/m, then this is dest */
|
||||
LLOperand *pm = (! bool(stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src();
|
||||
LLOperand *pm = (! (stateTable[i].flg & TO_REG) == fdst) ? &pIcode->ll()->m_dst : &pIcode->ll()->src();
|
||||
|
||||
/* Set segment. A later procedure (lookupAddr in proclist.c) will
|
||||
* provide the value of this segment in the field segValue.
|
||||
*/
|
||||
if (seg) /* segment override */
|
||||
if (seg) /* segment override */
|
||||
{
|
||||
pm->seg = pm->segOver = (eReg)seg;
|
||||
}
|
||||
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))
|
||||
{
|
||||
pm->seg = rSS; /* indexed on bp */
|
||||
pm->seg = rSS; /* indexed on bp */
|
||||
}
|
||||
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;
|
||||
|
||||
switch (mod) {
|
||||
case 0: /* No disp unless rm == 6 */
|
||||
case 0: /* No disp unless rm == 6 */
|
||||
if (rm == 6) {
|
||||
setAddress(i, true, SegPrefix, 0, getWord());
|
||||
pIcode->ll()->setFlags(WORD_OFF);
|
||||
@ -682,16 +682,16 @@ static void rm(int i)
|
||||
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, 0);
|
||||
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++));
|
||||
break;
|
||||
|
||||
case 2: /* 2 uint8_t disp */
|
||||
case 2: /* 2 uint8_t disp */
|
||||
setAddress(i, true, SegPrefix, rm + INDEX_BX_SI, getWord());
|
||||
pIcode->ll()->setFlags(WORD_OFF);
|
||||
break;
|
||||
|
||||
case 3: /* reg */
|
||||
case 3: /* reg */
|
||||
setAddress(i, true, 0, rm + rAX, 0);
|
||||
break;
|
||||
}
|
||||
@ -717,7 +717,7 @@ static void modrm(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)))
|
||||
pIcode->ll()->setOpcode((llIcode)0); // setCBW because it has that index
|
||||
@ -786,7 +786,7 @@ static void memImp(int i)
|
||||
static void memOnly(int )
|
||||
{
|
||||
if ((*pInst & 0xC0) == 0xC0)
|
||||
pIcode->ll()->setOpcode((llIcode)0);
|
||||
pIcode->ll()->setOpcode(iINVALID);
|
||||
}
|
||||
|
||||
|
||||
@ -796,7 +796,7 @@ static void memOnly(int )
|
||||
static void memReg0(int i)
|
||||
{
|
||||
if (REG(*pInst) or (*pInst & 0xC0) == 0xC0)
|
||||
pIcode->ll()->setOpcode((llIcode)0);
|
||||
pIcode->ll()->setOpcode(iINVALID);
|
||||
else
|
||||
rm(i);
|
||||
}
|
||||
@ -825,7 +825,7 @@ static void shift(int i)
|
||||
static llIcode shiftTable[8] =
|
||||
{
|
||||
(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)]);
|
||||
rm(i);
|
||||
@ -840,8 +840,8 @@ static void trans(int i)
|
||||
{
|
||||
static llIcode transTable[8] =
|
||||
{
|
||||
(llIcode)iINC, iDEC, (llIcode)iCALL, (llIcode)iCALLF,
|
||||
(llIcode)iJMP, (llIcode)iJMPF,(llIcode)iPUSH, (llIcode)0
|
||||
iINC, iDEC, iCALL, iCALLF,
|
||||
iJMP, iJMPF,iPUSH, (llIcode)0
|
||||
};
|
||||
LLInst *ll = pIcode->ll();
|
||||
// if(transTable[REG(*pInst)]==iPUSH) {
|
||||
@ -867,8 +867,8 @@ static void arith(int i)
|
||||
uint8_t opcode;
|
||||
static llIcode arithTable[8] =
|
||||
{
|
||||
iTEST, (llIcode)0, iNOT, iNEG,
|
||||
iMUL , iIMUL, iDIV, iIDIV
|
||||
iTEST, iINVALID, iNOT, iNEG,
|
||||
iMUL , iIMUL, iDIV, iIDIV
|
||||
};
|
||||
opcode = arithTable[REG(*pInst)];
|
||||
pIcode->ll()->setOpcode((llIcode)opcode);
|
||||
@ -883,7 +883,7 @@ static void arith(int i)
|
||||
else if (not (opcode == iNOT or opcode == iNEG))
|
||||
{
|
||||
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)
|
||||
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
|
||||
* on the stack. The procedure level is stored in the immediate
|
||||
* field. There is no source operand; therefore, the flag flg is
|
||||
* set to NO_OPS. */
|
||||
* set to NO_OPS. */
|
||||
if (pIcode->ll()->getOpcode() == iENTER)
|
||||
{
|
||||
pIcode->ll()->m_dst.off = getWord();
|
||||
@ -959,7 +959,7 @@ static void dispN(int )
|
||||
***************************************************************************/
|
||||
static void dispS(int )
|
||||
{
|
||||
/*long off =*/ signex(*pInst++); /* Signed displacement */
|
||||
/*long off =*/ signex(*pInst++); /* Signed displacement */
|
||||
|
||||
// decodeBranchTgt();
|
||||
}
|
||||
@ -984,7 +984,7 @@ static void dispF(int i)
|
||||
****************************************************************************/
|
||||
static void prefix(int )
|
||||
{
|
||||
if (pIcode->ll()->getOpcode() == iREPE or pIcode->ll()->getOpcode() == iREPNE)
|
||||
if ((pIcode->ll()->getOpcode() == iREPE) or (pIcode->ll()->getOpcode() == iREPNE))
|
||||
RepPrefix = pIcode->ll()->getOpcode();
|
||||
else
|
||||
SegPrefix = pIcode->ll()->getOpcode();
|
||||
@ -992,7 +992,7 @@ static void prefix(int )
|
||||
|
||||
inline void BumpOpcode(LLInst &ll)
|
||||
{
|
||||
llIcode ic((llIcode)ll.getOpcode());
|
||||
llIcode ic(ll.getOpcode());
|
||||
ic = (llIcode)(((int)ic)+1); // Bump this icode via the int type
|
||||
ll.setOpcode(ic);
|
||||
}
|
||||
@ -1068,7 +1068,7 @@ static void none1(int )
|
||||
****************************************************************************/
|
||||
static void none2(int )
|
||||
{
|
||||
if ( pIcode->ll()->srcIsImmed() )
|
||||
if ( pIcode->ll()->testFlags(I) )
|
||||
pIcode->ll()->setFlags(NO_OPS);
|
||||
}
|
||||
|
||||
|
||||
@ -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()
|
||||
@ -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)
|
||||
@ -1,7 +0,0 @@
|
||||
#include <QtTest/QTest>
|
||||
|
||||
class LoaderTest : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testDummy();
|
||||
};
|
||||
@ -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)
|
||||
@ -1,7 +0,0 @@
|
||||
#include <QtTest/QTest>
|
||||
|
||||
class MemoryChunkTest : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testIfConstructionWorksProperly();
|
||||
};
|
||||
@ -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)
|
||||
@ -1,9 +0,0 @@
|
||||
#include <QtTest/QTest>
|
||||
|
||||
class MemorySegmentCoordinatorTest : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testAddingSegments();
|
||||
void testAddingIntersectingSegments();
|
||||
void testSimpleQueries();
|
||||
};
|
||||
@ -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)
|
||||
@ -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
14
src/tests/loader.cpp
Normal 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
27
src/tests/project.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
18
src/udm.cpp
18
src/udm.cpp
@ -13,6 +13,7 @@
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
#include <CallGraph.h>
|
||||
extern Project g_proj;
|
||||
//static void displayCFG(Function * pProc);
|
||||
//static void displayDfs(BB * pBB);
|
||||
|
||||
@ -31,7 +32,7 @@ void Function::buildCFG(Disassembler &ds)
|
||||
|
||||
if (option.asm2)
|
||||
{
|
||||
ds.disassem(this->shared_from_this()); // Print 2nd pass assembler listing
|
||||
ds.disassem(this); // Print 2nd pass assembler listing
|
||||
return;
|
||||
}
|
||||
|
||||
@ -45,9 +46,10 @@ void Function::controlFlowAnalysis()
|
||||
{
|
||||
if (flg & PROC_ISLIB)
|
||||
return; /* Ignore library functions */
|
||||
derSeq *derivedG=nullptr;
|
||||
|
||||
/* Make cfg reducible and build derived sequences */
|
||||
derSeq *derivedG = checkReducibility();
|
||||
derivedG=checkReducibility();
|
||||
|
||||
if (option.VeryVerbose)
|
||||
derivedG->display();
|
||||
@ -78,13 +80,13 @@ void udm(void)
|
||||
Disassembler ds(2);
|
||||
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
|
||||
{
|
||||
Function &f(**iter);
|
||||
Function &f(*iter);
|
||||
if(option.CustomEntryPoint) {
|
||||
if(f.procEntry!=option.CustomEntryPoint) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
f.buildCFG(ds);
|
||||
iter->buildCFG(ds);
|
||||
}
|
||||
if (option.asm2)
|
||||
return;
|
||||
@ -95,8 +97,8 @@ void udm(void)
|
||||
* substitution algorithm */
|
||||
LivenessSet live_regs;
|
||||
if(option.CustomEntryPoint) {
|
||||
PtrFunction iter = proj->findByEntry(option.CustomEntryPoint);
|
||||
if(iter==nullptr) {
|
||||
ilFunction iter = proj->findByEntry(option.CustomEntryPoint);
|
||||
if(iter==proj->pProcList.end()) {
|
||||
qCritical()<< "No function found at entry point" << QString::number(option.CustomEntryPoint,16);
|
||||
return;
|
||||
}
|
||||
@ -107,12 +109,12 @@ void udm(void)
|
||||
proj->callGraph->proc = iter;
|
||||
return;
|
||||
}
|
||||
proj->pProcList.front()->dataFlow (live_regs);
|
||||
proj->pProcList.front().dataFlow (live_regs);
|
||||
|
||||
/* Control flow analysis - structuring algorithm */
|
||||
for (auto iter = proj->pProcList.rbegin(); iter!=proj->pProcList.rend(); ++iter)
|
||||
{
|
||||
(*iter)->controlFlowAnalysis();
|
||||
iter->controlFlowAnalysis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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());
|
||||
}
|
||||
@ -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
|
||||
@ -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&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>
|
||||
@ -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);
|
||||
}
|
||||
@ -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
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user