mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 15:05:27 +00:00
import
This commit is contained in:
commit
344d016104
81
.gitignore
vendored
Normal file
81
.gitignore
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
.DS_Store
|
||||
*.swp
|
||||
*.d
|
||||
*.o
|
||||
*.a
|
||||
|
||||
qemu/config-all-devices.mak
|
||||
|
||||
i386-softmmu/
|
||||
arm-softmmu/
|
||||
aarch64-softmmu/
|
||||
mips-softmmu/
|
||||
mips64-softmmu/
|
||||
mipsel-softmmu/
|
||||
mips64el-softmmu/
|
||||
sparc-softmmu/
|
||||
sparc64-softmmu/
|
||||
m68k-softmmu/
|
||||
|
||||
qapi-types.h
|
||||
qapi-visit.h
|
||||
x86_64-softmmu/
|
||||
tags
|
||||
qemu/config-host.ld
|
||||
qemu/config.log
|
||||
qemu/config.status
|
||||
qemu/config-host.h
|
||||
qemu/config-host.h-timestamp
|
||||
qemu/config-host.mak
|
||||
qemu/qapi-types.c
|
||||
qemu/qapi-visit.c
|
||||
|
||||
sample_x86
|
||||
sample_x86.exe
|
||||
sample_x86.static
|
||||
sample_arm
|
||||
sample_arm.exe
|
||||
sample_arm.static
|
||||
sample_arm64
|
||||
sample_arm64.exe
|
||||
sample_arm64.static
|
||||
sample_mips
|
||||
sample_mips.exe
|
||||
sample_mips.static
|
||||
sample_sparc
|
||||
sample_sparc.exe
|
||||
sample_sparc.static
|
||||
shellcode
|
||||
shellcode.exe
|
||||
shellcode.static
|
||||
sample_m68k
|
||||
sample_m68k.exe
|
||||
sample_m68k.static
|
||||
|
||||
libunicorn*.dll
|
||||
libunicorn*.so
|
||||
libunicorn*.dylib
|
||||
|
||||
unicorn.pc
|
||||
|
||||
unicorn.lib
|
||||
unicorn.dll
|
||||
unicorn_*.lib
|
||||
unicorn_*.dll
|
||||
|
||||
|
||||
docs/paper/*.dvi
|
||||
docs/paper/*.ps
|
||||
docs/paper/*.pdf
|
||||
docs/paper/*.htm
|
||||
docs/paper/*.log
|
||||
|
||||
*.tgz
|
||||
*.zip
|
||||
*.pyc
|
||||
_*.txt
|
||||
_*.diff
|
||||
tmp/
|
||||
|
||||
bindings/python/build/
|
||||
config.log
|
2
AUTHORS.TXT
Normal file
2
AUTHORS.TXT
Normal file
|
@ -0,0 +1,2 @@
|
|||
Nguyen Anh Quynh <aquynh -at- gmail.com>
|
||||
Dang Hoang Vu <dang.hvu -at- gmail.com>
|
218
COMPILE.TXT
Normal file
218
COMPILE.TXT
Normal file
|
@ -0,0 +1,218 @@
|
|||
This documentation explains how to compile, install & run Unicorn on MacOSX,
|
||||
Linux, *BSD & Solaris. We also show steps to cross-compile for Microsoft Windows.
|
||||
|
||||
*-*-*-*-*-*
|
||||
|
||||
[0] Dependencies
|
||||
|
||||
Unicorn requires few dependent packages as followings
|
||||
|
||||
- For Mac OS X, "pkg-config" is needed.
|
||||
Brew users can install "pkg-config" with:
|
||||
|
||||
$ brew install pkg-config
|
||||
|
||||
- For Linux, glib2-dev is needed.
|
||||
Ubuntu/Debian users can install this with:
|
||||
|
||||
$ sudo apt-get install libglib2.0-dev
|
||||
|
||||
- For Windows, cross-compile using Mingw. Mingw-glib2 is needed.
|
||||
|
||||
On Ubuntu 14.04 64-bit, do:
|
||||
|
||||
1. Download DEB packages for Mingw64 from https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251
|
||||
|
||||
2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings):
|
||||
|
||||
$ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb
|
||||
|
||||
To cross-compile for Windows 64-bit, install Mingw with:
|
||||
|
||||
$ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb
|
||||
|
||||
|
||||
|
||||
[1] Tailor Unicorn to your need.
|
||||
|
||||
Out of 8 archtitectures supported by Unicorn (Arm, Arm64, Mips, PPC, Sparc,
|
||||
SystemZ, XCore & X86), if you just need several selected archs, choose which
|
||||
ones you want to compile in by editing "config.mk" before going to next steps.
|
||||
|
||||
By default, all 8 architectures are compiled.
|
||||
|
||||
The other way of customize Unicorn without having to edit config.mk is to
|
||||
pass the desired options on the commandline to ./make.sh. Currently,
|
||||
Unicorn supports 3 options, as followings.
|
||||
|
||||
- UNICORN_ARCHS: specify list of architectures to compiled in.
|
||||
- UNICORN_STATIC: build static library.
|
||||
- UNICORN_SHARED: build dynamic (shared) library.
|
||||
|
||||
To avoid editing config.mk for these customization, we can pass their values to
|
||||
make.sh, as followings.
|
||||
|
||||
$ UNICORN_ARCHS="arm aarch64 x86" ./make.sh
|
||||
|
||||
NOTE: on commandline, put these values in front of ./make.sh, not after it.
|
||||
|
||||
For each option, refer to docs/README for more details.
|
||||
|
||||
|
||||
|
||||
[2] Compile from source
|
||||
|
||||
On *nix (such as MacOSX, Linux, *BSD, Solaris):
|
||||
|
||||
- To compile for current platform, run:
|
||||
|
||||
$ ./make.sh
|
||||
|
||||
- On 64-bit OS, run the command below to cross-compile Unicorn for 32-bit binary:
|
||||
|
||||
$ ./make.sh nix32
|
||||
|
||||
|
||||
|
||||
[3] Install Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris)
|
||||
|
||||
To install Unicorn, run:
|
||||
|
||||
$ sudo ./make.sh install
|
||||
|
||||
For FreeBSD/OpenBSD, where sudo is unavailable, run:
|
||||
|
||||
$ su; ./make.sh install
|
||||
|
||||
Users are then required to enter root password to copy Unicorn into machine
|
||||
system directories.
|
||||
|
||||
Afterwards, run ./tests/test* to see the tests disassembling sample code.
|
||||
|
||||
|
||||
NOTE: The core framework installed by "./make.sh install" consist of
|
||||
following files:
|
||||
|
||||
/usr/include/unicorn/unicorn.h
|
||||
/usr/include/unicorn/x86.h
|
||||
/usr/include/unicorn/arm.h
|
||||
/usr/include/unicorn/arm64.h
|
||||
/usr/include/unicorn/mips.h
|
||||
/usr/include/unicorn/ppc.h
|
||||
/usr/include/unicorn/sparc.h
|
||||
/usr/include/unicorn/m68k.h
|
||||
/usr/include/unicorn/platform.h
|
||||
/usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX)
|
||||
/usr/lib/libunicorn.a
|
||||
|
||||
|
||||
|
||||
[4] Cross-compile for Windows from *nix
|
||||
|
||||
To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64
|
||||
for 64-bit binaries) are required.
|
||||
|
||||
- To cross-compile Windows 32-bit binary, simply run:
|
||||
|
||||
$ ./make.sh cross-win32
|
||||
|
||||
- To cross-compile Windows 64-bit binary, run:
|
||||
|
||||
$ ./make.sh cross-win64
|
||||
|
||||
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then
|
||||
be used on Windows machine.
|
||||
|
||||
To run sample_x86.exe on Windows 32-bit, you need the following files:
|
||||
|
||||
- unicorn.dll
|
||||
- /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll
|
||||
- /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll
|
||||
- /usr/i686-w64-mingw32/lib/libwinpthread-1.dll
|
||||
|
||||
To run sample_x86.exe on Windows 64-bit, you need the following files:
|
||||
- unicorn.dll
|
||||
- /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll
|
||||
- /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll
|
||||
- /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll
|
||||
|
||||
Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit.
|
||||
For other architectures, run "sample_xxx.exe" found in the same directory.
|
||||
|
||||
|
||||
|
||||
[5] Cross-compile for iOS from Mac OSX.
|
||||
|
||||
To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required.
|
||||
|
||||
- To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run:
|
||||
$ ./make.sh ios_armv7
|
||||
|
||||
- To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run:
|
||||
$ ./make.sh ios_armv7s
|
||||
|
||||
- To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run:
|
||||
$ ./make.sh ios_arm64
|
||||
|
||||
- To cross-compile for all iDevices (armv7 + armv7s + arm64), run:
|
||||
$ ./make.sh ios
|
||||
|
||||
Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then
|
||||
be used on iOS devices.
|
||||
|
||||
|
||||
|
||||
[6] Cross-compile for Android
|
||||
|
||||
To cross-compile for Android (smartphone/tablet), Android NDK is required.
|
||||
NOTE: Only ARM and ARM64 are currently supported.
|
||||
|
||||
$ NDK=/android/android-ndk-r10e ./make.sh cross-android arm
|
||||
or
|
||||
$ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64
|
||||
|
||||
Resulted files libunicorn.so, libunicorn.a & tests/test* can then
|
||||
be used on Android devices.
|
||||
|
||||
|
||||
|
||||
[7] Compile on Windows with Cygwin
|
||||
|
||||
To compile under Cygwin gcc-mingw-w64-i686 or x86_64-w64-mingw32 run:
|
||||
|
||||
- To compile Windows 32-bit binary under Cygwin, run:
|
||||
|
||||
$ ./make.sh cygwin-mingw32
|
||||
|
||||
- To compile Windows 64-bit binary under Cygwin, run:
|
||||
|
||||
$ ./make.sh cygwin-mingw64
|
||||
|
||||
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then
|
||||
be used on Windows machine.
|
||||
|
||||
|
||||
|
||||
[8] By default, "cc" (default C compiler on the system) is used as compiler.
|
||||
|
||||
- To use "clang" compiler instead, run the command below:
|
||||
|
||||
$ ./make.sh clang
|
||||
|
||||
- To use "gcc" compiler instead, run:
|
||||
|
||||
$ ./make.sh gcc
|
||||
|
||||
|
||||
|
||||
[9] To uninstall Unicorn, run the command below:
|
||||
|
||||
$ sudo ./make.sh uninstall
|
||||
|
||||
|
||||
|
||||
[10] Language bindings
|
||||
|
||||
So far, only Python is supported by bindings in the main code.
|
||||
Look for the bindings under directory bindings/, and refer to README file
|
||||
of corresponding languages.
|
339
COPYING
Normal file
339
COPYING
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.
|
42
CREDITS.TXT
Normal file
42
CREDITS.TXT
Normal file
|
@ -0,0 +1,42 @@
|
|||
This file credits all the contributors of the Unicorn engine project.
|
||||
|
||||
|
||||
Key developers
|
||||
==============
|
||||
Nguyen Anh Quynh <aquynh -at- gmail.com>
|
||||
Dang Hoang Vu <dang.hvu -at- gmail.com>
|
||||
|
||||
|
||||
Beta testers (in no particular order)
|
||||
==============================
|
||||
Nguyen Tan Cong
|
||||
Loi Anh Tuan
|
||||
Edgar Barbosa
|
||||
Joxean Koret
|
||||
Chris Eagle
|
||||
Jay Little, Trail of Bits
|
||||
Jeong Wook Oh
|
||||
Luis Miras
|
||||
Yan Shoshitaishvili, Shellphish & UC Santa Barbara
|
||||
Erik Fischer
|
||||
Darel Griffin, NCC Group
|
||||
Anton Cherepanov
|
||||
Mohamed Saher (halsten)
|
||||
Tyler Colgan
|
||||
Jonathon Reinhart, jonathon.reinhart at gmail.com
|
||||
Blue Skeye
|
||||
Chris Maixner
|
||||
Pancake "radare"
|
||||
Ryan Hileman
|
||||
Tim "diff" Strazzere
|
||||
WanderingGlitch of the Zero Day Initiative
|
||||
Sascha Schirra
|
||||
François Serman
|
||||
|
||||
|
||||
Contributors (in no particular order)
|
||||
=====================================
|
||||
(Please let us know if you want to have your name here)
|
||||
|
||||
Nguyen Tan Cong
|
||||
Loi Anh Tuan
|
237
LEAK_VALGRIND
Normal file
237
LEAK_VALGRIND
Normal file
|
@ -0,0 +1,237 @@
|
|||
==25446== Memcheck, a memory error detector
|
||||
==25446== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
|
||||
==25446== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
|
||||
==25446== Command: ./samples/sample_x86.static -32
|
||||
==25446==
|
||||
==25446== Warning: set address range perms: large range [0xe30000, 0x14e30000) (defined)
|
||||
==25446== Conditional jump or move depends on uninitialised value(s)
|
||||
==25446== at 0x4379C1: tcg_target_init_x86_64 (tcg-target.c:2280)
|
||||
==25446== by 0x437F8F: tcg_context_init_x86_64 (tcg.c:372)
|
||||
==25446== by 0x4481A8: cpu_gen_init_x86_64 (translate-all.c:132)
|
||||
==25446== by 0x448953: tcg_exec_init_x86_64 (translate-all.c:709)
|
||||
==25446== by 0x40D390: tcg_init (accel.c:44)
|
||||
==25446== by 0x40D5E5: accel_init_machine (accel.c:114)
|
||||
==25446== by 0x40D3D5: configure_accelerator (accel.c:71)
|
||||
==25446== by 0x40D8B6: machine_initialize (vl.c:128)
|
||||
==25446== by 0x404F95: uc_open (uc.c:245)
|
||||
==25446== by 0x403637: test_i386 (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446== by 0x404A90: main (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446==
|
||||
==25446== Conditional jump or move depends on uninitialised value(s)
|
||||
==25446== at 0x4379F3: tcg_target_init_x86_64 (tcg-target.c:2295)
|
||||
==25446== by 0x437F8F: tcg_context_init_x86_64 (tcg.c:372)
|
||||
==25446== by 0x4481A8: cpu_gen_init_x86_64 (translate-all.c:132)
|
||||
==25446== by 0x448953: tcg_exec_init_x86_64 (translate-all.c:709)
|
||||
==25446== by 0x40D390: tcg_init (accel.c:44)
|
||||
==25446== by 0x40D5E5: accel_init_machine (accel.c:114)
|
||||
==25446== by 0x40D3D5: configure_accelerator (accel.c:71)
|
||||
==25446== by 0x40D8B6: machine_initialize (vl.c:128)
|
||||
==25446== by 0x404F95: uc_open (uc.c:245)
|
||||
==25446== by 0x403637: test_i386 (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446== by 0x404A90: main (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446==
|
||||
==25446== Thread 2:
|
||||
==25446== Conditional jump or move depends on uninitialised value(s)
|
||||
==25446== at 0x4849B2: disas_insn (translate.c:4748)
|
||||
==25446== by 0x492DC2: gen_intermediate_code_internal_x86_64 (translate.c:8382)
|
||||
==25446== by 0x492FF7: gen_intermediate_code_x86_64 (translate.c:8429)
|
||||
==25446== by 0x448288: cpu_x86_gen_code (translate-all.c:175)
|
||||
==25446== by 0x4494F2: tb_gen_code_x86_64 (translate-all.c:1087)
|
||||
==25446== by 0x43310D: tb_find_slow_x86_64 (cpu-exec.c:356)
|
||||
==25446== by 0x433290: tb_find_fast_x86_64 (cpu-exec.c:384)
|
||||
==25446== by 0x432C68: cpu_x86_exec (cpu-exec.c:203)
|
||||
==25446== by 0x40C49A: tcg_cpu_exec_x86_64 (cpus.c:178)
|
||||
==25446== by 0x40C515: tcg_exec_all_x86_64 (cpus.c:199)
|
||||
==25446== by 0x40C2F5: qemu_tcg_cpu_thread_fn_x86_64 (cpus.c:132)
|
||||
==25446== by 0x15C6D353: start_thread (in /usr/lib/libpthread-2.21.so)
|
||||
==25446==
|
||||
==25446==
|
||||
==25446== HEAP SUMMARY:
|
||||
==25446== in use at exit: 8,062 bytes in 156 blocks
|
||||
==25446== total heap usage: 583 allocs, 427 frees, 32,993,443 bytes allocated
|
||||
==25446==
|
||||
==25446== Thread 1:
|
||||
==25446== 7 bytes in 1 blocks are definitely lost in loss record 50 of 150
|
||||
==25446== at 0x15A59F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D6559: g_malloc (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x161EEDFE: g_strdup (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x445132: memory_region_init_x86_64 (memory.c:898)
|
||||
==25446== by 0x445BEC: memory_region_init_ram_x86_64 (memory.c:1152)
|
||||
==25446== by 0x4422A3: memory_map_x86_64 (memory.c:36)
|
||||
==25446== by 0x4057C1: uc_mem_map (uc.c:552)
|
||||
==25446== by 0x40366F: test_i386 (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446== by 0x404A90: main (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446==
|
||||
==25446== 8 bytes in 1 blocks are definitely lost in loss record 52 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40C362: qemu_tcg_init_vcpu_x86_64 (cpus.c:155)
|
||||
==25446== by 0x40C223: qemu_init_vcpu_x86_64 (cpus.c:95)
|
||||
==25446== by 0x456C07: x86_cpu_realizefn (cpu.c:2292)
|
||||
==25446== by 0x4129EF: device_set_realized (qdev.c:184)
|
||||
==25446== by 0x411AAD: property_set_bool (object.c:1504)
|
||||
==25446== by 0x410234: object_property_set (object.c:829)
|
||||
==25446== by 0x4122BB: object_property_set_qobject (qom-qobject.c:24)
|
||||
==25446== by 0x4104E4: object_property_set_bool (object.c:897)
|
||||
==25446== by 0x45072A: pc_new_cpu (pc.c:105)
|
||||
==25446== by 0x4507E3: pc_cpus_init (pc.c:130)
|
||||
==25446==
|
||||
==25446== 48 bytes in 1 blocks are definitely lost in loss record 102 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40C377: qemu_tcg_init_vcpu_x86_64 (cpus.c:156)
|
||||
==25446== by 0x40C223: qemu_init_vcpu_x86_64 (cpus.c:95)
|
||||
==25446== by 0x456C07: x86_cpu_realizefn (cpu.c:2292)
|
||||
==25446== by 0x4129EF: device_set_realized (qdev.c:184)
|
||||
==25446== by 0x411AAD: property_set_bool (object.c:1504)
|
||||
==25446== by 0x410234: object_property_set (object.c:829)
|
||||
==25446== by 0x4122BB: object_property_set_qobject (qom-qobject.c:24)
|
||||
==25446== by 0x4104E4: object_property_set_bool (object.c:897)
|
||||
==25446== by 0x45072A: pc_new_cpu (pc.c:105)
|
||||
==25446== by 0x4507E3: pc_cpus_init (pc.c:130)
|
||||
==25446==
|
||||
==25446== 144 bytes in 1 blocks are definitely lost in loss record 139 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x44BBB7: tcg_cpu_address_space_init_x86_64 (exec.c:403)
|
||||
==25446== by 0x40C347: qemu_tcg_init_vcpu_x86_64 (cpus.c:150)
|
||||
==25446== by 0x40C223: qemu_init_vcpu_x86_64 (cpus.c:95)
|
||||
==25446== by 0x456C07: x86_cpu_realizefn (cpu.c:2292)
|
||||
==25446== by 0x4129EF: device_set_realized (qdev.c:184)
|
||||
==25446== by 0x411AAD: property_set_bool (object.c:1504)
|
||||
==25446== by 0x410234: object_property_set (object.c:829)
|
||||
==25446== by 0x4122BB: object_property_set_qobject (qom-qobject.c:24)
|
||||
==25446== by 0x4104E4: object_property_set_bool (object.c:897)
|
||||
==25446== by 0x45072A: pc_new_cpu (pc.c:105)
|
||||
==25446==
|
||||
==25446== 320 bytes in 1 blocks are definitely lost in loss record 140 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x44D669: qemu_ram_alloc_from_ptr_x86_64 (exec.c:1092)
|
||||
==25446== by 0x44D752: qemu_ram_alloc_x86_64 (exec.c:1111)
|
||||
==25446== by 0x445C28: memory_region_init_ram_x86_64 (memory.c:1156)
|
||||
==25446== by 0x4422A3: memory_map_x86_64 (memory.c:36)
|
||||
==25446== by 0x4057C1: uc_mem_map (uc.c:552)
|
||||
==25446== by 0x40366F: test_i386 (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446== by 0x404A90: main (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446==
|
||||
==25446== 360 (96 direct, 264 indirect) bytes in 1 blocks are definitely lost in loss record 141 of 150
|
||||
==25446== at 0x15A59F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D6559: g_malloc (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40F68E: object_new_with_type (object.c:425)
|
||||
==25446== by 0x40F6FD: object_new (object.c:436)
|
||||
==25446== by 0x40D851: machine_initialize (vl.c:119)
|
||||
==25446== by 0x404F95: uc_open (uc.c:245)
|
||||
==25446== by 0x403637: test_i386 (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446== by 0x404A90: main (in /home/w00d/Workspace/unicorn/samples/sample_x86.static)
|
||||
==25446==
|
||||
==25446== 601 (80 direct, 521 indirect) bytes in 1 blocks are definitely lost in loss record 142 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F6AE: object_new_with_type (object.c:426)
|
||||
==25446== by 0x40F6FD: object_new (object.c:436)
|
||||
==25446== by 0x410A57: object_get_root (object.c:1041)
|
||||
==25446== by 0x412CF4: qdev_get_machine (qdev.c:278)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 143 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x44E837: memory_map_init_x86_64 (exec.c:1572)
|
||||
==25446== by 0x44E88D: cpu_exec_init_all_x86_64 (exec.c:1580)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 144 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x445B7B: memory_region_init_io_x86_64 (memory.c:1139)
|
||||
==25446== by 0x44E20D: io_mem_init (exec.c:1421)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 145 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x445B7B: memory_region_init_io_x86_64 (memory.c:1139)
|
||||
==25446== by 0x44E249: io_mem_init (exec.c:1422)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 146 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x445B7B: memory_region_init_io_x86_64 (memory.c:1139)
|
||||
==25446== by 0x44E282: io_mem_init (exec.c:1424)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 147 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x445BEC: memory_region_init_ram_x86_64 (memory.c:1152)
|
||||
==25446== by 0x4422A3: memory_map_x86_64 (memory.c:36)
|
||||
==25446==
|
||||
==25446== 616 (80 direct, 536 indirect) bytes in 1 blocks are definitely lost in loss record 148 of 150
|
||||
==25446== at 0x15A5C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||
==25446== by 0x161D65B1: g_malloc0 (in /usr/lib/libglib-2.0.so.0.4400.1)
|
||||
==25446== by 0x40FEFE: object_property_add (object.c:755)
|
||||
==25446== by 0x411957: object_property_add_str (object.c:1464)
|
||||
==25446== by 0x412219: object_instance_init (object.c:1699)
|
||||
==25446== by 0x40F117: object_init_with_type (object.c:310)
|
||||
==25446== by 0x40F0ED: object_init_with_type (object.c:306)
|
||||
==25446== by 0x40F2EB: object_initialize_with_type (object.c:340)
|
||||
==25446== by 0x40F34C: object_initialize (object.c:348)
|
||||
==25446== by 0x4450E7: memory_region_init_x86_64 (memory.c:892)
|
||||
==25446== by 0x445B7B: memory_region_init_io_x86_64 (memory.c:1139)
|
||||
==25446== by 0x44E2FE: subpage_init_x86_64 (exec.c:1438)
|
||||
==25446==
|
||||
==25446== LEAK SUMMARY:
|
||||
==25446== definitely lost: 1,183 bytes in 13 blocks
|
||||
==25446== indirectly lost: 4,001 bytes in 140 blocks
|
||||
==25446== possibly lost: 0 bytes in 0 blocks
|
||||
==25446== still reachable: 2,878 bytes in 3 blocks
|
||||
==25446== suppressed: 0 bytes in 0 blocks
|
||||
==25446== Reachable blocks (those to which a pointer was found) are not shown.
|
||||
==25446== To see them, rerun with: --leak-check=full --show-leak-kinds=all
|
||||
==25446==
|
||||
==25446== For counts of detected and suppressed errors, rerun with: -v
|
||||
==25446== Use --track-origins=yes to see where uninitialised values come from
|
||||
==25446== ERROR SUMMARY: 16 errors from 16 contexts (suppressed: 0 from 0)
|
326
Makefile
Normal file
326
Makefile
Normal file
|
@ -0,0 +1,326 @@
|
|||
# Unicorn Emulator Engine
|
||||
# By Dang Hoang Vu <dang.hvu -at- gmail.com>, 2015
|
||||
|
||||
|
||||
.PHONY: all clean install uninstall dist header
|
||||
|
||||
include config.mk
|
||||
include pkgconfig.mk # package version
|
||||
|
||||
LIBNAME = unicorn
|
||||
|
||||
GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) $(wildcard qemu/util/*.o) $(wildcard qemu/*.o) $(wildcard qemu/qom/*.o)\
|
||||
$(wildcard qemu/hw/core/*.o) $(wildcard qemu/qapi/*.o) $(wildcard qemu/qobject/*.o)
|
||||
|
||||
ifneq (,$(findstring x86,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,x86_64-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_X86
|
||||
UNICORN_TARGETS += x86_64-softmmu,
|
||||
endif
|
||||
ifneq (,$(findstring arm,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,arm-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_ARM
|
||||
UNICORN_TARGETS += arm-softmmu,
|
||||
endif
|
||||
ifneq (,$(findstring m68k,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,m68k-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_M68K
|
||||
UNICORN_TARGETS += m68k-softmmu,
|
||||
endif
|
||||
ifneq (,$(findstring aarch64,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,aarch64-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_ARM64
|
||||
UNICORN_TARGETS += aarch64-softmmu,
|
||||
endif
|
||||
ifneq (,$(findstring mips,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,mips-softmmu)
|
||||
UC_TARGET_OBJ += $(call GENOBJ,mipsel-softmmu)
|
||||
UC_TARGET_OBJ += $(call GENOBJ,mips64-softmmu)
|
||||
UC_TARGET_OBJ += $(call GENOBJ,mips64el-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_MIPS
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_MIPSEL
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_MIPS64
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_MIPS64EL
|
||||
UNICORN_TARGETS += mips-softmmu,
|
||||
UNICORN_TARGETS += mipsel-softmmu,
|
||||
UNICORN_TARGETS += mips64-softmmu,
|
||||
UNICORN_TARGETS += mips64el-softmmu,
|
||||
endif
|
||||
ifneq (,$(findstring sparc,$(UNICORN_ARCHS)))
|
||||
UC_TARGET_OBJ += $(call GENOBJ,sparc-softmmu)
|
||||
UC_TARGET_OBJ += $(call GENOBJ,sparc64-softmmu)
|
||||
UNICORN_CFLAGS += -DUNICORN_HAS_SPARC
|
||||
UNICORN_TARGETS += sparc-softmmu,sparc64-softmmu,
|
||||
endif
|
||||
|
||||
UNICORN_CFLAGS += -fPIC
|
||||
|
||||
# Verbose output?
|
||||
V ?= 0
|
||||
|
||||
ifeq ($(UNICORN_DEBUG),yes)
|
||||
CFLAGS += -O3
|
||||
else
|
||||
CFLAGS += -g
|
||||
endif
|
||||
|
||||
ifeq ($(CROSS),)
|
||||
CC ?= cc
|
||||
AR ?= ar
|
||||
RANLIB ?= ranlib
|
||||
STRIP ?= strip
|
||||
else
|
||||
CC ?= $(CROSS)-gcc
|
||||
AR ?= $(CROSS)-ar
|
||||
RANLIB ?= $(CROSS)-ranlib
|
||||
STRIP ?= $(CROSS)-strip
|
||||
GLIB="-L/usr/$(CROSS)/lib/ -lglib-2.0"
|
||||
endif
|
||||
|
||||
# Find GLIB
|
||||
ifndef GLIB
|
||||
GLIB = `pkg-config --libs glib-2.0`
|
||||
endif
|
||||
|
||||
ifeq ($(PKG_EXTRA),)
|
||||
PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR)
|
||||
else
|
||||
PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA)
|
||||
endif
|
||||
|
||||
API_MAJOR=$(shell echo `grep -e UC_API_MAJOR include/unicorn/unicorn.h | grep -v = | awk '{print $$3}'` | awk '{print $$1}')
|
||||
VERSION_EXT =
|
||||
|
||||
BIN_EXT =
|
||||
|
||||
IS_APPLE := $(shell $(CC) -dM -E - < /dev/null | grep __apple_build_version__ | wc -l | tr -d " ")
|
||||
ifeq ($(IS_APPLE),1)
|
||||
EXT = dylib
|
||||
VERSION_EXT = $(API_MAJOR).$(EXT)
|
||||
AR_EXT = a
|
||||
UNICORN_CFLAGS += -fvisibility=hidden
|
||||
else
|
||||
# Cygwin?
|
||||
IS_CYGWIN := $(shell $(CC) -dumpmachine | grep -i cygwin | wc -l)
|
||||
ifeq ($(IS_CYGWIN),1)
|
||||
EXT = dll
|
||||
AR_EXT = lib
|
||||
BIN_EXT = .exe
|
||||
else
|
||||
# mingw?
|
||||
IS_MINGW := $(shell $(CC) --version | grep -i mingw | wc -l)
|
||||
ifeq ($(IS_MINGW),1)
|
||||
EXT = dll
|
||||
AR_EXT = lib
|
||||
BIN_EXT = .exe
|
||||
else
|
||||
# Linux, *BSD
|
||||
EXT = so
|
||||
VERSION_EXT = $(EXT).$(API_MAJOR)
|
||||
AR_EXT = a
|
||||
UNICORN_CFLAGS += -fvisibility=hidden
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(UNICORN_SHARED),yes)
|
||||
ifeq ($(IS_MINGW),1)
|
||||
LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT)
|
||||
else ifeq ($(IS_CYGWIN),1)
|
||||
LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT)
|
||||
else # *nix
|
||||
LIBRARY = $(BLDIR)/lib$(LIBNAME).$(EXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(UNICORN_STATIC),yes)
|
||||
ifeq ($(IS_MINGW),1)
|
||||
ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT)
|
||||
else ifeq ($(IS_CYGWIN),1)
|
||||
ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT)
|
||||
else
|
||||
ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT)
|
||||
endif
|
||||
endif
|
||||
|
||||
INSTALL_BIN ?= install
|
||||
INSTALL_DATA ?= $(INSTALL_BIN) -m0644
|
||||
INSTALL_LIB ?= $(INSTALL_BIN) -m0755
|
||||
PKGCFGF = $(LIBNAME).pc
|
||||
PREFIX ?= /usr
|
||||
DESTDIR ?=
|
||||
BLDIR = .
|
||||
OBJDIR = .
|
||||
UNAME_S := $(shell uname -s)
|
||||
|
||||
LIBDIRARCH ?= lib
|
||||
# Uncomment the below line to installs x86_64 libs to lib64/ directory.
|
||||
# Or better, pass 'LIBDIRARCH=lib64' to 'make install/uninstall' via 'make.sh'.
|
||||
#LIBDIRARCH ?= lib64
|
||||
|
||||
LIBDIR ?= $(DESTDIR)$(PREFIX)/$(LIBDIRARCH)
|
||||
INCDIR ?= $(DESTDIR)$(PREFIX)/include
|
||||
|
||||
LIBDATADIR ?= $(LIBDIR)
|
||||
|
||||
# Don't redefine $LIBDATADIR when global environment variable
|
||||
# USE_GENERIC_LIBDATADIR is set. This is used by the pkgsrc framework.
|
||||
|
||||
ifndef USE_GENERIC_LIBDATADIR
|
||||
ifeq ($(UNAME_S), FreeBSD)
|
||||
LIBDATADIR = $(DESTDIR)$(PREFIX)/libdata
|
||||
endif
|
||||
ifeq ($(UNAME_S), DragonFly)
|
||||
LIBDATADIR = $(DESTDIR)$(PREFIX)/libdata
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PKG_EXTRA),)
|
||||
PKGCFGDIR = $(LIBDATADIR)/pkgconfig
|
||||
else
|
||||
PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig
|
||||
endif
|
||||
|
||||
all: compile_lib
|
||||
ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
|
||||
ifeq ($(UNICORN_SHARED),yes)
|
||||
ifeq ($(V),0)
|
||||
@$(INSTALL_DATA) $(LIBRARY) $(BLDIR)/samples/
|
||||
else
|
||||
$(INSTALL_DATA) $(LIBRARY) $(BLDIR)/samples/
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef BUILDDIR
|
||||
@cd samples && $(MAKE)
|
||||
else
|
||||
@cd samples && $(MAKE) BUILDDIR=$(BLDIR)
|
||||
endif
|
||||
endif
|
||||
|
||||
config:
|
||||
if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi
|
||||
|
||||
qemu/config-host.h-timestamp:
|
||||
ifeq ($(UNICORN_DEBUG),yes)
|
||||
cd qemu && \
|
||||
./configure --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)"
|
||||
printf "$(UNICORN_ARCHS)" > config.log
|
||||
else
|
||||
cd qemu && \
|
||||
./configure --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)"
|
||||
printf "$(UNICORN_ARCHS)" > config.log
|
||||
endif
|
||||
|
||||
compile_lib: config qemu/config-host.h-timestamp
|
||||
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll && cd qemu && $(MAKE) -j 8
|
||||
$(MAKE) unicorn
|
||||
cd samples && $(MAKE) clean
|
||||
|
||||
unicorn: $(LIBRARY) $(ARCHIVE)
|
||||
|
||||
$(LIBRARY): $(UC_TARGET_OBJ) uc.o hook.o
|
||||
ifeq ($(UNICORN_SHARED),yes)
|
||||
ifeq ($(V),0)
|
||||
$(call log,GEN,$(LIBRARY))
|
||||
@$(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm
|
||||
else
|
||||
$(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm
|
||||
endif
|
||||
endif
|
||||
|
||||
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o hook.o
|
||||
ifeq ($(UNICORN_STATIC),yes)
|
||||
ifeq ($(V),0)
|
||||
$(call log,GEN,$(ARCHIVE))
|
||||
@$(create-archive)
|
||||
else
|
||||
$(create-archive)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
$(PKGCFGF):
|
||||
ifeq ($(V),0)
|
||||
$(call log,GEN,$(@:$(BLDIR)/%=%))
|
||||
@$(generate-pkgcfg)
|
||||
else
|
||||
$(generate-pkgcfg)
|
||||
endif
|
||||
|
||||
|
||||
install: compile_lib $(PKGCFGF)
|
||||
mkdir -p $(LIBDIR)
|
||||
ifeq ($(UNICORN_SHARED),yes)
|
||||
$(INSTALL_LIB) $(LIBRARY) $(LIBDIR)
|
||||
ifneq ($(VERSION_EXT),)
|
||||
cd $(LIBDIR) && \
|
||||
mv lib$(LIBNAME).$(EXT) lib$(LIBNAME).$(VERSION_EXT) && \
|
||||
ln -s lib$(LIBNAME).$(VERSION_EXT) lib$(LIBNAME).$(EXT)
|
||||
endif
|
||||
endif
|
||||
ifeq ($(UNICORN_STATIC),yes)
|
||||
$(INSTALL_DATA) $(ARCHIVE) $(LIBDIR)
|
||||
endif
|
||||
mkdir -p $(INCDIR)/$(LIBNAME)
|
||||
$(INSTALL_DATA) include/unicorn/*.h $(INCDIR)/$(LIBNAME)
|
||||
mkdir -p $(PKGCFGDIR)
|
||||
$(INSTALL_DATA) $(PKGCFGF) $(PKGCFGDIR)/
|
||||
|
||||
|
||||
TAG ?= HEAD
|
||||
ifeq ($(TAG), HEAD)
|
||||
DIST_VERSION = latest
|
||||
else
|
||||
DIST_VERSION = $(TAG)
|
||||
endif
|
||||
|
||||
dist:
|
||||
git archive --format=tar.gz --prefix=unicorn-$(DIST_VERSION)/ $(TAG) > unicorn-$(DIST_VERSION).tgz
|
||||
git archive --format=zip --prefix=unicorn-$(DIST_VERSION)/ $(TAG) > unicorn-$(DIST_VERSION).zip
|
||||
|
||||
|
||||
header: FORCE
|
||||
$(eval TARGETS := m68k arm aarch64 mips mipsel mips64 mips64el\
|
||||
powerpc sparc sparc64 x86_64)
|
||||
$(foreach var,$(TARGETS),\
|
||||
$(shell python qemu/header_gen.py $(var) > qemu/$(var).h;))
|
||||
@echo "Generated headers for $(TARGETS)."
|
||||
|
||||
clean:
|
||||
$(MAKE) -C qemu clean
|
||||
rm -rf *.d *.o
|
||||
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll
|
||||
ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
|
||||
cd samples && $(MAKE) clean
|
||||
rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT)
|
||||
endif
|
||||
|
||||
ifdef BUILDDIR
|
||||
rm -rf $(BUILDDIR)
|
||||
endif
|
||||
|
||||
|
||||
define generate-pkgcfg
|
||||
echo 'Name: unicorn' > $(PKGCFGF)
|
||||
echo 'Description: Unicorn emulator engine' >> $(PKGCFGF)
|
||||
echo 'Version: $(PKG_VERSION)' >> $(PKGCFGF)
|
||||
echo 'libdir=$(LIBDIR)' >> $(PKGCFGF)
|
||||
echo 'includedir=$(INCDIR)' >> $(PKGCFGF)
|
||||
echo 'archive=$${libdir}/libunicorn.a' >> $(PKGCFGF)
|
||||
echo 'Libs: -L$${libdir} -lunicorn' >> $(PKGCFGF)
|
||||
echo 'Cflags: -I$${includedir}' >> $(PKGCFGF)
|
||||
endef
|
||||
|
||||
|
||||
define log
|
||||
@printf " %-7s %s\n" "$(1)" "$(2)"
|
||||
endef
|
||||
|
||||
|
||||
define create-archive
|
||||
$(AR) q $(ARCHIVE) $^
|
||||
$(RANLIB) $(ARCHIVE)
|
||||
endef
|
||||
|
||||
FORCE:
|
23
README
Normal file
23
README
Normal file
|
@ -0,0 +1,23 @@
|
|||
Unicorn is a lightweight multi-platform, multi-architecture CPU emulator framework.
|
||||
Unicorn offers some unparalleled features:
|
||||
|
||||
- Multi-architectures: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64).
|
||||
- Clean/simple/lightweight/intuitive architecture-neutral API.
|
||||
- Implemented in pure C language, with bindings for Python available.
|
||||
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed).
|
||||
- High performace by using Just-In-Time compiler technique.
|
||||
- Support fine-grained instrumentation at various levels.
|
||||
- Thread-safe by design.
|
||||
- Distributed under open source license GPL.
|
||||
|
||||
Further information is available at http://www.unicorn-engine.org
|
||||
|
||||
|
||||
[Compile]
|
||||
|
||||
See COMPILE.TXT file for how to compile and install Unicorn.
|
||||
|
||||
|
||||
[License]
|
||||
|
||||
This project is released under the GPL license.
|
58
bindings/Makefile
Normal file
58
bindings/Makefile
Normal file
|
@ -0,0 +1,58 @@
|
|||
# Unicorn Engine
|
||||
# By Nguyen Anh Quynh & Dang Hoang Vu, 2015
|
||||
TMPDIR = /tmp/unicorn_sample
|
||||
|
||||
DIFF = diff -u -w
|
||||
|
||||
SAMPLE_ARM = $(TMPDIR)/sample_arm
|
||||
SAMPLE_ARM64 = $(TMPDIR)/sample_arm64
|
||||
SAMPLE_MIPS = $(TMPDIR)/sample_mips
|
||||
SAMPLE_M68K = $(TMPDIR)/sample_m68k
|
||||
SAMPLE_SPARC = $(TMPDIR)/sample_sparc
|
||||
SAMPLE_X86 = $(TMPDIR)/sample_x86
|
||||
|
||||
.PHONY: all expected python
|
||||
|
||||
all:
|
||||
cd python && $(MAKE) gen_const
|
||||
|
||||
samples: expected python
|
||||
|
||||
sample_python: expected python
|
||||
|
||||
expected:
|
||||
cd ../samples && $(MAKE)
|
||||
mkdir -p $(TMPDIR)
|
||||
../samples/sample_arm > $(SAMPLE_ARM)_e
|
||||
../samples/sample_arm64 > $(SAMPLE_ARM64)_e
|
||||
../samples/sample_mips > $(SAMPLE_MIPS)_e
|
||||
../samples/sample_sparc > $(SAMPLE_SPARC)_e
|
||||
../samples/sample_m68k > $(SAMPLE_M68K)_e
|
||||
../samples/sample_x86 > $(SAMPLE_X86)_e
|
||||
|
||||
python: FORCE
|
||||
cd python && $(MAKE)
|
||||
python python/sample_arm.py > $(SAMPLE_ARM)_o
|
||||
python python/sample_arm64.py > $(SAMPLE_ARM64)_o
|
||||
python python/sample_mips.py > $(SAMPLE_MIPS)_o
|
||||
python python/sample_sparc.py > $(SAMPLE_SPARC)_o
|
||||
python python/sample_m68k.py > $(SAMPLE_M68K)_o
|
||||
python python/sample_x86.py > $(SAMPLE_X86)_o
|
||||
$(MAKE) sample_diff
|
||||
|
||||
sample_diff: FORCE
|
||||
$(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o
|
||||
$(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o
|
||||
$(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o
|
||||
$(DIFF) $(SAMPLE_SPARC)_e $(SAMPLE_SPARC)_o
|
||||
$(DIFF) $(SAMPLE_M68K)_e $(SAMPLE_M68K)_o
|
||||
$(DIFF) $(SAMPLE_X86)_e $(SAMPLE_X86)_o
|
||||
|
||||
clean:
|
||||
rm -rf $(TMPDIR)
|
||||
cd python && $(MAKE) clean
|
||||
|
||||
check:
|
||||
make -C python check
|
||||
|
||||
FORCE:
|
100
bindings/const_generator.py
Normal file
100
bindings/const_generator.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Unicorn Engine
|
||||
# By Dang Hoang Vu, 2013
|
||||
from __future__ import print_function
|
||||
import sys, re
|
||||
|
||||
INCL_DIR = '../include/unicorn/'
|
||||
|
||||
include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h' ]
|
||||
|
||||
template = {
|
||||
'python': {
|
||||
'header': "# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.py]\n",
|
||||
'footer': "",
|
||||
'line_format': '%s = %s\n',
|
||||
'out_file': './python/unicorn/%s_const.py',
|
||||
# prefixes for constant filenames of all archs - case sensitive
|
||||
'arm.h': 'arm',
|
||||
'arm64.h': 'arm64',
|
||||
'mips.h': 'mips',
|
||||
'x86.h': 'x86',
|
||||
'sparc.h': 'sparc',
|
||||
'm68k.h': 'm68k',
|
||||
'comment_open': '#',
|
||||
'comment_close': '',
|
||||
},
|
||||
}
|
||||
|
||||
# markup for comments to be added to autogen files
|
||||
MARKUP = '//>'
|
||||
|
||||
def gen(lang):
|
||||
global include, INCL_DIR
|
||||
templ = template[lang]
|
||||
for target in include:
|
||||
prefix = templ[target]
|
||||
outfile = open(templ['out_file'] %(prefix), 'w')
|
||||
outfile.write(templ['header'] % (prefix))
|
||||
|
||||
lines = open(INCL_DIR + target).readlines()
|
||||
|
||||
count = 0
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(MARKUP): # markup for comments
|
||||
outfile.write("\n%s%s%s\n" %(templ['comment_open'], \
|
||||
line.replace(MARKUP, ''), templ['comment_close']))
|
||||
continue
|
||||
|
||||
if line == '' or line.startswith('//'):
|
||||
continue
|
||||
|
||||
if not line.startswith(prefix.upper()):
|
||||
continue
|
||||
|
||||
tmp = line.strip().split(',')
|
||||
for t in tmp:
|
||||
t = t.strip()
|
||||
if not t or t.startswith('//'): continue
|
||||
f = re.split('\s+', t)
|
||||
|
||||
if f[0].startswith(prefix.upper()):
|
||||
if len(f) > 1 and f[1] not in '//=':
|
||||
print("Error: Unable to convert %s" % f)
|
||||
continue
|
||||
elif len(f) > 1 and f[1] == '=':
|
||||
rhs = ''.join(f[2:])
|
||||
else:
|
||||
rhs = str(count)
|
||||
count += 1
|
||||
|
||||
try:
|
||||
count = int(rhs) + 1
|
||||
if (count == 1):
|
||||
outfile.write("\n")
|
||||
except ValueError:
|
||||
if lang == 'ocaml':
|
||||
# ocaml uses lsl for '<<', lor for '|'
|
||||
rhs = rhs.replace('<<', ' lsl ')
|
||||
rhs = rhs.replace('|', ' lor ')
|
||||
# ocaml variable has _ as prefix
|
||||
if rhs[0].isalpha():
|
||||
rhs = '_' + rhs
|
||||
|
||||
outfile.write(templ['line_format'] %(f[0].strip(), rhs))
|
||||
|
||||
outfile.write(templ['footer'])
|
||||
outfile.close()
|
||||
|
||||
def main():
|
||||
try:
|
||||
gen(sys.argv[1])
|
||||
except:
|
||||
raise RuntimeError("Unsupported binding %s" % sys.argv[1])
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:", sys.argv[0], " <python>")
|
||||
sys.exit(1)
|
||||
main()
|
4
bindings/python/MANIFEST.in
Normal file
4
bindings/python/MANIFEST.in
Normal file
|
@ -0,0 +1,4 @@
|
|||
recursive-include src *
|
||||
recursive-include prebuilt *
|
||||
include LICENSE.TXT
|
||||
include README
|
82
bindings/python/Makefile
Normal file
82
bindings/python/Makefile
Normal file
|
@ -0,0 +1,82 @@
|
|||
# Python binding for Unicorn engine. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
ifndef BUILDDIR
|
||||
OBJDIR = ./build
|
||||
else
|
||||
OBJDIR = $(abspath $(BUILDDIR))/obj/bindings/python
|
||||
endif
|
||||
|
||||
.PHONY: gen_const install install3 clean
|
||||
|
||||
gen_const:
|
||||
cd .. && python const_generator.py python
|
||||
|
||||
install:
|
||||
rm -rf $(OBJDIR) src/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
if test -n "${DESTDIR}"; then \
|
||||
python setup.py build -b $(OBJDIR) install --root="${DESTDIR}"; \
|
||||
else \
|
||||
python setup.py build -b $(OBJDIR) install; \
|
||||
fi
|
||||
|
||||
install3:
|
||||
rm -rf $(OBJDIR) src/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
if test -n "${DESTDIR}"; then \
|
||||
python3 setup.py build -b $(OBJDIR) install --root="${DESTDIR}"; \
|
||||
else \
|
||||
python3 setup.py build -b $(OBJDIR) install; \
|
||||
fi
|
||||
|
||||
# build & upload PyPi package with source code of the core
|
||||
sdist:
|
||||
rm -rf src/ dist/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
cp README.pypi-src README
|
||||
cp PKG-INFO.src PKG-INFO
|
||||
python setup.py sdist register upload
|
||||
|
||||
# build & upload PyPi package with source code of the core
|
||||
sdist3:
|
||||
rm -rf src/ dist/
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
cp README.pypi-src README
|
||||
cp PKG-INFO.src PKG-INFO
|
||||
python3 setup.py sdist register upload
|
||||
|
||||
# build & upload PyPi package with prebuilt core
|
||||
# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
|
||||
sdist_win:
|
||||
rm -rf src/ dist/
|
||||
cp README.pypi-win README
|
||||
cp PKG-INFO.win PKG-INFO
|
||||
python setup.py sdist register upload
|
||||
|
||||
# build & upload PyPi package with prebuilt core
|
||||
# NOTE: be sure to have precompiled core under prebuilt/win*/ beforehand
|
||||
sdist3_win:
|
||||
rm -rf src/ dist/
|
||||
cp README.pypi-win README
|
||||
cp PKG-INFO.win PKG-INFO
|
||||
python3 setup.py sdist register upload
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) src/ dist/ README
|
||||
rm -f unicorn/*.so
|
||||
rm -rf prebuilt/win64/unicorn.dll
|
||||
rm -rf prebuilt/win32/unicorn.dll
|
||||
|
||||
|
||||
SAMPLES = sample_arm.py sample_arm64.py sample_mips.py
|
||||
SAMPLES += sample_sparc.py sample_m68k.py sample_x86.py
|
||||
check:
|
||||
@for t in $(SAMPLES); do \
|
||||
echo Check $$t ... ; \
|
||||
./$$t > /dev/null && echo OK || echo FAILED; \
|
||||
done
|
||||
|
63
bindings/python/README.TXT
Normal file
63
bindings/python/README.TXT
Normal file
|
@ -0,0 +1,63 @@
|
|||
This documentation explains how to install Python binding for Unicorn
|
||||
from source. If you want to install it from PyPi package, see the below
|
||||
docs instead:
|
||||
|
||||
- README.pypi-src: How to compile the Unicorn core & install binding
|
||||
at the same time from PyPi package "unicorn"
|
||||
|
||||
- README.pypi-win: How to install binding for Windows from PyPi package
|
||||
"unicorn-windows". Note that this package already has prebuilt core
|
||||
inside, so no compilation is needed.
|
||||
|
||||
|
||||
0. Install the core engine as dependency
|
||||
|
||||
Follow README in the root directory to compile & install the core.
|
||||
|
||||
On *nix, this can simply done by:
|
||||
|
||||
$ sudo ./make.sh install
|
||||
|
||||
|
||||
1. To install pure Python binding on *nix, run the command below:
|
||||
|
||||
$ sudo make install
|
||||
|
||||
To install Python3 binding package, run the command below:
|
||||
(Note: this requires python3 installed in your machine)
|
||||
|
||||
$ sudo make install3
|
||||
|
||||
|
||||
|
||||
This directory contains some sample code to show how to use Unicorn API.
|
||||
|
||||
- sample_<arch>.py
|
||||
These code show how to access architecture-specific information for each
|
||||
architecture.
|
||||
|
||||
- shellcode.py
|
||||
This shows how to analyze a Linux shellcode.
|
||||
|
||||
|
||||
2. To install Python binding on Windows:
|
||||
|
||||
Recommended method:
|
||||
|
||||
Use the Python module installer for 32/64 bit Windows from:
|
||||
|
||||
http://www.unicorn-engine.org/download.html
|
||||
|
||||
|
||||
Manual method:
|
||||
|
||||
If the module installer fails to locate your Python install, or if you have
|
||||
additional Python installs (e.g. Anaconda / virtualenv), run the following
|
||||
command in command prompt:
|
||||
|
||||
C:\> C:\location_to_python\python.exe setup.py install
|
||||
|
||||
Next, copy unicorn.dll from the 'Core engine for Windows' package available
|
||||
on the same Unicorn download page and paste it in the path:
|
||||
|
||||
C:\location_to_python\Lib\site-packages\unicorn\
|
103
bindings/python/sample_arm.py
Executable file
103
bindings/python/sample_arm.py
Executable file
|
@ -0,0 +1,103 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3
|
||||
THUMB_CODE = "\x83\xb0" # sub sp, #0xc
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
|
||||
|
||||
# Test ARM
|
||||
def test_arm():
|
||||
print("Emulate ARM code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_ARM)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, ARM_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(ARM_REG_R0, 0x1234)
|
||||
mu.reg_write(ARM_REG_R2, 0x6789)
|
||||
mu.reg_write(ARM_REG_R3, 0x3333)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r0 = mu.reg_read(ARM_REG_R0)
|
||||
r1 = mu.reg_read(ARM_REG_R1)
|
||||
print(">>> R0 = 0x%x" %r0)
|
||||
print(">>> R1 = 0x%x" %r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_thumb():
|
||||
print("Emulate THUMB code")
|
||||
try:
|
||||
# Initialize emulator in thumb mode
|
||||
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, THUMB_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(ARM_REG_SP, 0x1234)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(THUMB_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
sp = mu.reg_read(ARM_REG_SP)
|
||||
print(">>> SP = 0x%x" %sp)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm()
|
||||
print("=" * 20)
|
||||
test_thumb()
|
67
bindings/python/sample_arm64.py
Executable file
67
bindings/python/sample_arm64.py
Executable file
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.arm64_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
ARM64_CODE = "\xab\x01\x0f\x8b" #add x11, x13, x15
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
|
||||
|
||||
# Test ARM64
|
||||
def test_arm64():
|
||||
print("Emulate ARM64 code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, ARM64_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(ARM64_REG_X11, 0x1234)
|
||||
mu.reg_write(ARM64_REG_X13, 0x6789)
|
||||
mu.reg_write(ARM64_REG_X15, 0x3333)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(ARM64_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
x11 = mu.reg_read(ARM64_REG_X11)
|
||||
x13 = mu.reg_read(ARM64_REG_X13)
|
||||
x15 = mu.reg_read(ARM64_REG_X15)
|
||||
print(">>> X11 = 0x%x" %x11)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_arm64()
|
62
bindings/python/sample_m68k.py
Executable file
62
bindings/python/sample_m68k.py
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for ARM of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.m68k_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
M68K_CODE = "\x76\xed" # movq #-19, %d3
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
|
||||
|
||||
# Test ARM
|
||||
def test_m68k():
|
||||
print("Emulate M68K code")
|
||||
try:
|
||||
# Initialize emulator in ARM mode
|
||||
mu = Uc(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, M68K_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(M68K_REG_D3, 0x1234)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(M68K_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
d3 = mu.reg_read(M68K_REG_D3)
|
||||
print(">>> D3 = 0x%x" %d3)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_m68k()
|
101
bindings/python/sample_mips.py
Executable file
101
bindings/python/sample_mips.py
Executable file
|
@ -0,0 +1,101 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for MIPS of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.mips_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
MIPS_CODE_EB = "\x34\x21\x34\x56" # ori $at, $at, 0x3456;
|
||||
MIPS_CODE_EL = "\x56\x34\x21\x34" # ori $at, $at, 0x3456;
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
|
||||
|
||||
# Test MIPS EB
|
||||
def test_mips_eb():
|
||||
print("Emulate MIPS code (big-endian)")
|
||||
try:
|
||||
# Initialize emulator in MIPS32 + EB mode
|
||||
mu = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, MIPS_CODE_EB)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(MIPS_REG_1, 0x6789)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(MIPS_CODE_EB))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(MIPS_REG_1)
|
||||
print(">>> r1 = 0x%x" %r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
# Test MIPS EL
|
||||
def test_mips_el():
|
||||
print("Emulate MIPS code (little-endian)")
|
||||
try:
|
||||
# Initialize emulator in MIPS32 + EL mode
|
||||
mu = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, MIPS_CODE_EL)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(MIPS_REG_1, 0x6789)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(MIPS_CODE_EL))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r1 = mu.reg_read(MIPS_REG_1)
|
||||
print(">>> r1 = 0x%x" %r1)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_mips_eb()
|
||||
print("=" * 20)
|
||||
test_mips_el()
|
380
bindings/python/sample_network_auditing.py
Executable file
380
bindings/python/sample_network_auditing.py
Executable file
|
@ -0,0 +1,380 @@
|
|||
#!/usr/bin/env python
|
||||
# Unicorn sample for auditing network connection and file handling in shellcode.
|
||||
# Nguyen Tan Cong <shenlongbk@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
import struct
|
||||
import uuid
|
||||
import random
|
||||
|
||||
SIZE_REG = 4
|
||||
SOCKETCALL_MAX_ARGS = 6
|
||||
FILENAME_MAX_LEN = 128
|
||||
|
||||
SOCKET_TYPES = {
|
||||
1: "SOCK_STREAM",
|
||||
2: "SOCK_DGRAM",
|
||||
3: "SOCK_RAW",
|
||||
4: "SOCK_RDM",
|
||||
5: "SOCK_SEQPACKET",
|
||||
10: "SOCK_PACKET"
|
||||
}
|
||||
|
||||
ADDR_FAMILY = {
|
||||
0: "AF_UNSPEC",
|
||||
1: "AF_UNIX",
|
||||
2: "AF_INET",
|
||||
3: "AF_AX25",
|
||||
4: "AF_IPX",
|
||||
5: "AF_APPLETALK",
|
||||
6: "AF_NETROM",
|
||||
7: "AF_BRIDGE",
|
||||
8: "AF_AAL5",
|
||||
9: "AF_X25",
|
||||
10: "AF_INET6",
|
||||
12: "AF_MAX"
|
||||
}
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-861.php
|
||||
X86_SEND_ETCPASSWD = b"\x6a\x66\x58\x31\xdb\x43\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x6a\x66\x58\x43\x68\x7f\x01\x01\x01\x66\x68\x30\x39\x66\x53\x89\xe1\x6a\x10\x51\x56\x89\xe1\x43\xcd\x80\x89\xc6\x6a\x01\x59\xb0\x3f\xcd\x80\xeb\x27\x6a\x05\x58\x5b\x31\xc9\xcd\x80\x89\xc3\xb0\x03\x89\xe7\x89\xf9\x31\xd2\xb6\xff\xb2\xff\xcd\x80\x89\xc2\x6a\x04\x58\xb3\x01\xcd\x80\x6a\x01\x58\x43\xcd\x80\xe8\xd4\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-882.php
|
||||
X86_BIND_TCP = b"\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x5f\x97\x93\xb0\x66\x56\x66\x68\x05\x39\x66\x53\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\xb0\x66\xb3\x04\x56\x57\x89\xe1\xcd\x80\xb0\x66\x43\x56\x56\x57\x89\xe1\xcd\x80\x59\x59\xb1\x02\x93\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x41\x89\xca\xcd\x80"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-883.php
|
||||
X86_REVERSE_TCP = b"\x6a\x66\x58\x6a\x01\x5b\x31\xd2\x52\x53\x6a\x02\x89\xe1\xcd\x80\x92\xb0\x66\x68\x7f\x01\x01\x01\x66\x68\x05\x39\x43\x66\x53\x89\xe1\x6a\x10\x51\x52\x89\xe1\x43\xcd\x80\x6a\x02\x59\x87\xda\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x0b\x41\x89\xca\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd\x80"
|
||||
|
||||
# http://shell-storm.org/shellcode/files/shellcode-849.php
|
||||
X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x06\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\xb0\x66\x31\xdb\xb3\x02\x68\xc0\xa8\x01\x0a\x66\x68\x7a\x69\x66\x53\xfe\xc3\x89\xe1\x6a\x10\x51\x56\x89\xe1\xcd\x80\x31\xc9\xb1\x03\xfe\xc9\xb0\x3f\xcd\x80\x75\xf8\x31\xc0\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x52\x53\x89\xe1\x52\x89\xe2\xb0\x0b\xcd\x80"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
# supported classes
|
||||
class IdGenerator:
|
||||
def __init__(self):
|
||||
self.__next_id = 3 # exclude sdtin, stdout, stderr
|
||||
|
||||
def next(self):
|
||||
next_id = self.__next_id
|
||||
|
||||
self.__next_id += 1
|
||||
|
||||
return next_id
|
||||
|
||||
class LogChain:
|
||||
def __init__(self):
|
||||
self.__chains = {}
|
||||
self.__linking_fds = {}
|
||||
|
||||
def clean(self):
|
||||
self.__chains = {}
|
||||
self.__linking_fds = {}
|
||||
|
||||
def create_chain(self, id):
|
||||
if not self.__chains.has_key(id):
|
||||
self.__chains[id] = []
|
||||
else:
|
||||
print("LogChain: id %d existed" % id)
|
||||
|
||||
def add_log(self, id, msg):
|
||||
fd = self.get_original_fd(id)
|
||||
|
||||
if fd is not None:
|
||||
self.__chains[fd].append(msg)
|
||||
else:
|
||||
print("LogChain: id %d doesn't exist" % id)
|
||||
|
||||
def link_fd(self, from_fd, to_fd):
|
||||
if not self.__linking_fds.has_key(to_fd):
|
||||
self.__linking_fds[to_fd] = []
|
||||
|
||||
self.__linking_fds[to_fd].append(from_fd)
|
||||
|
||||
def get_original_fd(self, fd):
|
||||
if self.__chains.has_key(fd):
|
||||
return fd
|
||||
|
||||
for orig_fd, links in self.__linking_fds.iteritems():
|
||||
if fd in links:
|
||||
return orig_fd
|
||||
|
||||
return None
|
||||
|
||||
def print_report(self):
|
||||
print("""
|
||||
----------------
|
||||
| START REPORT |
|
||||
----------------
|
||||
""")
|
||||
for id, logs in self.__chains.iteritems():
|
||||
print("---- START FD(%d) ----" % id)
|
||||
print("\n".join(logs))
|
||||
print("---- END FD(%d) ----" % id)
|
||||
|
||||
print("""
|
||||
--------------
|
||||
| END REPORT |
|
||||
--------------
|
||||
""")
|
||||
|
||||
# end supported classes
|
||||
|
||||
id_gen = IdGenerator()
|
||||
fd_chains = LogChain()
|
||||
|
||||
# utilities
|
||||
def bin_to_ipv4(ip):
|
||||
return "%d.%d.%d.%d" % (
|
||||
(ip & 0xff000000) >> 24,
|
||||
(ip & 0xff0000) >> 16,
|
||||
(ip & 0xff00) >> 8,
|
||||
(ip & 0xff))
|
||||
|
||||
def bytearray_to_string(ba):
|
||||
ret = ""
|
||||
|
||||
i = 0
|
||||
while i < len(ba) and ba[i] != 0x0:
|
||||
ret += chr(ba[i])
|
||||
|
||||
i += 1
|
||||
|
||||
return ret
|
||||
|
||||
def parse_sock_address(sock_addr):
|
||||
sin_family, = struct.unpack("<h", sock_addr[:2])
|
||||
|
||||
if sin_family == 2: # AF_INET
|
||||
port, host = struct.unpack(">HI", sock_addr[2:8])
|
||||
return "%s:%d" % (bin_to_ipv4(host), port)
|
||||
elif sin_family == 6: # AF_INET6
|
||||
return ""
|
||||
|
||||
def print_sockcall(msg):
|
||||
print(">>> SOCKCALL %s" % msg)
|
||||
# end utilities
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print(">>> Instruction code at [0x%x] =" %(address), end="")
|
||||
for i in tmp:
|
||||
print(" %x" %i, end="")
|
||||
print("")
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
return
|
||||
|
||||
eax = uc.reg_read(X86_REG_EAX)
|
||||
ebx = uc.reg_read(X86_REG_EBX)
|
||||
ecx = uc.reg_read(X86_REG_ECX)
|
||||
edx = uc.reg_read(X86_REG_EDX)
|
||||
eip = uc.reg_read(X86_REG_EIP)
|
||||
|
||||
# print(">>> INTERRUPT %d" % eax)
|
||||
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> SYS_EXIT")
|
||||
uc.emu_stop()
|
||||
elif eax == 3: # sys_read
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
||||
dummy_content = str(uuid.uuid1())
|
||||
if len(dummy_content) > count:
|
||||
dummy_content = dummy_content[:count]
|
||||
|
||||
uc.mem_write(buf, dummy_content)
|
||||
|
||||
msg = "read %d bytes from fd(%d) with dummy_content(%s)" % (count, fd, dummy_content)
|
||||
|
||||
fd_chains.add_log(fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 4: # sys_write
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
||||
content = uc.mem_read(buf, count)
|
||||
|
||||
msg = "write data=%s count=%d to fd(%d)" % (bytearray_to_string(content), count, fd)
|
||||
|
||||
print(">>> %s" % msg)
|
||||
fd_chains.add_log(fd, msg)
|
||||
elif eax == 5: # sys_open
|
||||
filename_addr = ebx
|
||||
flags = ecx
|
||||
mode = edx
|
||||
filename = uc.mem_read(filename_addr, FILENAME_MAX_LEN)
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(X86_REG_EAX, dummy_fd)
|
||||
|
||||
msg = "open file (filename=%s flags=%d mode=%d) with fd(%d)" % (bytearray_to_string(filename), flags, mode, dummy_fd)
|
||||
|
||||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 11: # sys_execv
|
||||
# print(">>> ebx=0x%x, ecx=0x%x, edx=0x%x" % (ebx, ecx, edx))
|
||||
filename = uc.mem_read(ebx, FILENAME_MAX_LEN)
|
||||
|
||||
print(">>> SYS_EXECV filename=%s" % bytearray_to_string(filename))
|
||||
elif eax == 63: # sys_dup2
|
||||
fd_chains.link_fd(ecx, ebx)
|
||||
print(">>> SYS_DUP2 oldfd=%d newfd=%d" % (ebx, ecx))
|
||||
elif eax == 102: # sys_socketcall
|
||||
# ref: http://www.skyfree.org/linux/kernel_network/socket.html
|
||||
call = uc.reg_read(X86_REG_EBX)
|
||||
args = uc.reg_read(X86_REG_ECX)
|
||||
|
||||
buf = uc.mem_read(args, SOCKETCALL_MAX_ARGS*SIZE_REG)
|
||||
args = struct.unpack("<" + "I"*SOCKETCALL_MAX_ARGS, buf)
|
||||
|
||||
# int sys_socketcall(int call, unsigned long *args)
|
||||
if call == 1: # sys_socket
|
||||
# err = sys_socket(a0,a1,a[2])
|
||||
# int sys_socket(int family, int type, int protocol)
|
||||
family = args[0]
|
||||
sock_type = args[1]
|
||||
protocol = args[2]
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(X86_REG_EAX, dummy_fd)
|
||||
|
||||
if family == 2: # AF_INET
|
||||
|
||||
msg = "create socket (%s, %s) with fd(%d)" % (ADDR_FAMILY[family], SOCKET_TYPES[sock_type], dummy_fd)
|
||||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print_sockcall(msg)
|
||||
elif family == 3: # AF_INET6
|
||||
pass
|
||||
|
||||
elif call == 2: # sys_bind
|
||||
fd = args[0]
|
||||
umyaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
||||
sock_addr = uc.mem_read(umyaddr, addrlen)
|
||||
|
||||
msg = "fd(%d) bind to %s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 3: # sys_connect
|
||||
# err = sys_connect(a0, (struct sockaddr *)a1, a[2])
|
||||
# int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
|
||||
fd = args[0]
|
||||
uservaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
||||
sock_addr = uc.mem_read(uservaddr, addrlen)
|
||||
msg = "fd(%d) connect to %s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 4: # sys_listen
|
||||
fd = args[0]
|
||||
backlog = args[1]
|
||||
|
||||
msg = "fd(%d) listened with backlog=%d" % (fd, backlog)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 5: # sys_accept
|
||||
fd = args[0]
|
||||
upeer_sockaddr = args[1]
|
||||
upeer_addrlen = args[2]
|
||||
|
||||
# print(">>> upeer_sockaddr=0x%x, upeer_addrlen=%d" % (upeer_sockaddr, upeer_addrlen))
|
||||
|
||||
if upeer_sockaddr == 0x0:
|
||||
print_sockcall("fd(%d) accept client" % fd)
|
||||
else:
|
||||
upeer_len, = struct.unpack("<I", uc.mem_read(upeer_addrlen, 4))
|
||||
|
||||
sock_addr = uc.mem_read(upeer_sockaddr, upeer_len)
|
||||
|
||||
msg = "fd(%d) accept client with upeer=%s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 9: # sys_send
|
||||
fd = args[0]
|
||||
buff = args[1]
|
||||
length = args[2]
|
||||
flags = args[3]
|
||||
|
||||
buf = uc.mem_read(buff, length)
|
||||
msg = "fd(%d) send data=%s" % (fd, buf)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 11: # sys_receive
|
||||
fd = args[0]
|
||||
ubuf = args[1]
|
||||
size = args[2]
|
||||
flags = args[3]
|
||||
|
||||
msg = "fd(%d) is gonna receive data with size=%d flags=%d" % (fd, size, flags)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 13: # sys_shutdown
|
||||
fd = args[0]
|
||||
how = args[1]
|
||||
|
||||
msg = "fd(%d) is shutted down because of %d" % (fd, how)
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
# Test X86 32 bit
|
||||
def test_i386(code):
|
||||
fd_chains.clean()
|
||||
print("Emulate i386 code")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, code)
|
||||
|
||||
# initialize stack
|
||||
mu.reg_write(X86_REG_ESP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
# mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# handle interrupt ourself
|
||||
mu.hook_add(UC_HOOK_INTR, hook_intr)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(code))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
fd_chains.print_report()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386(X86_SEND_ETCPASSWD)
|
||||
test_i386(X86_BIND_TCP)
|
||||
test_i386(X86_REVERSE_TCP)
|
||||
test_i386(X86_REVERSE_TCP_2)
|
||||
|
64
bindings/python/sample_sparc.py
Executable file
64
bindings/python/sample_sparc.py
Executable file
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for SPARC of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
# Python sample ported by Loi Anh Tuan <loianhtuan@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.sparc_const import *
|
||||
|
||||
|
||||
# code to be emulated
|
||||
SPARC_CODE = "\x86\x00\x40\x02" # add %g1, %g2, %g3;
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x10000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
|
||||
|
||||
# Test SPARC
|
||||
def test_sparc():
|
||||
print("Emulate SPARC code")
|
||||
try:
|
||||
# Initialize emulator in SPARC EB mode
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_BIG_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, SPARC_CODE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(SPARC_REG_G1, 0x1230)
|
||||
mu.reg_write(SPARC_REG_G2, 0x6789)
|
||||
mu.reg_write(SPARC_REG_G3, 0x5555)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(SPARC_CODE))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
g3 = mu.reg_read(SPARC_REG_G3)
|
||||
print(">>> G3 = 0x%x" %g3)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_sparc()
|
409
bindings/python/sample_x86.py
Executable file
409
bindings/python/sample_x86.py
Executable file
|
@ -0,0 +1,409 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for X86 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
|
||||
X86_CODE32 = b"\x41\x4a" # INC ecx; DEC dex
|
||||
X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC dex; JMP self-loop
|
||||
X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC dex
|
||||
X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; dec edx
|
||||
X86_CODE64 = b"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"
|
||||
X86_CODE32_INOUT = b"\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size))
|
||||
#eip = uc.reg_read(X86_REG_EIP)
|
||||
#print(">>> EIP = 0x%x" %(eip))
|
||||
|
||||
|
||||
# callback for tracing invalid memory access (READ or WRITE)
|
||||
def hook_mem_invalid(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE:
|
||||
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
%(address, size, value))
|
||||
# map this memory in with 2MB in size
|
||||
uc.mem_map(0xaaaa0000, 2 * 1024*1024)
|
||||
# return True to indicate we want to continue emulation
|
||||
return True
|
||||
else:
|
||||
# return False to indicate we want to stop emulation
|
||||
return False
|
||||
|
||||
|
||||
# callback for tracing memory access (READ or WRITE)
|
||||
def hook_mem_access(uc, access, address, size, value, user_data):
|
||||
if access == UC_MEM_WRITE:
|
||||
print(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
|
||||
%(address, size, value))
|
||||
else: # READ
|
||||
print(">>> Memory is being READ at 0x%x, data size = %u" \
|
||||
%(address, size))
|
||||
|
||||
|
||||
# callback for IN instruction
|
||||
def hook_in(uc, port, size, user_data):
|
||||
eip = uc.reg_read(X86_REG_EIP)
|
||||
print("--- reading from port 0x%x, size: %u, address: 0x%x" %(port, size, eip))
|
||||
if size == 1:
|
||||
# read 1 byte to AL
|
||||
return 0xf1
|
||||
if size == 2:
|
||||
# read 2 byte to AX
|
||||
return 0xf2
|
||||
if size == 4:
|
||||
# read 4 byte to EAX
|
||||
return 0xf4
|
||||
# we should never reach here
|
||||
return 0
|
||||
|
||||
|
||||
# callback for OUT instruction
|
||||
def hook_out(uc, port, size, value, user_data):
|
||||
eip = uc.reg_read(X86_REG_EIP)
|
||||
print("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" %(port, size, value, eip))
|
||||
|
||||
# confirm that value is indeed the value of AL/AX/EAX
|
||||
v = 0
|
||||
if size == 1:
|
||||
# read 1 byte in AL
|
||||
v = uc.reg_read(X86_REG_AL)
|
||||
if size == 2:
|
||||
# read 2 bytes in AX
|
||||
v = uc.reg_read(X86_REG_AX)
|
||||
if size == 4:
|
||||
# read 4 bytes in EAX
|
||||
v = uc.reg_read(X86_REG_EAX)
|
||||
|
||||
print("--- register value = 0x%x" %v)
|
||||
|
||||
|
||||
# Test X86 32 bit
|
||||
def test_i386():
|
||||
print("Emulate i386 code")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE32)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(X86_REG_EDX, 0x7890)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(X86_REG_ECX)
|
||||
r_edx = mu.reg_read(X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
|
||||
# read from memory
|
||||
tmp = mu.mem_read(ADDRESS, 2)
|
||||
print(">>> Read 2 bytes from [0x%x] =" %(ADDRESS), end="")
|
||||
for i in tmp:
|
||||
print(" 0x%x" %i, end="")
|
||||
print("")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_loop():
|
||||
print("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE32_LOOP)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(X86_REG_EDX, 0x7890)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), 2 * UC_SECOND_SCALE)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(X86_REG_ECX)
|
||||
r_edx = mu.reg_read(X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_invalid_mem_read():
|
||||
print("Emulate i386 code that read from invalid memory")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE32_MEM_READ)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(X86_REG_EDX, 0x7890)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(X86_REG_ECX)
|
||||
r_edx = mu.reg_read(X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_i386_invalid_mem_write():
|
||||
print("Emulate i386 code that write to invalid memory")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE32_MEM_WRITE)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_ECX, 0x1234)
|
||||
mu.reg_write(X86_REG_EDX, 0x7890)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
#mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
#mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# intercept invalid memory events
|
||||
mu.hook_add(UC_HOOK_MEM_INVALID, hook_mem_invalid)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_WRITE))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(X86_REG_ECX)
|
||||
r_edx = mu.reg_read(X86_REG_EDX)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
print(">>> EDX = 0x%x" %r_edx)
|
||||
|
||||
try:
|
||||
# read from memory
|
||||
print(">>> Read 4 bytes from [0x%x] = " %(0xaaaaaaaa), end="")
|
||||
tmp = mu.mem_read(0xaaaaaaaa, 4)
|
||||
for i in tmp:
|
||||
print(" 0x%x" %i, end="")
|
||||
print("")
|
||||
|
||||
print(">>> Read 4 bytes from [0x%x] = " %(0xffffffaa), end="")
|
||||
tmp = mu.mem_read(0xffffffaa, 4)
|
||||
for i in tmp:
|
||||
print(" 0x%x" %i, end="")
|
||||
print("")
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
# Test X86 32 bit with IN/OUT instruction
|
||||
def test_i386_inout():
|
||||
print("Emulate i386 code with IN/OUT instructions")
|
||||
try:
|
||||
# Initialize emulator in X86-32bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE32_INOUT)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_EAX, 0x1234)
|
||||
mu.reg_write(X86_REG_ECX, 0x6789)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# handle IN & OUT instruction
|
||||
mu.hook_add(UC_HOOK_INSN, hook_in, None, X86_INS_IN)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_out, None, X86_INS_OUT)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_INOUT))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
r_ecx = mu.reg_read(X86_REG_ECX)
|
||||
r_eax = mu.reg_read(X86_REG_EAX)
|
||||
print(">>> EAX = 0x%x" %r_eax)
|
||||
print(">>> ECX = 0x%x" %r_ecx)
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
def test_x86_64():
|
||||
print("Emulate x86_64 code")
|
||||
try:
|
||||
# Initialize emulator in X86-64bit mode
|
||||
mu = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, X86_CODE64)
|
||||
|
||||
# initialize machine registers
|
||||
mu.reg_write(X86_REG_RAX, 0x71f3029efd49d41d)
|
||||
mu.reg_write(X86_REG_RBX, 0xd87b45277f133ddb)
|
||||
mu.reg_write(X86_REG_RCX, 0xab40d1ffd8afc461)
|
||||
mu.reg_write(X86_REG_RDX, 0x919317b4a733f01)
|
||||
mu.reg_write(X86_REG_RSI, 0x4c24e753a17ea358)
|
||||
mu.reg_write(X86_REG_RDI, 0xe509a57d2571ce96)
|
||||
mu.reg_write(X86_REG_R8, 0xea5b108cc2b9ab1f)
|
||||
mu.reg_write(X86_REG_R9, 0x19ec097c8eb618c1)
|
||||
mu.reg_write(X86_REG_R10, 0xec45774f00c5f682)
|
||||
mu.reg_write(X86_REG_R11, 0xe17e9dbec8c074aa)
|
||||
mu.reg_write(X86_REG_R12, 0x80f86a8dc0f6d457)
|
||||
mu.reg_write(X86_REG_R13, 0x48288ca5671c5492)
|
||||
mu.reg_write(X86_REG_R14, 0x595f72f6e4017f6e)
|
||||
mu.reg_write(X86_REG_R15, 0x1efd97aea331cccc)
|
||||
|
||||
# setup stack
|
||||
mu.reg_write(X86_REG_RSP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions in range [ADDRESS, ADDRESS+20]
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code, None, ADDRESS, ADDRESS+20)
|
||||
|
||||
# tracing all memory READ & WRITE access
|
||||
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
|
||||
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access)
|
||||
# actually you can also use READ_WRITE to trace all memory access
|
||||
#mu.hook_add(UC_HOOK_MEM_READ_WRITE, hook_mem_access)
|
||||
|
||||
try:
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64))
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done. Below is the CPU context")
|
||||
|
||||
rax = mu.reg_read(X86_REG_RAX)
|
||||
rbx = mu.reg_read(X86_REG_RBX)
|
||||
rcx = mu.reg_read(X86_REG_RCX)
|
||||
rdx = mu.reg_read(X86_REG_RDX)
|
||||
rsi = mu.reg_read(X86_REG_RSI)
|
||||
rdi = mu.reg_read(X86_REG_RDI)
|
||||
r8 = mu.reg_read(X86_REG_R8)
|
||||
r9 = mu.reg_read(X86_REG_R9)
|
||||
r10 = mu.reg_read(X86_REG_R10)
|
||||
r11 = mu.reg_read(X86_REG_R11)
|
||||
r12 = mu.reg_read(X86_REG_R12)
|
||||
r13 = mu.reg_read(X86_REG_R13)
|
||||
r14 = mu.reg_read(X86_REG_R14)
|
||||
r15 = mu.reg_read(X86_REG_R15)
|
||||
|
||||
print(">>> RAX = %x" %rax)
|
||||
print(">>> RBX = %x" %rbx)
|
||||
print(">>> RCX = %x" %rcx)
|
||||
print(">>> RDX = %x" %rdx)
|
||||
print(">>> RSI = %x" %rsi)
|
||||
print(">>> RDI = %x" %rdi)
|
||||
print(">>> R8 = %x" %r8)
|
||||
print(">>> R9 = %x" %r9)
|
||||
print(">>> R10 = %x" %r10)
|
||||
print(">>> R11 = %x" %r11)
|
||||
print(">>> R12 = %x" %r12)
|
||||
print(">>> R13 = %x" %r13)
|
||||
print(">>> R14 = %x" %r14)
|
||||
print(">>> R15 = %x" %r15)
|
||||
|
||||
#BUG
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64))
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386()
|
||||
print("=" * 20)
|
||||
test_i386_loop()
|
||||
print("=" * 20)
|
||||
test_i386_invalid_mem_read()
|
||||
print("=" * 20)
|
||||
test_i386_invalid_mem_write()
|
||||
print("=" * 20)
|
||||
test_i386_inout()
|
||||
print("=" * 20)
|
||||
test_x86_64()
|
182
bindings/python/setup.py
Executable file
182
bindings/python/setup.py
Executable file
|
@ -0,0 +1,182 @@
|
|||
#!/usr/bin/env python
|
||||
# Python binding for Unicorn engine. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
import glob
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import stat
|
||||
import sys
|
||||
|
||||
from distutils import log
|
||||
from distutils import dir_util
|
||||
from distutils.command.build_clib import build_clib
|
||||
from distutils.command.sdist import sdist
|
||||
from distutils.core import setup
|
||||
from distutils.sysconfig import get_python_lib
|
||||
|
||||
# prebuilt libraries for Windows - for sdist
|
||||
PATH_LIB64 = "prebuilt/win64/unicorn.dll"
|
||||
PATH_LIB32 = "prebuilt/win32/unicorn.dll"
|
||||
|
||||
# package name can be 'unicorn' or 'unicorn-windows'
|
||||
PKG_NAME = 'unicorn'
|
||||
if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
|
||||
PKG_NAME = 'unicorn-windows'
|
||||
|
||||
VERSION = '0.9'
|
||||
SYSTEM = sys.platform
|
||||
|
||||
# virtualenv breaks import, but get_python_lib() will work.
|
||||
SITE_PACKAGES = os.path.join(get_python_lib(), "unicorn")
|
||||
if "--user" in sys.argv:
|
||||
try:
|
||||
from site import getusersitepackages
|
||||
SITE_PACKAGES = os.path.join(getusersitepackages(), "unicorn")
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
SETUP_DATA_FILES = []
|
||||
|
||||
# adapted from commit e504b81 of Nguyen Tan Cong
|
||||
# Reference: https://docs.python.org/2/library/platform.html#cross-platform
|
||||
is_64bits = sys.maxsize > 2**32
|
||||
|
||||
def copy_sources():
|
||||
"""Copy the C sources into the source directory.
|
||||
This rearranges the source files under the python distribution
|
||||
directory.
|
||||
"""
|
||||
src = []
|
||||
|
||||
try:
|
||||
dir_util.remove_tree("src/")
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
dir_util.copy_tree("../../arch", "src/arch/")
|
||||
dir_util.copy_tree("../../include", "src/include/")
|
||||
|
||||
src.extend(glob.glob("../../*.[ch]"))
|
||||
src.extend(glob.glob("../../*.mk"))
|
||||
|
||||
src.extend(glob.glob("../../Makefile"))
|
||||
src.extend(glob.glob("../../LICENSE*"))
|
||||
src.extend(glob.glob("../../README"))
|
||||
src.extend(glob.glob("../../*.TXT"))
|
||||
src.extend(glob.glob("../../RELEASE_NOTES"))
|
||||
src.extend(glob.glob("../../make.sh"))
|
||||
src.extend(glob.glob("../../CMakeLists.txt"))
|
||||
|
||||
for filename in src:
|
||||
outpath = os.path.join("./src/", os.path.basename(filename))
|
||||
log.info("%s -> %s" % (filename, outpath))
|
||||
shutil.copy(filename, outpath)
|
||||
|
||||
|
||||
class custom_sdist(sdist):
|
||||
"""Reshuffle files for distribution."""
|
||||
|
||||
def run(self):
|
||||
# if prebuilt libraries are existent, then do not copy source
|
||||
if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
|
||||
return sdist.run(self)
|
||||
copy_sources()
|
||||
return sdist.run(self)
|
||||
|
||||
|
||||
class custom_build_clib(build_clib):
|
||||
"""Customized build_clib command."""
|
||||
|
||||
def run(self):
|
||||
log.info('running custom_build_clib')
|
||||
build_clib.run(self)
|
||||
|
||||
def finalize_options(self):
|
||||
# We want build-clib to default to build-lib as defined by the "build"
|
||||
# command. This is so the compiled library will be put in the right
|
||||
# place along side the python code.
|
||||
self.set_undefined_options('build',
|
||||
('build_lib', 'build_clib'),
|
||||
('build_temp', 'build_temp'),
|
||||
('compiler', 'compiler'),
|
||||
('debug', 'debug'),
|
||||
('force', 'force'))
|
||||
|
||||
build_clib.finalize_options(self)
|
||||
|
||||
def build_libraries(self, libraries):
|
||||
if SYSTEM in ("win32", "cygwin"):
|
||||
# if Windows prebuilt library is available, then include it
|
||||
if is_64bits and os.path.exists(PATH_LIB64):
|
||||
SETUP_DATA_FILES.append(PATH_LIB64)
|
||||
return
|
||||
elif os.path.exists(PATH_LIB32):
|
||||
SETUP_DATA_FILES.append(PATH_LIB32)
|
||||
return
|
||||
|
||||
# build library from source if src/ is existent
|
||||
if not os.path.exists('src'):
|
||||
return
|
||||
|
||||
try:
|
||||
for (lib_name, build_info) in libraries:
|
||||
log.info("building '%s' library", lib_name)
|
||||
|
||||
os.chdir("src")
|
||||
|
||||
# platform description refers at https://docs.python.org/2/library/sys.html#sys.platform
|
||||
if SYSTEM == "cygwin":
|
||||
os.chmod("make.sh", stat.S_IREAD|stat.S_IEXEC)
|
||||
if is_64bits:
|
||||
os.system("UNICORN_BUILD_CORE_ONLY=yes ./make.sh cygwin-mingw64")
|
||||
else:
|
||||
os.system("UNICORN_BUILD_CORE_ONLY=yes ./make.sh cygwin-mingw32")
|
||||
SETUP_DATA_FILES.append("src/unicorn.dll")
|
||||
else: # Unix
|
||||
os.chmod("make.sh", stat.S_IREAD|stat.S_IEXEC)
|
||||
os.system("UNICORN_BUILD_CORE_ONLY=yes ./make.sh")
|
||||
if SYSTEM == "darwin":
|
||||
SETUP_DATA_FILES.append("src/libunicorn.dylib")
|
||||
else: # Non-OSX
|
||||
SETUP_DATA_FILES.append("src/libunicorn.so")
|
||||
|
||||
os.chdir("..")
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def dummy_src():
|
||||
return []
|
||||
|
||||
|
||||
setup(
|
||||
provides=['unicorn'],
|
||||
packages=['unicorn'],
|
||||
name=PKG_NAME,
|
||||
version=VERSION,
|
||||
author='Nguyen Anh Quynh',
|
||||
author_email='aquynh@gmail.com',
|
||||
description='Unicorn CPU emulator engine',
|
||||
url='http://www.unicorn-engine.org',
|
||||
classifiers=[
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
],
|
||||
requires=['ctypes'],
|
||||
cmdclass=dict(
|
||||
build_clib=custom_build_clib,
|
||||
sdist=custom_sdist,
|
||||
),
|
||||
|
||||
libraries=[(
|
||||
'unicorn', dict(
|
||||
package='unicorn',
|
||||
sources=dummy_src()
|
||||
),
|
||||
)],
|
||||
|
||||
data_files=[(SITE_PACKAGES, SETUP_DATA_FILES)],
|
||||
)
|
110
bindings/python/shellcode.py
Executable file
110
bindings/python/shellcode.py
Executable file
|
@ -0,0 +1,110 @@
|
|||
#!/usr/bin/env python
|
||||
# Sample code for X86 of Unicorn. Nguyen Anh Quynh <aquynh@gmail.com>
|
||||
|
||||
from __future__ import print_function
|
||||
from unicorn import *
|
||||
from unicorn.x86_const import *
|
||||
|
||||
|
||||
X86_CODE32 = b"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f"
|
||||
|
||||
X86_CODE32_SELF = b"\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41"
|
||||
|
||||
X86_CODE64 = "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"
|
||||
|
||||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print(">>> Instruction code at [0x%x] =" %(address), end="")
|
||||
for i in tmp:
|
||||
print(" %02x" %i, end="")
|
||||
print("")
|
||||
|
||||
|
||||
# callback for tracing basic blocks
|
||||
def hook_block(uc, address, size, user_data):
|
||||
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
|
||||
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
print("got interrupt %x ???" %intno);
|
||||
uc.emu_stop()
|
||||
return
|
||||
|
||||
eax = uc.reg_read(X86_REG_EAX)
|
||||
eip = uc.reg_read(X86_REG_EIP)
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(eip, intno, eax))
|
||||
uc.emu_stop()
|
||||
elif eax == 4: # sys_write
|
||||
# ECX = buffer address
|
||||
ecx = uc.reg_read(X86_REG_ECX)
|
||||
# EDX = buffer size
|
||||
edx = uc.reg_read(X86_REG_EDX)
|
||||
|
||||
try:
|
||||
buf = uc.mem_read(ecx, edx)
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = " \
|
||||
%(eip, intno, ecx, edx), end="")
|
||||
for i in buf:
|
||||
print("%c" %i, end="")
|
||||
print("")
|
||||
except UcError as e:
|
||||
print(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = <unknown>\n" \
|
||||
%(eip, intno, ecx, edx))
|
||||
else:
|
||||
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(eip, intno, eax))
|
||||
|
||||
|
||||
# Test X86 32 bit
|
||||
def test_i386(mode, code):
|
||||
print("Emulate x86 code")
|
||||
try:
|
||||
# Initialize emulator
|
||||
mu = Uc(UC_ARCH_X86, mode)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
||||
# write machine code to be emulated to memory
|
||||
mu.mem_write(ADDRESS, code)
|
||||
|
||||
# initialize stack
|
||||
mu.reg_write(X86_REG_ESP, ADDRESS + 0x200000)
|
||||
|
||||
# tracing all basic blocks with customized callback
|
||||
mu.hook_add(UC_HOOK_BLOCK, hook_block)
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# handle interrupt ourself
|
||||
mu.hook_add(UC_HOOK_INTR, hook_intr)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(code))
|
||||
|
||||
# now print out some registers
|
||||
print(">>> Emulation done")
|
||||
|
||||
except UcError as e:
|
||||
print("ERROR: %s" % e)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#test_i386(UC_MODE_32, X86_CODE32_SELF)
|
||||
#print("=" * 20)
|
||||
#test_i386(UC_MODE_32, X86_CODE32)
|
||||
#print("=" * 20)
|
||||
test_i386(UC_MODE_64, X86_CODE64) # FIXME
|
||||
|
458
bindings/python/unicorn/__init__.py
Normal file
458
bindings/python/unicorn/__init__.py
Normal file
|
@ -0,0 +1,458 @@
|
|||
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
|
||||
import sys
|
||||
_python2 = sys.version_info[0] < 3
|
||||
if _python2:
|
||||
range = xrange
|
||||
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
|
||||
|
||||
__all__ = [
|
||||
'Uc',
|
||||
|
||||
'uc_version',
|
||||
'uc_support',
|
||||
'version_bind',
|
||||
'debug',
|
||||
|
||||
'UC_API_MAJOR',
|
||||
'UC_API_MINOR',
|
||||
|
||||
'UC_ARCH_ARM',
|
||||
'UC_ARCH_ARM64',
|
||||
'UC_ARCH_MIPS',
|
||||
'UC_ARCH_X86',
|
||||
'UC_ARCH_SPARC',
|
||||
'UC_ARCH_M68K',
|
||||
'UC_ARCH_ALL',
|
||||
|
||||
'UC_MODE_LITTLE_ENDIAN',
|
||||
'UC_MODE_BIG_ENDIAN',
|
||||
'UC_MODE_16',
|
||||
'UC_MODE_32',
|
||||
'UC_MODE_64',
|
||||
'UC_MODE_ARM',
|
||||
'UC_MODE_THUMB',
|
||||
'UC_MODE_MCLASS',
|
||||
'UC_MODE_MICRO',
|
||||
'UC_MODE_MIPS3',
|
||||
'UC_MODE_MIPS32R6',
|
||||
'UC_MODE_MIPSGP64',
|
||||
'UC_MODE_V8',
|
||||
'UC_MODE_V9',
|
||||
'UC_MODE_MIPS32',
|
||||
'UC_MODE_MIPS64',
|
||||
|
||||
'UC_ERR_OK',
|
||||
'UC_ERR_OOM',
|
||||
'UC_ERR_ARCH',
|
||||
'UC_ERR_HANDLE',
|
||||
'UC_ERR_UCH',
|
||||
'UC_ERR_MODE',
|
||||
'UC_ERR_VERSION',
|
||||
'UC_ERR_MEM_READ',
|
||||
'UC_ERR_MEM_WRITE',
|
||||
'UC_ERR_CODE_INVALID',
|
||||
'UC_ERR_HOOK',
|
||||
'UC_ERR_INSN_INVALID',
|
||||
|
||||
'UC_HOOK_INTR',
|
||||
'UC_HOOK_INSN',
|
||||
'UC_HOOK_CODE',
|
||||
'UC_HOOK_BLOCK',
|
||||
'UC_HOOK_MEM_INVALID',
|
||||
'UC_HOOK_MEM_READ',
|
||||
'UC_HOOK_MEM_WRITE',
|
||||
'UC_HOOK_MEM_READ_WRITE',
|
||||
|
||||
'UC_MEM_READ',
|
||||
'UC_MEM_WRITE',
|
||||
'UC_MEM_READ_WRITE',
|
||||
|
||||
'UC_SECOND_SCALE',
|
||||
'UC_MILISECOND_SCALE',
|
||||
|
||||
'UcError',
|
||||
]
|
||||
|
||||
# Unicorn C interface
|
||||
|
||||
# API version
|
||||
UC_API_MAJOR = 0
|
||||
UC_API_MINOR = 9
|
||||
|
||||
# Architectures
|
||||
UC_ARCH_ARM = 1
|
||||
UC_ARCH_ARM64 = 2
|
||||
UC_ARCH_MIPS = 3
|
||||
UC_ARCH_X86 = 4
|
||||
UC_ARCH_PPC = 5
|
||||
UC_ARCH_SPARC = 6
|
||||
UC_ARCH_M68K = 7
|
||||
UC_ARCH_MAX = 8
|
||||
UC_ARCH_ALL = 0xFFFF
|
||||
|
||||
# Hardware modes
|
||||
UC_MODE_LITTLE_ENDIAN = 0 # little-endian mode (default mode)
|
||||
UC_MODE_ARM = 0 # ARM mode
|
||||
UC_MODE_16 = (1 << 1) # 16-bit mode (for X86)
|
||||
UC_MODE_32 = (1 << 2) # 32-bit mode (for X86)
|
||||
UC_MODE_64 = (1 << 3) # 64-bit mode (for X86, PPC)
|
||||
UC_MODE_THUMB = (1 << 4) # ARM's Thumb mode, including Thumb-2
|
||||
UC_MODE_MCLASS = (1 << 5) # ARM's Cortex-M series
|
||||
UC_MODE_V8 = (1 << 6) # ARMv8 A32 encodings for ARM
|
||||
UC_MODE_MICRO = (1 << 4) # MicroMips mode (MIPS architecture)
|
||||
UC_MODE_MIPS3 = (1 << 5) # Mips III ISA
|
||||
UC_MODE_MIPS32R6 = (1 << 6) # Mips32r6 ISA
|
||||
UC_MODE_MIPSGP64 = (1 << 7) # General Purpose Registers are 64-bit wide (MIPS arch)
|
||||
UC_MODE_V9 = (1 << 4) # Sparc V9 mode (for Sparc)
|
||||
UC_MODE_BIG_ENDIAN = (1 << 31) # big-endian mode
|
||||
UC_MODE_MIPS32 = UC_MODE_32 # Mips32 ISA
|
||||
UC_MODE_MIPS64 = UC_MODE_64 # Mips64 ISA
|
||||
|
||||
|
||||
# Unicorn error type
|
||||
UC_ERR_OK = 0 # No error: everything was fine
|
||||
UC_ERR_OOM = 1 # Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
UC_ERR_ARCH = 2 # Unsupported architecture: uc_open()
|
||||
UC_ERR_HANDLE = 3 # Invalid handle
|
||||
UC_ERR_UCH = 4 # Invalid handle (uch)
|
||||
UC_ERR_MODE = 5 # Invalid/unsupported mode: uc_open()
|
||||
UC_ERR_VERSION = 6 # Unsupported version (bindings)
|
||||
UC_ERR_MEM_READ = 7 # Quit emulation due to invalid memory READ: uc_emu_start()
|
||||
UC_ERR_MEM_WRITE = 8 # Quit emulation due to invalid memory WRITE: uc_emu_start()
|
||||
UC_ERR_CODE_INVALID = 9 # Quit emulation due to invalid code address: uc_emu_start()
|
||||
UC_ERR_HOOK = 10 # Invalid hook type: uc_hook_add()
|
||||
UC_ERR_INSN_INVALID = 11 # Invalid instruction
|
||||
|
||||
|
||||
# All type of hooks for uc_hook_add() API.
|
||||
UC_HOOK_INTR = 32 # Hook all interrupt events
|
||||
UC_HOOK_INSN = 33 # Hook a particular instruction
|
||||
UC_HOOK_CODE = 34 # Hook a range of code
|
||||
UC_HOOK_BLOCK = 35 # Hook basic blocks
|
||||
UC_HOOK_MEM_INVALID = 36 # Hook for all invalid memory access events
|
||||
UC_HOOK_MEM_READ = 37 # Hook all memory read events.
|
||||
UC_HOOK_MEM_WRITE = 38 # Hook all memory write events.
|
||||
UC_HOOK_MEM_READ_WRITE = 39 # Hook all memory accesses (either READ or WRITE).
|
||||
|
||||
|
||||
# All type of memory accesses for UC_HOOK_MEM_*
|
||||
UC_MEM_READ = 16 # Memory is read from
|
||||
UC_MEM_WRITE = 17 # Memory is written to
|
||||
UC_MEM_READ_WRITE = 18 # Memory is accessed (either READ or WRITE)
|
||||
|
||||
|
||||
# Time scales to calculate timeout on microsecond unit
|
||||
# This is for Uc.emu_start()
|
||||
UC_SECOND_SCALE = 1000000 # 1 second = 1000,000 microseconds
|
||||
UC_MILISECOND_SCALE = 1000 # 1 milisecond = 1000 nanoseconds
|
||||
|
||||
|
||||
import ctypes, ctypes.util, sys
|
||||
from os.path import split, join, dirname
|
||||
import distutils.sysconfig
|
||||
|
||||
|
||||
import inspect
|
||||
if not hasattr(sys.modules[__name__], '__file__'):
|
||||
__file__ = inspect.getfile(inspect.currentframe())
|
||||
|
||||
_lib_path = split(__file__)[0]
|
||||
_all_libs = ['unicorn.dll', 'libunicorn.so', 'libunicorn.dylib']
|
||||
_found = False
|
||||
|
||||
for _lib in _all_libs:
|
||||
try:
|
||||
_lib_file = join(_lib_path, _lib)
|
||||
# print "Trying to load:", _lib_file
|
||||
_uc = ctypes.cdll.LoadLibrary(_lib_file)
|
||||
_found = True
|
||||
break
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if _found == False:
|
||||
# try loading from default paths
|
||||
for _lib in _all_libs:
|
||||
try:
|
||||
_uc = ctypes.cdll.LoadLibrary(_lib)
|
||||
_found = True
|
||||
break
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if _found == False:
|
||||
# last try: loading from python lib directory
|
||||
_lib_path = distutils.sysconfig.get_python_lib()
|
||||
for _lib in _all_libs:
|
||||
try:
|
||||
_lib_file = join(_lib_path, 'unicorn', _lib)
|
||||
# print "Trying to load:", _lib_file
|
||||
_uc = ctypes.cdll.LoadLibrary(_lib_file)
|
||||
_found = True
|
||||
break
|
||||
except OSError:
|
||||
pass
|
||||
if _found == False:
|
||||
raise ImportError("ERROR: fail to load the dynamic library.")
|
||||
|
||||
|
||||
# setup all the function prototype
|
||||
def _setup_prototype(lib, fname, restype, *argtypes):
|
||||
getattr(lib, fname).restype = restype
|
||||
getattr(lib, fname).argtypes = argtypes
|
||||
|
||||
_setup_prototype(_uc, "uc_version", ctypes.c_int, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
|
||||
_setup_prototype(_uc, "uc_support", ctypes.c_bool, ctypes.c_int)
|
||||
_setup_prototype(_uc, "uc_open", ctypes.c_int, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(ctypes.c_size_t))
|
||||
_setup_prototype(_uc, "uc_close", ctypes.c_int, ctypes.POINTER(ctypes.c_size_t))
|
||||
_setup_prototype(_uc, "uc_strerror", ctypes.c_char_p, ctypes.c_int)
|
||||
_setup_prototype(_uc, "uc_errno", ctypes.c_int, ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_reg_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_reg_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_int, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_mem_read", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_mem_write", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.POINTER(ctypes.c_char), ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_emu_start", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_emu_stop", ctypes.c_int, ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_hook_del", ctypes.c_int, ctypes.c_size_t, ctypes.POINTER(ctypes.c_size_t))
|
||||
_setup_prototype(_uc, "uc_mem_map", ctypes.c_int, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t)
|
||||
|
||||
# uc_hook_add is special due to variable number of arguments
|
||||
_uc.uc_hook_add = getattr(_uc, "uc_hook_add")
|
||||
_uc.uc_hook_add.restype = ctypes.c_int
|
||||
|
||||
UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p)
|
||||
UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_size_t, ctypes.c_int, \
|
||||
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
|
||||
UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_int, \
|
||||
ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p)
|
||||
UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
|
||||
ctypes.c_void_p)
|
||||
UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, ctypes.c_size_t, ctypes.c_uint32, \
|
||||
ctypes.c_int, ctypes.c_void_p)
|
||||
UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, ctypes.c_size_t, ctypes.c_uint32, \
|
||||
ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p)
|
||||
|
||||
|
||||
# access to error code via @errno of UcError
|
||||
class UcError(Exception):
|
||||
def __init__(self, errno):
|
||||
self.errno = errno
|
||||
|
||||
def __str__(self):
|
||||
return _uc.uc_strerror(self.errno)
|
||||
|
||||
|
||||
# return the core's version
|
||||
def uc_version():
|
||||
major = ctypes.c_int()
|
||||
minor = ctypes.c_int()
|
||||
combined = _uc.uc_version(ctypes.byref(major), ctypes.byref(minor))
|
||||
return (major.value, minor.value, combined)
|
||||
|
||||
|
||||
# return the binding's version
|
||||
def version_bind():
|
||||
return (UC_API_MAJOR, UC_API_MINOR, (UC_API_MAJOR << 8) + UC_API_MINOR)
|
||||
|
||||
|
||||
# check to see if this engine supports a particular arch
|
||||
def uc_support(query):
|
||||
return _uc.uc_support(query)
|
||||
|
||||
|
||||
class Uc(object):
|
||||
def __init__(self, arch, mode):
|
||||
# verify version compatibility with the core before doing anything
|
||||
(major, minor, _combined) = uc_version()
|
||||
if major != UC_API_MAJOR or minor != UC_API_MINOR:
|
||||
self._uch = None
|
||||
# our binding version is different from the core's API version
|
||||
raise UcError(UC_ERR_VERSION)
|
||||
|
||||
self._arch, self._mode = arch, mode
|
||||
self._uch = ctypes.c_size_t()
|
||||
status = _uc.uc_open(arch, mode, ctypes.byref(self._uch))
|
||||
if status != UC_ERR_OK:
|
||||
self._uch = None
|
||||
raise UcError(status)
|
||||
# internal mapping table to save callback & userdata
|
||||
self._callbacks = {}
|
||||
self._callback_count = 0
|
||||
|
||||
|
||||
# destructor to be called automatically when object is destroyed.
|
||||
def __del__(self):
|
||||
if self._uch:
|
||||
try:
|
||||
status = _uc.uc_close(ctypes.byref(self._uch))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
except: # _uc might be pulled from under our feet
|
||||
pass
|
||||
|
||||
|
||||
# emulate from @begin, and stop when reaching address @until
|
||||
def emu_start(self, begin, until, timeout=0, count=0):
|
||||
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
|
||||
# stop emulation
|
||||
def emu_stop(self):
|
||||
status = _uc.uc_emu_stop(self._uch)
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
|
||||
# return the value of a register
|
||||
def reg_read(self, reg_id):
|
||||
# read to 64bit number to be safe
|
||||
reg = ctypes.c_int64(0)
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return reg.value
|
||||
|
||||
|
||||
# write to a register
|
||||
def reg_write(self, reg_id, value):
|
||||
# convert to 64bit number to be safe
|
||||
reg = ctypes.c_int64(value)
|
||||
status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
|
||||
# read data from memory
|
||||
def mem_read(self, address, size):
|
||||
data = ctypes.create_string_buffer(size)
|
||||
status = _uc.uc_mem_read(self._uch, address, data, size)
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return bytearray(data)
|
||||
|
||||
|
||||
# write to memory
|
||||
def mem_write(self, address, data):
|
||||
status = _uc.uc_mem_write(self._uch, address, data, len(data))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
|
||||
# map a range of memory
|
||||
def mem_map(self, address, size):
|
||||
status = _uc.uc_mem_map(self._uch, address, size)
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
|
||||
def _hookcode_cb(self, handle, address, size, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, address, size, data)
|
||||
|
||||
|
||||
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, access, address, size, value, data)
|
||||
|
||||
|
||||
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, access, address, size, value, data)
|
||||
|
||||
|
||||
def _hook_intr_cb(self, handle, intno, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, intno, data)
|
||||
|
||||
|
||||
def _hook_insn_in_cb(self, handle, port, size, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
return cb(self, port, size, data)
|
||||
|
||||
|
||||
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
|
||||
# call user's callback with self object
|
||||
(cb, data) = self._callbacks[user_data]
|
||||
cb(self, port, size, value, data)
|
||||
|
||||
|
||||
# add a hook
|
||||
def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
|
||||
_h2 = ctypes.c_size_t()
|
||||
|
||||
# save callback & user_data
|
||||
self._callback_count += 1
|
||||
self._callbacks[self._callback_count] = (callback, user_data)
|
||||
|
||||
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
|
||||
begin = ctypes.c_uint64(arg1)
|
||||
end = ctypes.c_uint64(arg2)
|
||||
# set callback with wrapper, so it can be called
|
||||
# with this object as param
|
||||
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
|
||||
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
|
||||
elif htype == UC_HOOK_MEM_INVALID:
|
||||
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE):
|
||||
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
elif htype == UC_HOOK_INSN:
|
||||
insn = ctypes.c_int(arg1)
|
||||
if arg1 == x86_const.X86_INS_IN: # IN instruction
|
||||
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
|
||||
if arg1 == x86_const.X86_INS_OUT: # OUT instruction
|
||||
cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn)
|
||||
elif htype == UC_HOOK_INTR:
|
||||
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
return _h2.value
|
||||
|
||||
|
||||
# delete a hook
|
||||
def hook_del(self, h):
|
||||
_h = ctypes.c_size_t(h)
|
||||
status = _uc.uc_hook_del(self._uch, ctypes.byref(_h))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
h = 0
|
||||
|
||||
|
||||
# print out debugging info
|
||||
def debug():
|
||||
archs = { "arm": UC_ARCH_ARM, "arm64": UC_ARCH_ARM64, \
|
||||
"mips": UC_ARCH_MIPS, "sparc": UC_ARCH_SPARC, \
|
||||
"m68k": UC_ARCH_M68K }
|
||||
|
||||
all_archs = ""
|
||||
keys = archs.keys()
|
||||
keys.sort()
|
||||
for k in keys:
|
||||
if uc_support(archs[k]):
|
||||
all_archs += "-%s" % k
|
||||
|
||||
if uc_support(UC_ARCH_X86):
|
||||
all_archs += "-x86"
|
||||
if uc_support(UC_SUPPORT_X86_REDUCE):
|
||||
all_archs += "_reduce"
|
||||
|
||||
(major, minor, _combined) = uc_version()
|
||||
|
||||
return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR)
|
274
bindings/python/unicorn/arm64_const.py
Normal file
274
bindings/python/unicorn/arm64_const.py
Normal file
|
@ -0,0 +1,274 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm64_const.py]
|
||||
|
||||
# ARM64 registers
|
||||
|
||||
ARM64_REG_INVALID = 0
|
||||
ARM64_REG_X29 = 1
|
||||
ARM64_REG_X30 = 2
|
||||
ARM64_REG_NZCV = 3
|
||||
ARM64_REG_SP = 4
|
||||
ARM64_REG_WSP = 5
|
||||
ARM64_REG_WZR = 6
|
||||
ARM64_REG_XZR = 7
|
||||
ARM64_REG_B0 = 8
|
||||
ARM64_REG_B1 = 9
|
||||
ARM64_REG_B2 = 10
|
||||
ARM64_REG_B3 = 11
|
||||
ARM64_REG_B4 = 12
|
||||
ARM64_REG_B5 = 13
|
||||
ARM64_REG_B6 = 14
|
||||
ARM64_REG_B7 = 15
|
||||
ARM64_REG_B8 = 16
|
||||
ARM64_REG_B9 = 17
|
||||
ARM64_REG_B10 = 18
|
||||
ARM64_REG_B11 = 19
|
||||
ARM64_REG_B12 = 20
|
||||
ARM64_REG_B13 = 21
|
||||
ARM64_REG_B14 = 22
|
||||
ARM64_REG_B15 = 23
|
||||
ARM64_REG_B16 = 24
|
||||
ARM64_REG_B17 = 25
|
||||
ARM64_REG_B18 = 26
|
||||
ARM64_REG_B19 = 27
|
||||
ARM64_REG_B20 = 28
|
||||
ARM64_REG_B21 = 29
|
||||
ARM64_REG_B22 = 30
|
||||
ARM64_REG_B23 = 31
|
||||
ARM64_REG_B24 = 32
|
||||
ARM64_REG_B25 = 33
|
||||
ARM64_REG_B26 = 34
|
||||
ARM64_REG_B27 = 35
|
||||
ARM64_REG_B28 = 36
|
||||
ARM64_REG_B29 = 37
|
||||
ARM64_REG_B30 = 38
|
||||
ARM64_REG_B31 = 39
|
||||
ARM64_REG_D0 = 40
|
||||
ARM64_REG_D1 = 41
|
||||
ARM64_REG_D2 = 42
|
||||
ARM64_REG_D3 = 43
|
||||
ARM64_REG_D4 = 44
|
||||
ARM64_REG_D5 = 45
|
||||
ARM64_REG_D6 = 46
|
||||
ARM64_REG_D7 = 47
|
||||
ARM64_REG_D8 = 48
|
||||
ARM64_REG_D9 = 49
|
||||
ARM64_REG_D10 = 50
|
||||
ARM64_REG_D11 = 51
|
||||
ARM64_REG_D12 = 52
|
||||
ARM64_REG_D13 = 53
|
||||
ARM64_REG_D14 = 54
|
||||
ARM64_REG_D15 = 55
|
||||
ARM64_REG_D16 = 56
|
||||
ARM64_REG_D17 = 57
|
||||
ARM64_REG_D18 = 58
|
||||
ARM64_REG_D19 = 59
|
||||
ARM64_REG_D20 = 60
|
||||
ARM64_REG_D21 = 61
|
||||
ARM64_REG_D22 = 62
|
||||
ARM64_REG_D23 = 63
|
||||
ARM64_REG_D24 = 64
|
||||
ARM64_REG_D25 = 65
|
||||
ARM64_REG_D26 = 66
|
||||
ARM64_REG_D27 = 67
|
||||
ARM64_REG_D28 = 68
|
||||
ARM64_REG_D29 = 69
|
||||
ARM64_REG_D30 = 70
|
||||
ARM64_REG_D31 = 71
|
||||
ARM64_REG_H0 = 72
|
||||
ARM64_REG_H1 = 73
|
||||
ARM64_REG_H2 = 74
|
||||
ARM64_REG_H3 = 75
|
||||
ARM64_REG_H4 = 76
|
||||
ARM64_REG_H5 = 77
|
||||
ARM64_REG_H6 = 78
|
||||
ARM64_REG_H7 = 79
|
||||
ARM64_REG_H8 = 80
|
||||
ARM64_REG_H9 = 81
|
||||
ARM64_REG_H10 = 82
|
||||
ARM64_REG_H11 = 83
|
||||
ARM64_REG_H12 = 84
|
||||
ARM64_REG_H13 = 85
|
||||
ARM64_REG_H14 = 86
|
||||
ARM64_REG_H15 = 87
|
||||
ARM64_REG_H16 = 88
|
||||
ARM64_REG_H17 = 89
|
||||
ARM64_REG_H18 = 90
|
||||
ARM64_REG_H19 = 91
|
||||
ARM64_REG_H20 = 92
|
||||
ARM64_REG_H21 = 93
|
||||
ARM64_REG_H22 = 94
|
||||
ARM64_REG_H23 = 95
|
||||
ARM64_REG_H24 = 96
|
||||
ARM64_REG_H25 = 97
|
||||
ARM64_REG_H26 = 98
|
||||
ARM64_REG_H27 = 99
|
||||
ARM64_REG_H28 = 100
|
||||
ARM64_REG_H29 = 101
|
||||
ARM64_REG_H30 = 102
|
||||
ARM64_REG_H31 = 103
|
||||
ARM64_REG_Q0 = 104
|
||||
ARM64_REG_Q1 = 105
|
||||
ARM64_REG_Q2 = 106
|
||||
ARM64_REG_Q3 = 107
|
||||
ARM64_REG_Q4 = 108
|
||||
ARM64_REG_Q5 = 109
|
||||
ARM64_REG_Q6 = 110
|
||||
ARM64_REG_Q7 = 111
|
||||
ARM64_REG_Q8 = 112
|
||||
ARM64_REG_Q9 = 113
|
||||
ARM64_REG_Q10 = 114
|
||||
ARM64_REG_Q11 = 115
|
||||
ARM64_REG_Q12 = 116
|
||||
ARM64_REG_Q13 = 117
|
||||
ARM64_REG_Q14 = 118
|
||||
ARM64_REG_Q15 = 119
|
||||
ARM64_REG_Q16 = 120
|
||||
ARM64_REG_Q17 = 121
|
||||
ARM64_REG_Q18 = 122
|
||||
ARM64_REG_Q19 = 123
|
||||
ARM64_REG_Q20 = 124
|
||||
ARM64_REG_Q21 = 125
|
||||
ARM64_REG_Q22 = 126
|
||||
ARM64_REG_Q23 = 127
|
||||
ARM64_REG_Q24 = 128
|
||||
ARM64_REG_Q25 = 129
|
||||
ARM64_REG_Q26 = 130
|
||||
ARM64_REG_Q27 = 131
|
||||
ARM64_REG_Q28 = 132
|
||||
ARM64_REG_Q29 = 133
|
||||
ARM64_REG_Q30 = 134
|
||||
ARM64_REG_Q31 = 135
|
||||
ARM64_REG_S0 = 136
|
||||
ARM64_REG_S1 = 137
|
||||
ARM64_REG_S2 = 138
|
||||
ARM64_REG_S3 = 139
|
||||
ARM64_REG_S4 = 140
|
||||
ARM64_REG_S5 = 141
|
||||
ARM64_REG_S6 = 142
|
||||
ARM64_REG_S7 = 143
|
||||
ARM64_REG_S8 = 144
|
||||
ARM64_REG_S9 = 145
|
||||
ARM64_REG_S10 = 146
|
||||
ARM64_REG_S11 = 147
|
||||
ARM64_REG_S12 = 148
|
||||
ARM64_REG_S13 = 149
|
||||
ARM64_REG_S14 = 150
|
||||
ARM64_REG_S15 = 151
|
||||
ARM64_REG_S16 = 152
|
||||
ARM64_REG_S17 = 153
|
||||
ARM64_REG_S18 = 154
|
||||
ARM64_REG_S19 = 155
|
||||
ARM64_REG_S20 = 156
|
||||
ARM64_REG_S21 = 157
|
||||
ARM64_REG_S22 = 158
|
||||
ARM64_REG_S23 = 159
|
||||
ARM64_REG_S24 = 160
|
||||
ARM64_REG_S25 = 161
|
||||
ARM64_REG_S26 = 162
|
||||
ARM64_REG_S27 = 163
|
||||
ARM64_REG_S28 = 164
|
||||
ARM64_REG_S29 = 165
|
||||
ARM64_REG_S30 = 166
|
||||
ARM64_REG_S31 = 167
|
||||
ARM64_REG_W0 = 168
|
||||
ARM64_REG_W1 = 169
|
||||
ARM64_REG_W2 = 170
|
||||
ARM64_REG_W3 = 171
|
||||
ARM64_REG_W4 = 172
|
||||
ARM64_REG_W5 = 173
|
||||
ARM64_REG_W6 = 174
|
||||
ARM64_REG_W7 = 175
|
||||
ARM64_REG_W8 = 176
|
||||
ARM64_REG_W9 = 177
|
||||
ARM64_REG_W10 = 178
|
||||
ARM64_REG_W11 = 179
|
||||
ARM64_REG_W12 = 180
|
||||
ARM64_REG_W13 = 181
|
||||
ARM64_REG_W14 = 182
|
||||
ARM64_REG_W15 = 183
|
||||
ARM64_REG_W16 = 184
|
||||
ARM64_REG_W17 = 185
|
||||
ARM64_REG_W18 = 186
|
||||
ARM64_REG_W19 = 187
|
||||
ARM64_REG_W20 = 188
|
||||
ARM64_REG_W21 = 189
|
||||
ARM64_REG_W22 = 190
|
||||
ARM64_REG_W23 = 191
|
||||
ARM64_REG_W24 = 192
|
||||
ARM64_REG_W25 = 193
|
||||
ARM64_REG_W26 = 194
|
||||
ARM64_REG_W27 = 195
|
||||
ARM64_REG_W28 = 196
|
||||
ARM64_REG_W29 = 197
|
||||
ARM64_REG_W30 = 198
|
||||
ARM64_REG_X0 = 199
|
||||
ARM64_REG_X1 = 200
|
||||
ARM64_REG_X2 = 201
|
||||
ARM64_REG_X3 = 202
|
||||
ARM64_REG_X4 = 203
|
||||
ARM64_REG_X5 = 204
|
||||
ARM64_REG_X6 = 205
|
||||
ARM64_REG_X7 = 206
|
||||
ARM64_REG_X8 = 207
|
||||
ARM64_REG_X9 = 208
|
||||
ARM64_REG_X10 = 209
|
||||
ARM64_REG_X11 = 210
|
||||
ARM64_REG_X12 = 211
|
||||
ARM64_REG_X13 = 212
|
||||
ARM64_REG_X14 = 213
|
||||
ARM64_REG_X15 = 214
|
||||
ARM64_REG_X16 = 215
|
||||
ARM64_REG_X17 = 216
|
||||
ARM64_REG_X18 = 217
|
||||
ARM64_REG_X19 = 218
|
||||
ARM64_REG_X20 = 219
|
||||
ARM64_REG_X21 = 220
|
||||
ARM64_REG_X22 = 221
|
||||
ARM64_REG_X23 = 222
|
||||
ARM64_REG_X24 = 223
|
||||
ARM64_REG_X25 = 224
|
||||
ARM64_REG_X26 = 225
|
||||
ARM64_REG_X27 = 226
|
||||
ARM64_REG_X28 = 227
|
||||
ARM64_REG_V0 = 228
|
||||
ARM64_REG_V1 = 229
|
||||
ARM64_REG_V2 = 230
|
||||
ARM64_REG_V3 = 231
|
||||
ARM64_REG_V4 = 232
|
||||
ARM64_REG_V5 = 233
|
||||
ARM64_REG_V6 = 234
|
||||
ARM64_REG_V7 = 235
|
||||
ARM64_REG_V8 = 236
|
||||
ARM64_REG_V9 = 237
|
||||
ARM64_REG_V10 = 238
|
||||
ARM64_REG_V11 = 239
|
||||
ARM64_REG_V12 = 240
|
||||
ARM64_REG_V13 = 241
|
||||
ARM64_REG_V14 = 242
|
||||
ARM64_REG_V15 = 243
|
||||
ARM64_REG_V16 = 244
|
||||
ARM64_REG_V17 = 245
|
||||
ARM64_REG_V18 = 246
|
||||
ARM64_REG_V19 = 247
|
||||
ARM64_REG_V20 = 248
|
||||
ARM64_REG_V21 = 249
|
||||
ARM64_REG_V22 = 250
|
||||
ARM64_REG_V23 = 251
|
||||
ARM64_REG_V24 = 252
|
||||
ARM64_REG_V25 = 253
|
||||
ARM64_REG_V26 = 254
|
||||
ARM64_REG_V27 = 255
|
||||
ARM64_REG_V28 = 256
|
||||
ARM64_REG_V29 = 257
|
||||
ARM64_REG_V30 = 258
|
||||
ARM64_REG_V31 = 259
|
||||
|
||||
# pseudo registers
|
||||
ARM64_REG_PC = 260
|
||||
ARM64_REG_ENDING = 261
|
||||
|
||||
# alias registers
|
||||
ARM64_REG_IP1 = ARM64_REG_X16
|
||||
ARM64_REG_IP0 = ARM64_REG_X17
|
||||
ARM64_REG_FP = ARM64_REG_X29
|
||||
ARM64_REG_LR = ARM64_REG_X30
|
125
bindings/python/unicorn/arm_const.py
Normal file
125
bindings/python/unicorn/arm_const.py
Normal file
|
@ -0,0 +1,125 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.py]
|
||||
|
||||
# ARM registers
|
||||
|
||||
ARM_REG_INVALID = 0
|
||||
ARM_REG_APSR = 1
|
||||
ARM_REG_APSR_NZCV = 2
|
||||
ARM_REG_CPSR = 3
|
||||
ARM_REG_FPEXC = 4
|
||||
ARM_REG_FPINST = 5
|
||||
ARM_REG_FPSCR = 6
|
||||
ARM_REG_FPSCR_NZCV = 7
|
||||
ARM_REG_FPSID = 8
|
||||
ARM_REG_ITSTATE = 9
|
||||
ARM_REG_LR = 10
|
||||
ARM_REG_PC = 11
|
||||
ARM_REG_SP = 12
|
||||
ARM_REG_SPSR = 13
|
||||
ARM_REG_D0 = 14
|
||||
ARM_REG_D1 = 15
|
||||
ARM_REG_D2 = 16
|
||||
ARM_REG_D3 = 17
|
||||
ARM_REG_D4 = 18
|
||||
ARM_REG_D5 = 19
|
||||
ARM_REG_D6 = 20
|
||||
ARM_REG_D7 = 21
|
||||
ARM_REG_D8 = 22
|
||||
ARM_REG_D9 = 23
|
||||
ARM_REG_D10 = 24
|
||||
ARM_REG_D11 = 25
|
||||
ARM_REG_D12 = 26
|
||||
ARM_REG_D13 = 27
|
||||
ARM_REG_D14 = 28
|
||||
ARM_REG_D15 = 29
|
||||
ARM_REG_D16 = 30
|
||||
ARM_REG_D17 = 31
|
||||
ARM_REG_D18 = 32
|
||||
ARM_REG_D19 = 33
|
||||
ARM_REG_D20 = 34
|
||||
ARM_REG_D21 = 35
|
||||
ARM_REG_D22 = 36
|
||||
ARM_REG_D23 = 37
|
||||
ARM_REG_D24 = 38
|
||||
ARM_REG_D25 = 39
|
||||
ARM_REG_D26 = 40
|
||||
ARM_REG_D27 = 41
|
||||
ARM_REG_D28 = 42
|
||||
ARM_REG_D29 = 43
|
||||
ARM_REG_D30 = 44
|
||||
ARM_REG_D31 = 45
|
||||
ARM_REG_FPINST2 = 46
|
||||
ARM_REG_MVFR0 = 47
|
||||
ARM_REG_MVFR1 = 48
|
||||
ARM_REG_MVFR2 = 49
|
||||
ARM_REG_Q0 = 50
|
||||
ARM_REG_Q1 = 51
|
||||
ARM_REG_Q2 = 52
|
||||
ARM_REG_Q3 = 53
|
||||
ARM_REG_Q4 = 54
|
||||
ARM_REG_Q5 = 55
|
||||
ARM_REG_Q6 = 56
|
||||
ARM_REG_Q7 = 57
|
||||
ARM_REG_Q8 = 58
|
||||
ARM_REG_Q9 = 59
|
||||
ARM_REG_Q10 = 60
|
||||
ARM_REG_Q11 = 61
|
||||
ARM_REG_Q12 = 62
|
||||
ARM_REG_Q13 = 63
|
||||
ARM_REG_Q14 = 64
|
||||
ARM_REG_Q15 = 65
|
||||
ARM_REG_R0 = 66
|
||||
ARM_REG_R1 = 67
|
||||
ARM_REG_R2 = 68
|
||||
ARM_REG_R3 = 69
|
||||
ARM_REG_R4 = 70
|
||||
ARM_REG_R5 = 71
|
||||
ARM_REG_R6 = 72
|
||||
ARM_REG_R7 = 73
|
||||
ARM_REG_R8 = 74
|
||||
ARM_REG_R9 = 75
|
||||
ARM_REG_R10 = 76
|
||||
ARM_REG_R11 = 77
|
||||
ARM_REG_R12 = 78
|
||||
ARM_REG_S0 = 79
|
||||
ARM_REG_S1 = 80
|
||||
ARM_REG_S2 = 81
|
||||
ARM_REG_S3 = 82
|
||||
ARM_REG_S4 = 83
|
||||
ARM_REG_S5 = 84
|
||||
ARM_REG_S6 = 85
|
||||
ARM_REG_S7 = 86
|
||||
ARM_REG_S8 = 87
|
||||
ARM_REG_S9 = 88
|
||||
ARM_REG_S10 = 89
|
||||
ARM_REG_S11 = 90
|
||||
ARM_REG_S12 = 91
|
||||
ARM_REG_S13 = 92
|
||||
ARM_REG_S14 = 93
|
||||
ARM_REG_S15 = 94
|
||||
ARM_REG_S16 = 95
|
||||
ARM_REG_S17 = 96
|
||||
ARM_REG_S18 = 97
|
||||
ARM_REG_S19 = 98
|
||||
ARM_REG_S20 = 99
|
||||
ARM_REG_S21 = 100
|
||||
ARM_REG_S22 = 101
|
||||
ARM_REG_S23 = 102
|
||||
ARM_REG_S24 = 103
|
||||
ARM_REG_S25 = 104
|
||||
ARM_REG_S26 = 105
|
||||
ARM_REG_S27 = 106
|
||||
ARM_REG_S28 = 107
|
||||
ARM_REG_S29 = 108
|
||||
ARM_REG_S30 = 109
|
||||
ARM_REG_S31 = 110
|
||||
ARM_REG_ENDING = 111
|
||||
|
||||
# alias registers
|
||||
ARM_REG_R13 = ARM_REG_SP
|
||||
ARM_REG_R14 = ARM_REG_LR
|
||||
ARM_REG_R15 = ARM_REG_PC
|
||||
ARM_REG_SB = ARM_REG_R9
|
||||
ARM_REG_SL = ARM_REG_R10
|
||||
ARM_REG_FP = ARM_REG_R11
|
||||
ARM_REG_IP = ARM_REG_R12
|
24
bindings/python/unicorn/m68k_const.py
Normal file
24
bindings/python/unicorn/m68k_const.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.py]
|
||||
|
||||
# M68K registers
|
||||
|
||||
M68K_REG_INVALID = 0
|
||||
M68K_REG_A0 = 1
|
||||
M68K_REG_A1 = 2
|
||||
M68K_REG_A2 = 3
|
||||
M68K_REG_A3 = 4
|
||||
M68K_REG_A4 = 5
|
||||
M68K_REG_A5 = 6
|
||||
M68K_REG_A6 = 7
|
||||
M68K_REG_A7 = 8
|
||||
M68K_REG_D0 = 9
|
||||
M68K_REG_D1 = 10
|
||||
M68K_REG_D2 = 11
|
||||
M68K_REG_D3 = 12
|
||||
M68K_REG_D4 = 13
|
||||
M68K_REG_D5 = 14
|
||||
M68K_REG_D6 = 15
|
||||
M68K_REG_D7 = 16
|
||||
M68K_REG_SR = 17
|
||||
M68K_REG_PC = 18
|
||||
M68K_REG_ENDING = 19
|
195
bindings/python/unicorn/mips_const.py
Normal file
195
bindings/python/unicorn/mips_const.py
Normal file
|
@ -0,0 +1,195 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [mips_const.py]
|
||||
|
||||
# MIPS registers
|
||||
|
||||
MIPS_REG_INVALID = 0
|
||||
|
||||
# General purpose registers
|
||||
MIPS_REG_PC = 1
|
||||
MIPS_REG_0 = 2
|
||||
MIPS_REG_1 = 3
|
||||
MIPS_REG_2 = 4
|
||||
MIPS_REG_3 = 5
|
||||
MIPS_REG_4 = 6
|
||||
MIPS_REG_5 = 7
|
||||
MIPS_REG_6 = 8
|
||||
MIPS_REG_7 = 9
|
||||
MIPS_REG_8 = 10
|
||||
MIPS_REG_9 = 11
|
||||
MIPS_REG_10 = 12
|
||||
MIPS_REG_11 = 13
|
||||
MIPS_REG_12 = 14
|
||||
MIPS_REG_13 = 15
|
||||
MIPS_REG_14 = 16
|
||||
MIPS_REG_15 = 17
|
||||
MIPS_REG_16 = 18
|
||||
MIPS_REG_17 = 19
|
||||
MIPS_REG_18 = 20
|
||||
MIPS_REG_19 = 21
|
||||
MIPS_REG_20 = 22
|
||||
MIPS_REG_21 = 23
|
||||
MIPS_REG_22 = 24
|
||||
MIPS_REG_23 = 25
|
||||
MIPS_REG_24 = 26
|
||||
MIPS_REG_25 = 27
|
||||
MIPS_REG_26 = 28
|
||||
MIPS_REG_27 = 29
|
||||
MIPS_REG_28 = 30
|
||||
MIPS_REG_29 = 31
|
||||
MIPS_REG_30 = 32
|
||||
MIPS_REG_31 = 33
|
||||
|
||||
# DSP registers
|
||||
MIPS_REG_DSPCCOND = 34
|
||||
MIPS_REG_DSPCARRY = 35
|
||||
MIPS_REG_DSPEFI = 36
|
||||
MIPS_REG_DSPOUTFLAG = 37
|
||||
MIPS_REG_DSPOUTFLAG16_19 = 38
|
||||
MIPS_REG_DSPOUTFLAG20 = 39
|
||||
MIPS_REG_DSPOUTFLAG21 = 40
|
||||
MIPS_REG_DSPOUTFLAG22 = 41
|
||||
MIPS_REG_DSPOUTFLAG23 = 42
|
||||
MIPS_REG_DSPPOS = 43
|
||||
MIPS_REG_DSPSCOUNT = 44
|
||||
|
||||
# ACC registers
|
||||
MIPS_REG_AC0 = 45
|
||||
MIPS_REG_AC1 = 46
|
||||
MIPS_REG_AC2 = 47
|
||||
MIPS_REG_AC3 = 48
|
||||
|
||||
# COP registers
|
||||
MIPS_REG_CC0 = 49
|
||||
MIPS_REG_CC1 = 50
|
||||
MIPS_REG_CC2 = 51
|
||||
MIPS_REG_CC3 = 52
|
||||
MIPS_REG_CC4 = 53
|
||||
MIPS_REG_CC5 = 54
|
||||
MIPS_REG_CC6 = 55
|
||||
MIPS_REG_CC7 = 56
|
||||
|
||||
# FPU registers
|
||||
MIPS_REG_F0 = 57
|
||||
MIPS_REG_F1 = 58
|
||||
MIPS_REG_F2 = 59
|
||||
MIPS_REG_F3 = 60
|
||||
MIPS_REG_F4 = 61
|
||||
MIPS_REG_F5 = 62
|
||||
MIPS_REG_F6 = 63
|
||||
MIPS_REG_F7 = 64
|
||||
MIPS_REG_F8 = 65
|
||||
MIPS_REG_F9 = 66
|
||||
MIPS_REG_F10 = 67
|
||||
MIPS_REG_F11 = 68
|
||||
MIPS_REG_F12 = 69
|
||||
MIPS_REG_F13 = 70
|
||||
MIPS_REG_F14 = 71
|
||||
MIPS_REG_F15 = 72
|
||||
MIPS_REG_F16 = 73
|
||||
MIPS_REG_F17 = 74
|
||||
MIPS_REG_F18 = 75
|
||||
MIPS_REG_F19 = 76
|
||||
MIPS_REG_F20 = 77
|
||||
MIPS_REG_F21 = 78
|
||||
MIPS_REG_F22 = 79
|
||||
MIPS_REG_F23 = 80
|
||||
MIPS_REG_F24 = 81
|
||||
MIPS_REG_F25 = 82
|
||||
MIPS_REG_F26 = 83
|
||||
MIPS_REG_F27 = 84
|
||||
MIPS_REG_F28 = 85
|
||||
MIPS_REG_F29 = 86
|
||||
MIPS_REG_F30 = 87
|
||||
MIPS_REG_F31 = 88
|
||||
MIPS_REG_FCC0 = 89
|
||||
MIPS_REG_FCC1 = 90
|
||||
MIPS_REG_FCC2 = 91
|
||||
MIPS_REG_FCC3 = 92
|
||||
MIPS_REG_FCC4 = 93
|
||||
MIPS_REG_FCC5 = 94
|
||||
MIPS_REG_FCC6 = 95
|
||||
MIPS_REG_FCC7 = 96
|
||||
|
||||
# AFPR128
|
||||
MIPS_REG_W0 = 97
|
||||
MIPS_REG_W1 = 98
|
||||
MIPS_REG_W2 = 99
|
||||
MIPS_REG_W3 = 100
|
||||
MIPS_REG_W4 = 101
|
||||
MIPS_REG_W5 = 102
|
||||
MIPS_REG_W6 = 103
|
||||
MIPS_REG_W7 = 104
|
||||
MIPS_REG_W8 = 105
|
||||
MIPS_REG_W9 = 106
|
||||
MIPS_REG_W10 = 107
|
||||
MIPS_REG_W11 = 108
|
||||
MIPS_REG_W12 = 109
|
||||
MIPS_REG_W13 = 110
|
||||
MIPS_REG_W14 = 111
|
||||
MIPS_REG_W15 = 112
|
||||
MIPS_REG_W16 = 113
|
||||
MIPS_REG_W17 = 114
|
||||
MIPS_REG_W18 = 115
|
||||
MIPS_REG_W19 = 116
|
||||
MIPS_REG_W20 = 117
|
||||
MIPS_REG_W21 = 118
|
||||
MIPS_REG_W22 = 119
|
||||
MIPS_REG_W23 = 120
|
||||
MIPS_REG_W24 = 121
|
||||
MIPS_REG_W25 = 122
|
||||
MIPS_REG_W26 = 123
|
||||
MIPS_REG_W27 = 124
|
||||
MIPS_REG_W28 = 125
|
||||
MIPS_REG_W29 = 126
|
||||
MIPS_REG_W30 = 127
|
||||
MIPS_REG_W31 = 128
|
||||
MIPS_REG_HI = 129
|
||||
MIPS_REG_LO = 130
|
||||
MIPS_REG_P0 = 131
|
||||
MIPS_REG_P1 = 132
|
||||
MIPS_REG_P2 = 133
|
||||
MIPS_REG_MPL0 = 134
|
||||
MIPS_REG_MPL1 = 135
|
||||
MIPS_REG_MPL2 = 136
|
||||
MIPS_REG_ENDING = 137
|
||||
MIPS_REG_ZERO = MIPS_REG_0
|
||||
MIPS_REG_AT = MIPS_REG_1
|
||||
MIPS_REG_V0 = MIPS_REG_2
|
||||
MIPS_REG_V1 = MIPS_REG_3
|
||||
MIPS_REG_A0 = MIPS_REG_4
|
||||
MIPS_REG_A1 = MIPS_REG_5
|
||||
MIPS_REG_A2 = MIPS_REG_6
|
||||
MIPS_REG_A3 = MIPS_REG_7
|
||||
MIPS_REG_T0 = MIPS_REG_8
|
||||
MIPS_REG_T1 = MIPS_REG_9
|
||||
MIPS_REG_T2 = MIPS_REG_10
|
||||
MIPS_REG_T3 = MIPS_REG_11
|
||||
MIPS_REG_T4 = MIPS_REG_12
|
||||
MIPS_REG_T5 = MIPS_REG_13
|
||||
MIPS_REG_T6 = MIPS_REG_14
|
||||
MIPS_REG_T7 = MIPS_REG_15
|
||||
MIPS_REG_S0 = MIPS_REG_16
|
||||
MIPS_REG_S1 = MIPS_REG_17
|
||||
MIPS_REG_S2 = MIPS_REG_18
|
||||
MIPS_REG_S3 = MIPS_REG_19
|
||||
MIPS_REG_S4 = MIPS_REG_20
|
||||
MIPS_REG_S5 = MIPS_REG_21
|
||||
MIPS_REG_S6 = MIPS_REG_22
|
||||
MIPS_REG_S7 = MIPS_REG_23
|
||||
MIPS_REG_T8 = MIPS_REG_24
|
||||
MIPS_REG_T9 = MIPS_REG_25
|
||||
MIPS_REG_K0 = MIPS_REG_26
|
||||
MIPS_REG_K1 = MIPS_REG_27
|
||||
MIPS_REG_GP = MIPS_REG_28
|
||||
MIPS_REG_SP = MIPS_REG_29
|
||||
MIPS_REG_FP = MIPS_REG_30
|
||||
MIPS_REG_S8 = MIPS_REG_30
|
||||
MIPS_REG_RA = MIPS_REG_31
|
||||
MIPS_REG_HI0 = MIPS_REG_AC0
|
||||
MIPS_REG_HI1 = MIPS_REG_AC1
|
||||
MIPS_REG_HI2 = MIPS_REG_AC2
|
||||
MIPS_REG_HI3 = MIPS_REG_AC3
|
||||
MIPS_REG_LO0 = MIPS_REG_HI0
|
||||
MIPS_REG_LO1 = MIPS_REG_HI1
|
||||
MIPS_REG_LO2 = MIPS_REG_HI2
|
||||
MIPS_REG_LO3 = MIPS_REG_HI3
|
96
bindings/python/unicorn/sparc_const.py
Normal file
96
bindings/python/unicorn/sparc_const.py
Normal file
|
@ -0,0 +1,96 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.py]
|
||||
|
||||
# SPARC registers
|
||||
|
||||
SPARC_REG_INVALID = 0
|
||||
SPARC_REG_F0 = 1
|
||||
SPARC_REG_F1 = 2
|
||||
SPARC_REG_F2 = 3
|
||||
SPARC_REG_F3 = 4
|
||||
SPARC_REG_F4 = 5
|
||||
SPARC_REG_F5 = 6
|
||||
SPARC_REG_F6 = 7
|
||||
SPARC_REG_F7 = 8
|
||||
SPARC_REG_F8 = 9
|
||||
SPARC_REG_F9 = 10
|
||||
SPARC_REG_F10 = 11
|
||||
SPARC_REG_F11 = 12
|
||||
SPARC_REG_F12 = 13
|
||||
SPARC_REG_F13 = 14
|
||||
SPARC_REG_F14 = 15
|
||||
SPARC_REG_F15 = 16
|
||||
SPARC_REG_F16 = 17
|
||||
SPARC_REG_F17 = 18
|
||||
SPARC_REG_F18 = 19
|
||||
SPARC_REG_F19 = 20
|
||||
SPARC_REG_F20 = 21
|
||||
SPARC_REG_F21 = 22
|
||||
SPARC_REG_F22 = 23
|
||||
SPARC_REG_F23 = 24
|
||||
SPARC_REG_F24 = 25
|
||||
SPARC_REG_F25 = 26
|
||||
SPARC_REG_F26 = 27
|
||||
SPARC_REG_F27 = 28
|
||||
SPARC_REG_F28 = 29
|
||||
SPARC_REG_F29 = 30
|
||||
SPARC_REG_F30 = 31
|
||||
SPARC_REG_F31 = 32
|
||||
SPARC_REG_F32 = 33
|
||||
SPARC_REG_F34 = 34
|
||||
SPARC_REG_F36 = 35
|
||||
SPARC_REG_F38 = 36
|
||||
SPARC_REG_F40 = 37
|
||||
SPARC_REG_F42 = 38
|
||||
SPARC_REG_F44 = 39
|
||||
SPARC_REG_F46 = 40
|
||||
SPARC_REG_F48 = 41
|
||||
SPARC_REG_F50 = 42
|
||||
SPARC_REG_F52 = 43
|
||||
SPARC_REG_F54 = 44
|
||||
SPARC_REG_F56 = 45
|
||||
SPARC_REG_F58 = 46
|
||||
SPARC_REG_F60 = 47
|
||||
SPARC_REG_F62 = 48
|
||||
SPARC_REG_FCC0 = 49
|
||||
SPARC_REG_FCC1 = 50
|
||||
SPARC_REG_FCC2 = 51
|
||||
SPARC_REG_FCC3 = 52
|
||||
SPARC_REG_FP = 53
|
||||
SPARC_REG_G0 = 54
|
||||
SPARC_REG_G1 = 55
|
||||
SPARC_REG_G2 = 56
|
||||
SPARC_REG_G3 = 57
|
||||
SPARC_REG_G4 = 58
|
||||
SPARC_REG_G5 = 59
|
||||
SPARC_REG_G6 = 60
|
||||
SPARC_REG_G7 = 61
|
||||
SPARC_REG_I0 = 62
|
||||
SPARC_REG_I1 = 63
|
||||
SPARC_REG_I2 = 64
|
||||
SPARC_REG_I3 = 65
|
||||
SPARC_REG_I4 = 66
|
||||
SPARC_REG_I5 = 67
|
||||
SPARC_REG_I7 = 68
|
||||
SPARC_REG_ICC = 69
|
||||
SPARC_REG_L0 = 70
|
||||
SPARC_REG_L1 = 71
|
||||
SPARC_REG_L2 = 72
|
||||
SPARC_REG_L3 = 73
|
||||
SPARC_REG_L4 = 74
|
||||
SPARC_REG_L5 = 75
|
||||
SPARC_REG_L6 = 76
|
||||
SPARC_REG_L7 = 77
|
||||
SPARC_REG_O0 = 78
|
||||
SPARC_REG_O1 = 79
|
||||
SPARC_REG_O2 = 80
|
||||
SPARC_REG_O3 = 81
|
||||
SPARC_REG_O4 = 82
|
||||
SPARC_REG_O5 = 83
|
||||
SPARC_REG_O7 = 84
|
||||
SPARC_REG_SP = 85
|
||||
SPARC_REG_Y = 86
|
||||
SPARC_REG_XCC = 87
|
||||
SPARC_REG_PC = 88
|
||||
SPARC_REG_ENDING = 89
|
||||
SPARC_REG_O6 = SPARC_REG_SP
|
||||
SPARC_REG_I6 = SPARC_REG_FP
|
1589
bindings/python/unicorn/x86_const.py
Normal file
1589
bindings/python/unicorn/x86_const.py
Normal file
File diff suppressed because it is too large
Load diff
30
config.mk
Normal file
30
config.mk
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Unicorn Emulator Engine
|
||||
# By Nguyen Anh Quynh, 2015
|
||||
|
||||
# This file contains all customized compile options for Unicorn emulator.
|
||||
# Consult COMPILE.TXT & docs/README for more details.
|
||||
|
||||
################################################################################
|
||||
# Compile with debug info when you want to debug code.
|
||||
# Change this to 'no' for release edition.
|
||||
|
||||
UNICORN_DEBUG ?= yes
|
||||
|
||||
################################################################################
|
||||
# Specify which archs you want to compile in. By default, we build all archs.
|
||||
|
||||
UNICORN_ARCHS ?= x86 m68k arm aarch64 mips sparc
|
||||
|
||||
|
||||
################################################################################
|
||||
# Change 'UNICORN_STATIC = yes' to 'UNICORN_STATIC = no' to avoid building
|
||||
# a static library.
|
||||
|
||||
UNICORN_STATIC ?= yes
|
||||
|
||||
|
||||
################################################################################
|
||||
# Change 'UNICORN_SHARED = yes' to 'UNICORN_SHARED = no' to avoid building
|
||||
# a shared library.
|
||||
|
||||
UNICORN_SHARED ?= yes
|
BIN
docs/BHUSA2015-unicorn.pdf
Normal file
BIN
docs/BHUSA2015-unicorn.pdf
Normal file
Binary file not shown.
1
docs/README
Normal file
1
docs/README
Normal file
|
@ -0,0 +1 @@
|
|||
tutorials & docs come here.
|
BIN
docs/unicorn-logo.png
Normal file
BIN
docs/unicorn-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
274
hook.c
Normal file
274
hook.c
Normal file
|
@ -0,0 +1,274 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#include "uc_priv.h"
|
||||
#include "hook.h"
|
||||
|
||||
|
||||
// return index for a new hook entry in hook_callbacks[] array.
|
||||
// this realloc memory if needed.
|
||||
size_t hook_find_new(struct uc_struct *uc)
|
||||
{
|
||||
size_t i;
|
||||
struct hook_struct *new;
|
||||
|
||||
// find the first free slot. skip slot 0, so index > 0
|
||||
for(i = 1; i < uc->hook_size; i++) {
|
||||
if (uc->hook_callbacks[i].callback == NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// not found, so the array is full.
|
||||
// we have to realloc hook_callbacks[] to contain new hooks
|
||||
new = realloc(uc->hook_callbacks,
|
||||
(uc->hook_size + HOOK_SIZE) * sizeof(uc->hook_callbacks[0]));
|
||||
if (!new) // OOM ?
|
||||
return 0;
|
||||
|
||||
// reset the newly added slots
|
||||
memset(new + uc->hook_size * sizeof(uc->hook_callbacks[0]), 0,
|
||||
HOOK_SIZE * sizeof(uc->hook_callbacks[0]));
|
||||
|
||||
uc->hook_callbacks = new;
|
||||
uc->hook_size += HOOK_SIZE;
|
||||
|
||||
// return the first newly allocated slot
|
||||
return uc->hook_size - HOOK_SIZE;
|
||||
}
|
||||
|
||||
// return -1 on failure, index to hook_callbacks[] on success.
|
||||
size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data)
|
||||
{
|
||||
int i;
|
||||
struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle;
|
||||
|
||||
if (handle == 0)
|
||||
return -1;
|
||||
|
||||
// find the first free slot. skip slot 0, so index > 0
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].hook_type = type;
|
||||
uc->hook_callbacks[i].begin = begin;
|
||||
uc->hook_callbacks[i].end = end;
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
uc->hook_block = true;
|
||||
if (begin > end)
|
||||
uc->hook_block_idx = i;
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
uc->hook_insn = true;
|
||||
if (begin > end)
|
||||
uc->hook_insn_idx = i;
|
||||
break;
|
||||
case UC_MEM_READ:
|
||||
uc->hook_mem_read = true;
|
||||
if (begin > end)
|
||||
uc->hook_read_idx = i;
|
||||
break;
|
||||
case UC_MEM_WRITE:
|
||||
uc->hook_mem_write = true;
|
||||
if (begin > end)
|
||||
uc->hook_write_idx = i;
|
||||
break;
|
||||
case UC_MEM_READ_WRITE:
|
||||
uc->hook_mem_read = true;
|
||||
uc->hook_mem_write = true;
|
||||
if (begin > end) {
|
||||
uc->hook_read_idx = i;
|
||||
uc->hook_write_idx = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
uc_err hook_del(uch handle, uch *h2)
|
||||
{
|
||||
struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle;
|
||||
|
||||
if (handle == 0)
|
||||
return UC_ERR_UCH;
|
||||
|
||||
if (*h2 == uc->hook_block_idx) {
|
||||
uc->hook_block_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_insn_idx) {
|
||||
uc->hook_insn_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_read_idx) {
|
||||
uc->hook_read_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_write_idx) {
|
||||
uc->hook_write_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_mem_idx) {
|
||||
uc->hook_mem_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_intr_idx) {
|
||||
uc->hook_intr_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_out_idx) {
|
||||
uc->hook_out_idx = 0;
|
||||
}
|
||||
|
||||
if (*h2 == uc->hook_in_idx) {
|
||||
uc->hook_in_idx = 0;
|
||||
}
|
||||
|
||||
uc->hook_callbacks[*h2].callback = NULL;
|
||||
uc->hook_callbacks[*h2].user_data = NULL;
|
||||
uc->hook_callbacks[*h2].hook_type = 0;
|
||||
uc->hook_callbacks[*h2].begin = 0;
|
||||
uc->hook_callbacks[*h2].end = 0;
|
||||
|
||||
*h2 = 0;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
// return NULL on failure
|
||||
static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t address)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
// already hooked all blocks?
|
||||
if (uc->hook_block_idx)
|
||||
return &uc->hook_callbacks[uc->hook_block_idx];
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
// already hooked all the code?
|
||||
if (uc->hook_insn_idx)
|
||||
return &uc->hook_callbacks[uc->hook_insn_idx];
|
||||
break;
|
||||
case UC_MEM_READ:
|
||||
// already hooked all memory read?
|
||||
if (uc->hook_read_idx)
|
||||
return &uc->hook_callbacks[uc->hook_read_idx];
|
||||
break;
|
||||
case UC_MEM_WRITE:
|
||||
// already hooked all memory write?
|
||||
if (uc->hook_write_idx)
|
||||
return &uc->hook_callbacks[uc->hook_write_idx];
|
||||
break;
|
||||
}
|
||||
|
||||
// no trace-all callback
|
||||
for(i = 1; i < uc->hook_size; i++) {
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
case UC_HOOK_CODE:
|
||||
if (uc->hook_callbacks[i].hook_type == type) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
case UC_MEM_READ:
|
||||
if (uc->hook_callbacks[i].hook_type == UC_MEM_READ || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
case UC_MEM_WRITE:
|
||||
if (uc->hook_callbacks[i].hook_type == UC_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_MEM_READ_WRITE) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hook_count_cb(uch handle, uint64_t address, uint32_t size, void *user_data)
|
||||
{
|
||||
struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle;
|
||||
|
||||
// count this instruction
|
||||
uc->emu_counter++;
|
||||
|
||||
if (uc->emu_counter > uc->emu_count)
|
||||
uc_emu_stop(handle);
|
||||
else if (uc->hook_count_callback)
|
||||
uc->hook_count_callback(handle, address, size, user_data);
|
||||
}
|
||||
|
||||
struct hook_struct *hook_find(uch handle, int type, uint64_t address)
|
||||
{
|
||||
struct uc_struct *uc = (struct uc_struct *)(uintptr_t)handle;
|
||||
|
||||
if (handle == 0)
|
||||
return NULL;
|
||||
|
||||
// stop executing callbacks if we already got stop request
|
||||
if (uc->stop_request)
|
||||
return NULL;
|
||||
|
||||
// UC_HOOK_CODE is special because we may need to count instructions
|
||||
if (type == UC_HOOK_CODE && uc->emu_count > 0) {
|
||||
struct hook_struct *st = _hook_find(uc, type, address);
|
||||
if (st) {
|
||||
// prepare this struct to pass back to caller
|
||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
||||
uc->hook_count.begin = st->begin;
|
||||
uc->hook_count.end = st->end;
|
||||
uc->hook_count.callback = hook_count_cb;
|
||||
uc->hook_count.user_data = st->user_data;
|
||||
// save this hook callback so we can call it later
|
||||
uc->hook_count_callback = st->callback;
|
||||
} else {
|
||||
// there is no callback, but we still need to
|
||||
// handle instruction count
|
||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
||||
uc->hook_count.begin = 1;
|
||||
uc->hook_count.end = 0;
|
||||
uc->hook_count.callback = hook_count_cb;
|
||||
uc->hook_count.user_data = NULL;
|
||||
uc->hook_count_callback = NULL; // no callback
|
||||
}
|
||||
|
||||
return &(uc->hook_count);
|
||||
} else
|
||||
return _hook_find(uc, type, address);
|
||||
}
|
||||
|
||||
|
||||
// TCG helper
|
||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data);
|
||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data)
|
||||
{
|
||||
struct uc_struct *uc = handle;
|
||||
|
||||
// sync PC in CPUArchState with address
|
||||
if (uc->set_pc) {
|
||||
uc->set_pc(uc, address);
|
||||
}
|
||||
|
||||
((uc_cb_hookcode_t)callback)((uch)handle, address, size, user_data);
|
||||
}
|
||||
|
20
include/hook.h
Normal file
20
include/hook.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_HOOK_H
|
||||
#define UC_HOOK_H
|
||||
|
||||
// return -1 on failure, index to traces[] on success.
|
||||
size_t hook_add(uch handle, int type, uint64_t begin, uint64_t end, void *callback, void *user_data);
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
uc_err hook_del(uch handle, uch *traceh);
|
||||
|
||||
// return NULL on failure
|
||||
struct hook_struct *hook_find(uch handle, int type, uint64_t address);
|
||||
|
||||
// return index of an free hook entry in hook_callbacks[] array.
|
||||
// this realloc memory if needed.
|
||||
size_t hook_find_new(struct uc_struct *uc);
|
||||
|
||||
#endif
|
54
include/qemu.h
Normal file
54
include/qemu.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* By Dang Hoang Vu <dang.hvu -at- gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_QEMU_H
|
||||
#define UC_QEMU_H
|
||||
|
||||
struct uc_struct;
|
||||
|
||||
#define OPC_BUF_SIZE 640
|
||||
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "exec/cpu-common.h"
|
||||
#include "exec/memory.h"
|
||||
|
||||
#include "qemu/thread.h"
|
||||
#include "include/qom/cpu.h"
|
||||
#include "exec/spinlock.h"
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
// This two struct is originally from qemu/include/exec/cpu-all.h
|
||||
// Temporarily moved here since there is circular inclusion.
|
||||
typedef struct RAMBlock {
|
||||
struct MemoryRegion *mr;
|
||||
uint8_t *host;
|
||||
ram_addr_t offset;
|
||||
ram_addr_t length;
|
||||
uint32_t flags;
|
||||
char idstr[256];
|
||||
/* Reads can take either the iothread or the ramlist lock.
|
||||
* Writes must take both locks.
|
||||
*/
|
||||
QTAILQ_ENTRY(RAMBlock) next;
|
||||
int fd;
|
||||
} RAMBlock;
|
||||
|
||||
typedef struct {
|
||||
MemoryRegion *mr;
|
||||
void *buffer;
|
||||
hwaddr addr;
|
||||
hwaddr len;
|
||||
} BounceBuffer;
|
||||
|
||||
typedef struct RAMList {
|
||||
QemuMutex mutex;
|
||||
/* Protected by the iothread lock. */
|
||||
unsigned long *dirty_memory[DIRTY_MEMORY_NUM];
|
||||
RAMBlock *mru_block;
|
||||
/* Protected by the ramlist lock. */
|
||||
QTAILQ_HEAD(, RAMBlock) blocks;
|
||||
uint32_t version;
|
||||
} RAMList;
|
||||
|
||||
#endif
|
13
include/qemu_macro.h
Normal file
13
include/qemu_macro.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* By Dang Hoang Vu <dang.hvu -at- gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_QEMU_MACRO_H
|
||||
#define UC_QEMU_MACRO_H
|
||||
|
||||
#define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node)
|
||||
#define CPU_FOREACH(cpu) QTAILQ_FOREACH(cpu, &uc->cpus, node)
|
||||
#define CPU_FOREACH_SAFE(cpu, next_cpu) \
|
||||
QTAILQ_FOREACH_SAFE(cpu, &cpu->uc->cpus, node, next_cpu)
|
||||
#define first_cpu QTAILQ_FIRST(&uc->cpus)
|
||||
|
||||
#endif
|
||||
|
170
include/uc_priv.h
Normal file
170
include/uc_priv.h
Normal file
|
@ -0,0 +1,170 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_PRIV_H
|
||||
#define UC_PRIV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "qemu.h"
|
||||
#include "unicorn/unicorn.h"
|
||||
#include "hook.h"
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
QTAILQ_HEAD(CPUTailQ, CPUState);
|
||||
|
||||
typedef struct ModuleEntry {
|
||||
void (*init)(void);
|
||||
QTAILQ_ENTRY(ModuleEntry) node;
|
||||
module_init_type type;
|
||||
} ModuleEntry;
|
||||
|
||||
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
typedef int (*reg_access_t)(uch handle, unsigned int regid, void *value);
|
||||
|
||||
typedef void (*reg_reset_t)(uch handle);
|
||||
|
||||
typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf, int len);
|
||||
|
||||
typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf, int len);
|
||||
|
||||
typedef void (*uc_args_void_t)(void*);
|
||||
|
||||
typedef void (*uc_args_uc_t)(struct uc_struct*);
|
||||
|
||||
typedef bool (*uc_args_tcg_enable_t)(struct uc_struct*);
|
||||
|
||||
typedef void (*uc_minit_t)(struct uc_struct*, ram_addr_t);
|
||||
|
||||
typedef void (*uc_args_uc_long_t)(struct uc_struct*, unsigned long);
|
||||
|
||||
typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
|
||||
|
||||
typedef int (*uc_args_uc_ram_size_t)(struct uc_struct*, ram_addr_t begin, size_t size);
|
||||
|
||||
// which interrupt should make emulation stop?
|
||||
typedef bool (*uc_args_int_t)(int intno);
|
||||
|
||||
|
||||
struct hook_struct {
|
||||
int hook_type; // uc_tracecode_type & uc_tracemem_type
|
||||
uint64_t begin, end; // range of address to be monitored
|
||||
void *callback; // either uc_cb_tracecode_t or uc_cb_tracemem_t
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
// extend memory to keep 32 more hooks each time
|
||||
#define HOOK_SIZE 32
|
||||
|
||||
struct uc_struct {
|
||||
uc_arch arch;
|
||||
uc_mode mode;
|
||||
QemuMutex qemu_global_mutex; // qemu/cpus.c
|
||||
QemuCond qemu_cpu_cond; // qemu/cpus.c
|
||||
QemuThread *tcg_cpu_thread; // qemu/cpus.c
|
||||
QemuCond *tcg_halt_cond; // qemu/cpus.c
|
||||
struct CPUTailQ cpus; // qemu/cpu-exec.c
|
||||
uc_err errnum; // qemu/cpu-exec.c
|
||||
AddressSpace as;
|
||||
reg_access_t reg_read, reg_write;
|
||||
reg_reset_t reg_reset;
|
||||
|
||||
uc_write_mem_t write_mem;
|
||||
uc_read_mem_t read_mem;
|
||||
uc_args_void_t release; // release resource when uc_close()
|
||||
uc_args_uc_u64_t set_pc; // set PC for tracecode
|
||||
uc_args_int_t stop_interrupt; // check if the interrupt should stop emulation
|
||||
|
||||
uc_args_uc_t init_arch, pause_all_vcpus, vm_start, cpu_exec_init_all;
|
||||
uc_args_tcg_enable_t tcg_enabled;
|
||||
uc_args_uc_long_t tcg_exec_init;
|
||||
uc_args_uc_ram_size_t memory_map;
|
||||
// list of cpu
|
||||
void* cpu;
|
||||
|
||||
MemoryRegion *system_memory; // qemu/exec.c
|
||||
MemoryRegion *ram;
|
||||
MemoryRegion io_mem_rom; // qemu/exec.c
|
||||
MemoryRegion io_mem_notdirty; // qemu/exec.c
|
||||
MemoryRegion io_mem_unassigned; // qemu/exec.c
|
||||
MemoryRegion io_mem_watch; // qemu/exec.c
|
||||
RAMList ram_list; // qemu/exec.c
|
||||
CPUState *next_cpu; // qemu/cpus.c
|
||||
BounceBuffer bounce; // qemu/cpu-exec.c
|
||||
volatile sig_atomic_t exit_request; // qemu/cpu-exec.c
|
||||
spinlock_t x86_global_cpu_lock; // for X86 arch only
|
||||
bool global_dirty_log; // qemu/memory.c
|
||||
/* This is a multi-level map on the virtual address space.
|
||||
The bottom level has pointers to PageDesc. */
|
||||
void *l1_map; // qemu/translate-all.c
|
||||
size_t l1_map_size;
|
||||
/* code generation context */
|
||||
void *tcg_ctx; // for "TCGContext tcg_ctx" in qemu/translate-all.c
|
||||
/* memory.c */
|
||||
unsigned memory_region_transaction_depth;
|
||||
bool memory_region_update_pending;
|
||||
bool ioeventfd_update_pending;
|
||||
QemuMutex flat_view_mutex;
|
||||
QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners;
|
||||
QTAILQ_HEAD(, AddressSpace) address_spaces;
|
||||
// qom/object.c
|
||||
GHashTable *type_table;
|
||||
Type type_interface;
|
||||
Object *root;
|
||||
bool enumerating_types;
|
||||
// util/module.c
|
||||
ModuleTypeList init_type_list[MODULE_INIT_MAX];
|
||||
// hw/intc/apic_common.c
|
||||
DeviceState *vapic;
|
||||
int apic_no;
|
||||
bool mmio_registered;
|
||||
bool apic_report_tpr_access;
|
||||
CPUState *current_cpu;
|
||||
|
||||
// all the hook callbacks
|
||||
size_t hook_size;
|
||||
struct hook_struct *hook_callbacks;
|
||||
|
||||
// hook to count number of instructions for uc_emu_start()
|
||||
struct hook_struct hook_count;
|
||||
uc_cb_hookcode_t hook_count_callback;
|
||||
|
||||
size_t emu_counter; // current counter of uc_emu_start()
|
||||
size_t emu_count; // save counter of uc_emu_start()
|
||||
|
||||
// indexes if hooking ALL block/code/read/write events
|
||||
unsigned int hook_block_idx, hook_insn_idx, hook_read_idx, hook_write_idx;
|
||||
// boolean variables for quick check on hooking block, code, memory accesses
|
||||
bool hook_block, hook_insn, hook_mem_read, hook_mem_write;
|
||||
uint64_t block_addr; // save the last block address we hooked
|
||||
// indexes to event callbacks
|
||||
int hook_mem_idx; // for handling invalid memory access
|
||||
int hook_intr_idx; // for handling interrupt
|
||||
int hook_out_idx; // for handling OUT instruction (X86)
|
||||
int hook_in_idx; // for handling IN instruction (X86)
|
||||
|
||||
|
||||
bool init_tcg; // already initialized local TCGv variables?
|
||||
bool stop_request; // request to immediately stop emulation - for uc_emu_stop()
|
||||
bool emulation_done; // emulation is done by uc_emu_start()
|
||||
QemuThread timer; // timer for emulation timeout
|
||||
uint64_t timeout; // timeout for uc_emu_start()
|
||||
|
||||
uint64_t invalid_addr; // invalid address to be accessed
|
||||
int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE
|
||||
|
||||
uint64_t addr_end; // address where emulation stops (@end param of uc_emu_start())
|
||||
|
||||
int thumb; // thumb mode for ARM
|
||||
};
|
||||
|
||||
#include "qemu_macro.h"
|
||||
|
||||
// check if this address is mapped in (via uc_mem_map())
|
||||
bool memory_mapping(uint64_t address);
|
||||
|
||||
#endif
|
146
include/unicorn/arm.h
Normal file
146
include/unicorn/arm.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
#ifndef UNICORN_ARM_H
|
||||
#define UNICORN_ARM_H
|
||||
|
||||
/* Unicorn Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
//> ARM registers
|
||||
typedef enum arm_reg {
|
||||
ARM_REG_INVALID = 0,
|
||||
ARM_REG_APSR,
|
||||
ARM_REG_APSR_NZCV,
|
||||
ARM_REG_CPSR,
|
||||
ARM_REG_FPEXC,
|
||||
ARM_REG_FPINST,
|
||||
ARM_REG_FPSCR,
|
||||
ARM_REG_FPSCR_NZCV,
|
||||
ARM_REG_FPSID,
|
||||
ARM_REG_ITSTATE,
|
||||
ARM_REG_LR,
|
||||
ARM_REG_PC,
|
||||
ARM_REG_SP,
|
||||
ARM_REG_SPSR,
|
||||
ARM_REG_D0,
|
||||
ARM_REG_D1,
|
||||
ARM_REG_D2,
|
||||
ARM_REG_D3,
|
||||
ARM_REG_D4,
|
||||
ARM_REG_D5,
|
||||
ARM_REG_D6,
|
||||
ARM_REG_D7,
|
||||
ARM_REG_D8,
|
||||
ARM_REG_D9,
|
||||
ARM_REG_D10,
|
||||
ARM_REG_D11,
|
||||
ARM_REG_D12,
|
||||
ARM_REG_D13,
|
||||
ARM_REG_D14,
|
||||
ARM_REG_D15,
|
||||
ARM_REG_D16,
|
||||
ARM_REG_D17,
|
||||
ARM_REG_D18,
|
||||
ARM_REG_D19,
|
||||
ARM_REG_D20,
|
||||
ARM_REG_D21,
|
||||
ARM_REG_D22,
|
||||
ARM_REG_D23,
|
||||
ARM_REG_D24,
|
||||
ARM_REG_D25,
|
||||
ARM_REG_D26,
|
||||
ARM_REG_D27,
|
||||
ARM_REG_D28,
|
||||
ARM_REG_D29,
|
||||
ARM_REG_D30,
|
||||
ARM_REG_D31,
|
||||
ARM_REG_FPINST2,
|
||||
ARM_REG_MVFR0,
|
||||
ARM_REG_MVFR1,
|
||||
ARM_REG_MVFR2,
|
||||
ARM_REG_Q0,
|
||||
ARM_REG_Q1,
|
||||
ARM_REG_Q2,
|
||||
ARM_REG_Q3,
|
||||
ARM_REG_Q4,
|
||||
ARM_REG_Q5,
|
||||
ARM_REG_Q6,
|
||||
ARM_REG_Q7,
|
||||
ARM_REG_Q8,
|
||||
ARM_REG_Q9,
|
||||
ARM_REG_Q10,
|
||||
ARM_REG_Q11,
|
||||
ARM_REG_Q12,
|
||||
ARM_REG_Q13,
|
||||
ARM_REG_Q14,
|
||||
ARM_REG_Q15,
|
||||
ARM_REG_R0,
|
||||
ARM_REG_R1,
|
||||
ARM_REG_R2,
|
||||
ARM_REG_R3,
|
||||
ARM_REG_R4,
|
||||
ARM_REG_R5,
|
||||
ARM_REG_R6,
|
||||
ARM_REG_R7,
|
||||
ARM_REG_R8,
|
||||
ARM_REG_R9,
|
||||
ARM_REG_R10,
|
||||
ARM_REG_R11,
|
||||
ARM_REG_R12,
|
||||
ARM_REG_S0,
|
||||
ARM_REG_S1,
|
||||
ARM_REG_S2,
|
||||
ARM_REG_S3,
|
||||
ARM_REG_S4,
|
||||
ARM_REG_S5,
|
||||
ARM_REG_S6,
|
||||
ARM_REG_S7,
|
||||
ARM_REG_S8,
|
||||
ARM_REG_S9,
|
||||
ARM_REG_S10,
|
||||
ARM_REG_S11,
|
||||
ARM_REG_S12,
|
||||
ARM_REG_S13,
|
||||
ARM_REG_S14,
|
||||
ARM_REG_S15,
|
||||
ARM_REG_S16,
|
||||
ARM_REG_S17,
|
||||
ARM_REG_S18,
|
||||
ARM_REG_S19,
|
||||
ARM_REG_S20,
|
||||
ARM_REG_S21,
|
||||
ARM_REG_S22,
|
||||
ARM_REG_S23,
|
||||
ARM_REG_S24,
|
||||
ARM_REG_S25,
|
||||
ARM_REG_S26,
|
||||
ARM_REG_S27,
|
||||
ARM_REG_S28,
|
||||
ARM_REG_S29,
|
||||
ARM_REG_S30,
|
||||
ARM_REG_S31,
|
||||
|
||||
ARM_REG_ENDING, // <-- mark the end of the list or registers
|
||||
|
||||
//> alias registers
|
||||
ARM_REG_R13 = ARM_REG_SP,
|
||||
ARM_REG_R14 = ARM_REG_LR,
|
||||
ARM_REG_R15 = ARM_REG_PC,
|
||||
|
||||
ARM_REG_SB = ARM_REG_R9,
|
||||
ARM_REG_SL = ARM_REG_R10,
|
||||
ARM_REG_FP = ARM_REG_R11,
|
||||
ARM_REG_IP = ARM_REG_R12,
|
||||
} arm_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
297
include/unicorn/arm64.h
Normal file
297
include/unicorn/arm64.h
Normal file
|
@ -0,0 +1,297 @@
|
|||
#ifndef UNICORN_ARM64_H
|
||||
#define UNICORN_ARM64_H
|
||||
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
//> ARM64 registers
|
||||
typedef enum arm64_reg {
|
||||
ARM64_REG_INVALID = 0,
|
||||
|
||||
ARM64_REG_X29,
|
||||
ARM64_REG_X30,
|
||||
ARM64_REG_NZCV,
|
||||
ARM64_REG_SP,
|
||||
ARM64_REG_WSP,
|
||||
ARM64_REG_WZR,
|
||||
ARM64_REG_XZR,
|
||||
ARM64_REG_B0,
|
||||
ARM64_REG_B1,
|
||||
ARM64_REG_B2,
|
||||
ARM64_REG_B3,
|
||||
ARM64_REG_B4,
|
||||
ARM64_REG_B5,
|
||||
ARM64_REG_B6,
|
||||
ARM64_REG_B7,
|
||||
ARM64_REG_B8,
|
||||
ARM64_REG_B9,
|
||||
ARM64_REG_B10,
|
||||
ARM64_REG_B11,
|
||||
ARM64_REG_B12,
|
||||
ARM64_REG_B13,
|
||||
ARM64_REG_B14,
|
||||
ARM64_REG_B15,
|
||||
ARM64_REG_B16,
|
||||
ARM64_REG_B17,
|
||||
ARM64_REG_B18,
|
||||
ARM64_REG_B19,
|
||||
ARM64_REG_B20,
|
||||
ARM64_REG_B21,
|
||||
ARM64_REG_B22,
|
||||
ARM64_REG_B23,
|
||||
ARM64_REG_B24,
|
||||
ARM64_REG_B25,
|
||||
ARM64_REG_B26,
|
||||
ARM64_REG_B27,
|
||||
ARM64_REG_B28,
|
||||
ARM64_REG_B29,
|
||||
ARM64_REG_B30,
|
||||
ARM64_REG_B31,
|
||||
ARM64_REG_D0,
|
||||
ARM64_REG_D1,
|
||||
ARM64_REG_D2,
|
||||
ARM64_REG_D3,
|
||||
ARM64_REG_D4,
|
||||
ARM64_REG_D5,
|
||||
ARM64_REG_D6,
|
||||
ARM64_REG_D7,
|
||||
ARM64_REG_D8,
|
||||
ARM64_REG_D9,
|
||||
ARM64_REG_D10,
|
||||
ARM64_REG_D11,
|
||||
ARM64_REG_D12,
|
||||
ARM64_REG_D13,
|
||||
ARM64_REG_D14,
|
||||
ARM64_REG_D15,
|
||||
ARM64_REG_D16,
|
||||
ARM64_REG_D17,
|
||||
ARM64_REG_D18,
|
||||
ARM64_REG_D19,
|
||||
ARM64_REG_D20,
|
||||
ARM64_REG_D21,
|
||||
ARM64_REG_D22,
|
||||
ARM64_REG_D23,
|
||||
ARM64_REG_D24,
|
||||
ARM64_REG_D25,
|
||||
ARM64_REG_D26,
|
||||
ARM64_REG_D27,
|
||||
ARM64_REG_D28,
|
||||
ARM64_REG_D29,
|
||||
ARM64_REG_D30,
|
||||
ARM64_REG_D31,
|
||||
ARM64_REG_H0,
|
||||
ARM64_REG_H1,
|
||||
ARM64_REG_H2,
|
||||
ARM64_REG_H3,
|
||||
ARM64_REG_H4,
|
||||
ARM64_REG_H5,
|
||||
ARM64_REG_H6,
|
||||
ARM64_REG_H7,
|
||||
ARM64_REG_H8,
|
||||
ARM64_REG_H9,
|
||||
ARM64_REG_H10,
|
||||
ARM64_REG_H11,
|
||||
ARM64_REG_H12,
|
||||
ARM64_REG_H13,
|
||||
ARM64_REG_H14,
|
||||
ARM64_REG_H15,
|
||||
ARM64_REG_H16,
|
||||
ARM64_REG_H17,
|
||||
ARM64_REG_H18,
|
||||
ARM64_REG_H19,
|
||||
ARM64_REG_H20,
|
||||
ARM64_REG_H21,
|
||||
ARM64_REG_H22,
|
||||
ARM64_REG_H23,
|
||||
ARM64_REG_H24,
|
||||
ARM64_REG_H25,
|
||||
ARM64_REG_H26,
|
||||
ARM64_REG_H27,
|
||||
ARM64_REG_H28,
|
||||
ARM64_REG_H29,
|
||||
ARM64_REG_H30,
|
||||
ARM64_REG_H31,
|
||||
ARM64_REG_Q0,
|
||||
ARM64_REG_Q1,
|
||||
ARM64_REG_Q2,
|
||||
ARM64_REG_Q3,
|
||||
ARM64_REG_Q4,
|
||||
ARM64_REG_Q5,
|
||||
ARM64_REG_Q6,
|
||||
ARM64_REG_Q7,
|
||||
ARM64_REG_Q8,
|
||||
ARM64_REG_Q9,
|
||||
ARM64_REG_Q10,
|
||||
ARM64_REG_Q11,
|
||||
ARM64_REG_Q12,
|
||||
ARM64_REG_Q13,
|
||||
ARM64_REG_Q14,
|
||||
ARM64_REG_Q15,
|
||||
ARM64_REG_Q16,
|
||||
ARM64_REG_Q17,
|
||||
ARM64_REG_Q18,
|
||||
ARM64_REG_Q19,
|
||||
ARM64_REG_Q20,
|
||||
ARM64_REG_Q21,
|
||||
ARM64_REG_Q22,
|
||||
ARM64_REG_Q23,
|
||||
ARM64_REG_Q24,
|
||||
ARM64_REG_Q25,
|
||||
ARM64_REG_Q26,
|
||||
ARM64_REG_Q27,
|
||||
ARM64_REG_Q28,
|
||||
ARM64_REG_Q29,
|
||||
ARM64_REG_Q30,
|
||||
ARM64_REG_Q31,
|
||||
ARM64_REG_S0,
|
||||
ARM64_REG_S1,
|
||||
ARM64_REG_S2,
|
||||
ARM64_REG_S3,
|
||||
ARM64_REG_S4,
|
||||
ARM64_REG_S5,
|
||||
ARM64_REG_S6,
|
||||
ARM64_REG_S7,
|
||||
ARM64_REG_S8,
|
||||
ARM64_REG_S9,
|
||||
ARM64_REG_S10,
|
||||
ARM64_REG_S11,
|
||||
ARM64_REG_S12,
|
||||
ARM64_REG_S13,
|
||||
ARM64_REG_S14,
|
||||
ARM64_REG_S15,
|
||||
ARM64_REG_S16,
|
||||
ARM64_REG_S17,
|
||||
ARM64_REG_S18,
|
||||
ARM64_REG_S19,
|
||||
ARM64_REG_S20,
|
||||
ARM64_REG_S21,
|
||||
ARM64_REG_S22,
|
||||
ARM64_REG_S23,
|
||||
ARM64_REG_S24,
|
||||
ARM64_REG_S25,
|
||||
ARM64_REG_S26,
|
||||
ARM64_REG_S27,
|
||||
ARM64_REG_S28,
|
||||
ARM64_REG_S29,
|
||||
ARM64_REG_S30,
|
||||
ARM64_REG_S31,
|
||||
ARM64_REG_W0,
|
||||
ARM64_REG_W1,
|
||||
ARM64_REG_W2,
|
||||
ARM64_REG_W3,
|
||||
ARM64_REG_W4,
|
||||
ARM64_REG_W5,
|
||||
ARM64_REG_W6,
|
||||
ARM64_REG_W7,
|
||||
ARM64_REG_W8,
|
||||
ARM64_REG_W9,
|
||||
ARM64_REG_W10,
|
||||
ARM64_REG_W11,
|
||||
ARM64_REG_W12,
|
||||
ARM64_REG_W13,
|
||||
ARM64_REG_W14,
|
||||
ARM64_REG_W15,
|
||||
ARM64_REG_W16,
|
||||
ARM64_REG_W17,
|
||||
ARM64_REG_W18,
|
||||
ARM64_REG_W19,
|
||||
ARM64_REG_W20,
|
||||
ARM64_REG_W21,
|
||||
ARM64_REG_W22,
|
||||
ARM64_REG_W23,
|
||||
ARM64_REG_W24,
|
||||
ARM64_REG_W25,
|
||||
ARM64_REG_W26,
|
||||
ARM64_REG_W27,
|
||||
ARM64_REG_W28,
|
||||
ARM64_REG_W29,
|
||||
ARM64_REG_W30,
|
||||
ARM64_REG_X0,
|
||||
ARM64_REG_X1,
|
||||
ARM64_REG_X2,
|
||||
ARM64_REG_X3,
|
||||
ARM64_REG_X4,
|
||||
ARM64_REG_X5,
|
||||
ARM64_REG_X6,
|
||||
ARM64_REG_X7,
|
||||
ARM64_REG_X8,
|
||||
ARM64_REG_X9,
|
||||
ARM64_REG_X10,
|
||||
ARM64_REG_X11,
|
||||
ARM64_REG_X12,
|
||||
ARM64_REG_X13,
|
||||
ARM64_REG_X14,
|
||||
ARM64_REG_X15,
|
||||
ARM64_REG_X16,
|
||||
ARM64_REG_X17,
|
||||
ARM64_REG_X18,
|
||||
ARM64_REG_X19,
|
||||
ARM64_REG_X20,
|
||||
ARM64_REG_X21,
|
||||
ARM64_REG_X22,
|
||||
ARM64_REG_X23,
|
||||
ARM64_REG_X24,
|
||||
ARM64_REG_X25,
|
||||
ARM64_REG_X26,
|
||||
ARM64_REG_X27,
|
||||
ARM64_REG_X28,
|
||||
|
||||
ARM64_REG_V0,
|
||||
ARM64_REG_V1,
|
||||
ARM64_REG_V2,
|
||||
ARM64_REG_V3,
|
||||
ARM64_REG_V4,
|
||||
ARM64_REG_V5,
|
||||
ARM64_REG_V6,
|
||||
ARM64_REG_V7,
|
||||
ARM64_REG_V8,
|
||||
ARM64_REG_V9,
|
||||
ARM64_REG_V10,
|
||||
ARM64_REG_V11,
|
||||
ARM64_REG_V12,
|
||||
ARM64_REG_V13,
|
||||
ARM64_REG_V14,
|
||||
ARM64_REG_V15,
|
||||
ARM64_REG_V16,
|
||||
ARM64_REG_V17,
|
||||
ARM64_REG_V18,
|
||||
ARM64_REG_V19,
|
||||
ARM64_REG_V20,
|
||||
ARM64_REG_V21,
|
||||
ARM64_REG_V22,
|
||||
ARM64_REG_V23,
|
||||
ARM64_REG_V24,
|
||||
ARM64_REG_V25,
|
||||
ARM64_REG_V26,
|
||||
ARM64_REG_V27,
|
||||
ARM64_REG_V28,
|
||||
ARM64_REG_V29,
|
||||
ARM64_REG_V30,
|
||||
ARM64_REG_V31,
|
||||
|
||||
//> pseudo registers
|
||||
ARM64_REG_PC, // program counter register
|
||||
|
||||
ARM64_REG_ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
//> alias registers
|
||||
|
||||
ARM64_REG_IP1 = ARM64_REG_X16,
|
||||
ARM64_REG_IP0 = ARM64_REG_X17,
|
||||
ARM64_REG_FP = ARM64_REG_X29,
|
||||
ARM64_REG_LR = ARM64_REG_X30,
|
||||
} arm64_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
50
include/unicorn/m68k.h
Normal file
50
include/unicorn/m68k.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef UNICORN_M68K_H
|
||||
#define UNICORN_M68K_H
|
||||
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2015 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
//> M68K registers
|
||||
typedef enum m68k_reg {
|
||||
M68K_REG_INVALID = 0,
|
||||
|
||||
M68K_REG_A0,
|
||||
M68K_REG_A1,
|
||||
M68K_REG_A2,
|
||||
M68K_REG_A3,
|
||||
M68K_REG_A4,
|
||||
M68K_REG_A5,
|
||||
M68K_REG_A6,
|
||||
M68K_REG_A7,
|
||||
|
||||
M68K_REG_D0,
|
||||
M68K_REG_D1,
|
||||
M68K_REG_D2,
|
||||
M68K_REG_D3,
|
||||
M68K_REG_D4,
|
||||
M68K_REG_D5,
|
||||
M68K_REG_D6,
|
||||
M68K_REG_D7,
|
||||
|
||||
M68K_REG_SR,
|
||||
M68K_REG_PC,
|
||||
|
||||
M68K_REG_ENDING, // <-- mark the end of the list of registers
|
||||
} m68k_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
226
include/unicorn/mips.h
Normal file
226
include/unicorn/mips.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
#ifndef UNICORN_MIPS_H
|
||||
#define UNICORN_MIPS_H
|
||||
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// GCC MIPS toolchain has a default macro called "mips" which breaks
|
||||
// compilation
|
||||
#undef mips
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
//> MIPS registers
|
||||
typedef enum mips_reg {
|
||||
MIPS_REG_INVALID = 0,
|
||||
//> General purpose registers
|
||||
MIPS_REG_PC,
|
||||
|
||||
MIPS_REG_0,
|
||||
MIPS_REG_1,
|
||||
MIPS_REG_2,
|
||||
MIPS_REG_3,
|
||||
MIPS_REG_4,
|
||||
MIPS_REG_5,
|
||||
MIPS_REG_6,
|
||||
MIPS_REG_7,
|
||||
MIPS_REG_8,
|
||||
MIPS_REG_9,
|
||||
MIPS_REG_10,
|
||||
MIPS_REG_11,
|
||||
MIPS_REG_12,
|
||||
MIPS_REG_13,
|
||||
MIPS_REG_14,
|
||||
MIPS_REG_15,
|
||||
MIPS_REG_16,
|
||||
MIPS_REG_17,
|
||||
MIPS_REG_18,
|
||||
MIPS_REG_19,
|
||||
MIPS_REG_20,
|
||||
MIPS_REG_21,
|
||||
MIPS_REG_22,
|
||||
MIPS_REG_23,
|
||||
MIPS_REG_24,
|
||||
MIPS_REG_25,
|
||||
MIPS_REG_26,
|
||||
MIPS_REG_27,
|
||||
MIPS_REG_28,
|
||||
MIPS_REG_29,
|
||||
MIPS_REG_30,
|
||||
MIPS_REG_31,
|
||||
|
||||
//> DSP registers
|
||||
MIPS_REG_DSPCCOND,
|
||||
MIPS_REG_DSPCARRY,
|
||||
MIPS_REG_DSPEFI,
|
||||
MIPS_REG_DSPOUTFLAG,
|
||||
MIPS_REG_DSPOUTFLAG16_19,
|
||||
MIPS_REG_DSPOUTFLAG20,
|
||||
MIPS_REG_DSPOUTFLAG21,
|
||||
MIPS_REG_DSPOUTFLAG22,
|
||||
MIPS_REG_DSPOUTFLAG23,
|
||||
MIPS_REG_DSPPOS,
|
||||
MIPS_REG_DSPSCOUNT,
|
||||
|
||||
//> ACC registers
|
||||
MIPS_REG_AC0,
|
||||
MIPS_REG_AC1,
|
||||
MIPS_REG_AC2,
|
||||
MIPS_REG_AC3,
|
||||
|
||||
//> COP registers
|
||||
MIPS_REG_CC0,
|
||||
MIPS_REG_CC1,
|
||||
MIPS_REG_CC2,
|
||||
MIPS_REG_CC3,
|
||||
MIPS_REG_CC4,
|
||||
MIPS_REG_CC5,
|
||||
MIPS_REG_CC6,
|
||||
MIPS_REG_CC7,
|
||||
|
||||
//> FPU registers
|
||||
MIPS_REG_F0,
|
||||
MIPS_REG_F1,
|
||||
MIPS_REG_F2,
|
||||
MIPS_REG_F3,
|
||||
MIPS_REG_F4,
|
||||
MIPS_REG_F5,
|
||||
MIPS_REG_F6,
|
||||
MIPS_REG_F7,
|
||||
MIPS_REG_F8,
|
||||
MIPS_REG_F9,
|
||||
MIPS_REG_F10,
|
||||
MIPS_REG_F11,
|
||||
MIPS_REG_F12,
|
||||
MIPS_REG_F13,
|
||||
MIPS_REG_F14,
|
||||
MIPS_REG_F15,
|
||||
MIPS_REG_F16,
|
||||
MIPS_REG_F17,
|
||||
MIPS_REG_F18,
|
||||
MIPS_REG_F19,
|
||||
MIPS_REG_F20,
|
||||
MIPS_REG_F21,
|
||||
MIPS_REG_F22,
|
||||
MIPS_REG_F23,
|
||||
MIPS_REG_F24,
|
||||
MIPS_REG_F25,
|
||||
MIPS_REG_F26,
|
||||
MIPS_REG_F27,
|
||||
MIPS_REG_F28,
|
||||
MIPS_REG_F29,
|
||||
MIPS_REG_F30,
|
||||
MIPS_REG_F31,
|
||||
|
||||
MIPS_REG_FCC0,
|
||||
MIPS_REG_FCC1,
|
||||
MIPS_REG_FCC2,
|
||||
MIPS_REG_FCC3,
|
||||
MIPS_REG_FCC4,
|
||||
MIPS_REG_FCC5,
|
||||
MIPS_REG_FCC6,
|
||||
MIPS_REG_FCC7,
|
||||
|
||||
//> AFPR128
|
||||
MIPS_REG_W0,
|
||||
MIPS_REG_W1,
|
||||
MIPS_REG_W2,
|
||||
MIPS_REG_W3,
|
||||
MIPS_REG_W4,
|
||||
MIPS_REG_W5,
|
||||
MIPS_REG_W6,
|
||||
MIPS_REG_W7,
|
||||
MIPS_REG_W8,
|
||||
MIPS_REG_W9,
|
||||
MIPS_REG_W10,
|
||||
MIPS_REG_W11,
|
||||
MIPS_REG_W12,
|
||||
MIPS_REG_W13,
|
||||
MIPS_REG_W14,
|
||||
MIPS_REG_W15,
|
||||
MIPS_REG_W16,
|
||||
MIPS_REG_W17,
|
||||
MIPS_REG_W18,
|
||||
MIPS_REG_W19,
|
||||
MIPS_REG_W20,
|
||||
MIPS_REG_W21,
|
||||
MIPS_REG_W22,
|
||||
MIPS_REG_W23,
|
||||
MIPS_REG_W24,
|
||||
MIPS_REG_W25,
|
||||
MIPS_REG_W26,
|
||||
MIPS_REG_W27,
|
||||
MIPS_REG_W28,
|
||||
MIPS_REG_W29,
|
||||
MIPS_REG_W30,
|
||||
MIPS_REG_W31,
|
||||
|
||||
MIPS_REG_HI,
|
||||
MIPS_REG_LO,
|
||||
|
||||
MIPS_REG_P0,
|
||||
MIPS_REG_P1,
|
||||
MIPS_REG_P2,
|
||||
|
||||
MIPS_REG_MPL0,
|
||||
MIPS_REG_MPL1,
|
||||
MIPS_REG_MPL2,
|
||||
|
||||
MIPS_REG_ENDING, // <-- mark the end of the list or registers
|
||||
|
||||
// alias registers
|
||||
MIPS_REG_ZERO = MIPS_REG_0,
|
||||
MIPS_REG_AT = MIPS_REG_1,
|
||||
MIPS_REG_V0 = MIPS_REG_2,
|
||||
MIPS_REG_V1 = MIPS_REG_3,
|
||||
MIPS_REG_A0 = MIPS_REG_4,
|
||||
MIPS_REG_A1 = MIPS_REG_5,
|
||||
MIPS_REG_A2 = MIPS_REG_6,
|
||||
MIPS_REG_A3 = MIPS_REG_7,
|
||||
MIPS_REG_T0 = MIPS_REG_8,
|
||||
MIPS_REG_T1 = MIPS_REG_9,
|
||||
MIPS_REG_T2 = MIPS_REG_10,
|
||||
MIPS_REG_T3 = MIPS_REG_11,
|
||||
MIPS_REG_T4 = MIPS_REG_12,
|
||||
MIPS_REG_T5 = MIPS_REG_13,
|
||||
MIPS_REG_T6 = MIPS_REG_14,
|
||||
MIPS_REG_T7 = MIPS_REG_15,
|
||||
MIPS_REG_S0 = MIPS_REG_16,
|
||||
MIPS_REG_S1 = MIPS_REG_17,
|
||||
MIPS_REG_S2 = MIPS_REG_18,
|
||||
MIPS_REG_S3 = MIPS_REG_19,
|
||||
MIPS_REG_S4 = MIPS_REG_20,
|
||||
MIPS_REG_S5 = MIPS_REG_21,
|
||||
MIPS_REG_S6 = MIPS_REG_22,
|
||||
MIPS_REG_S7 = MIPS_REG_23,
|
||||
MIPS_REG_T8 = MIPS_REG_24,
|
||||
MIPS_REG_T9 = MIPS_REG_25,
|
||||
MIPS_REG_K0 = MIPS_REG_26,
|
||||
MIPS_REG_K1 = MIPS_REG_27,
|
||||
MIPS_REG_GP = MIPS_REG_28,
|
||||
MIPS_REG_SP = MIPS_REG_29,
|
||||
MIPS_REG_FP = MIPS_REG_30, MIPS_REG_S8 = MIPS_REG_30,
|
||||
MIPS_REG_RA = MIPS_REG_31,
|
||||
|
||||
MIPS_REG_HI0 = MIPS_REG_AC0,
|
||||
MIPS_REG_HI1 = MIPS_REG_AC1,
|
||||
MIPS_REG_HI2 = MIPS_REG_AC2,
|
||||
MIPS_REG_HI3 = MIPS_REG_AC3,
|
||||
|
||||
MIPS_REG_LO0 = MIPS_REG_HI0,
|
||||
MIPS_REG_LO1 = MIPS_REG_HI1,
|
||||
MIPS_REG_LO2 = MIPS_REG_HI2,
|
||||
MIPS_REG_LO3 = MIPS_REG_HI3,
|
||||
} mips_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
28
include/unicorn/platform.h
Normal file
28
include/unicorn/platform.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Axel Souchet & Nguyen Anh Quynh, 2014 */
|
||||
|
||||
// handle C99 issue (for pre-2013 VisualStudio)
|
||||
#ifndef UNICORN_PLATFORM_H
|
||||
#define UNICORN_PLATFORM_H
|
||||
|
||||
#if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
|
||||
// MSVC
|
||||
|
||||
// stdbool.h
|
||||
#if (_MSC_VER < 1800)
|
||||
#ifndef __cplusplus
|
||||
typedef unsigned char bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
#else
|
||||
// VisualStudio 2013+ -> C99 is supported
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#else // not MSVC -> C99 is supported
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#endif
|
130
include/unicorn/sparc.h
Normal file
130
include/unicorn/sparc.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
#ifndef UNICORN_SPARC_H
|
||||
#define UNICORN_SPARC_H
|
||||
|
||||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2015 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
|
||||
// GCC SPARC toolchain has a default macro called "sparc" which breaks
|
||||
// compilation
|
||||
#undef sparc
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#endif
|
||||
|
||||
//> SPARC registers
|
||||
typedef enum sparc_reg {
|
||||
SPARC_REG_INVALID = 0,
|
||||
|
||||
SPARC_REG_F0,
|
||||
SPARC_REG_F1,
|
||||
SPARC_REG_F2,
|
||||
SPARC_REG_F3,
|
||||
SPARC_REG_F4,
|
||||
SPARC_REG_F5,
|
||||
SPARC_REG_F6,
|
||||
SPARC_REG_F7,
|
||||
SPARC_REG_F8,
|
||||
SPARC_REG_F9,
|
||||
SPARC_REG_F10,
|
||||
SPARC_REG_F11,
|
||||
SPARC_REG_F12,
|
||||
SPARC_REG_F13,
|
||||
SPARC_REG_F14,
|
||||
SPARC_REG_F15,
|
||||
SPARC_REG_F16,
|
||||
SPARC_REG_F17,
|
||||
SPARC_REG_F18,
|
||||
SPARC_REG_F19,
|
||||
SPARC_REG_F20,
|
||||
SPARC_REG_F21,
|
||||
SPARC_REG_F22,
|
||||
SPARC_REG_F23,
|
||||
SPARC_REG_F24,
|
||||
SPARC_REG_F25,
|
||||
SPARC_REG_F26,
|
||||
SPARC_REG_F27,
|
||||
SPARC_REG_F28,
|
||||
SPARC_REG_F29,
|
||||
SPARC_REG_F30,
|
||||
SPARC_REG_F31,
|
||||
SPARC_REG_F32,
|
||||
SPARC_REG_F34,
|
||||
SPARC_REG_F36,
|
||||
SPARC_REG_F38,
|
||||
SPARC_REG_F40,
|
||||
SPARC_REG_F42,
|
||||
SPARC_REG_F44,
|
||||
SPARC_REG_F46,
|
||||
SPARC_REG_F48,
|
||||
SPARC_REG_F50,
|
||||
SPARC_REG_F52,
|
||||
SPARC_REG_F54,
|
||||
SPARC_REG_F56,
|
||||
SPARC_REG_F58,
|
||||
SPARC_REG_F60,
|
||||
SPARC_REG_F62,
|
||||
SPARC_REG_FCC0, // Floating condition codes
|
||||
SPARC_REG_FCC1,
|
||||
SPARC_REG_FCC2,
|
||||
SPARC_REG_FCC3,
|
||||
SPARC_REG_FP,
|
||||
SPARC_REG_G0,
|
||||
SPARC_REG_G1,
|
||||
SPARC_REG_G2,
|
||||
SPARC_REG_G3,
|
||||
SPARC_REG_G4,
|
||||
SPARC_REG_G5,
|
||||
SPARC_REG_G6,
|
||||
SPARC_REG_G7,
|
||||
SPARC_REG_I0,
|
||||
SPARC_REG_I1,
|
||||
SPARC_REG_I2,
|
||||
SPARC_REG_I3,
|
||||
SPARC_REG_I4,
|
||||
SPARC_REG_I5,
|
||||
SPARC_REG_I7,
|
||||
SPARC_REG_ICC, // Integer condition codes
|
||||
SPARC_REG_L0,
|
||||
SPARC_REG_L1,
|
||||
SPARC_REG_L2,
|
||||
SPARC_REG_L3,
|
||||
SPARC_REG_L4,
|
||||
SPARC_REG_L5,
|
||||
SPARC_REG_L6,
|
||||
SPARC_REG_L7,
|
||||
SPARC_REG_O0,
|
||||
SPARC_REG_O1,
|
||||
SPARC_REG_O2,
|
||||
SPARC_REG_O3,
|
||||
SPARC_REG_O4,
|
||||
SPARC_REG_O5,
|
||||
SPARC_REG_O7,
|
||||
SPARC_REG_SP,
|
||||
SPARC_REG_Y,
|
||||
|
||||
// special register
|
||||
SPARC_REG_XCC,
|
||||
|
||||
// pseudo register
|
||||
SPARC_REG_PC, // program counter register
|
||||
|
||||
SPARC_REG_ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
// extras
|
||||
SPARC_REG_O6 = SPARC_REG_SP,
|
||||
SPARC_REG_I6 = SPARC_REG_FP,
|
||||
} sparc_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
408
include/unicorn/unicorn.h
Normal file
408
include/unicorn/unicorn.h
Normal file
|
@ -0,0 +1,408 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UNICORN_ENGINE_H
|
||||
#define UNICORN_ENGINE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#if defined(UNICORN_HAS_OSXKERNEL)
|
||||
#include <libkern/libkern.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "m68k.h"
|
||||
#include "x86.h"
|
||||
#include "arm.h"
|
||||
#include "arm64.h"
|
||||
#include "mips.h"
|
||||
#include "sparc.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable:4100)
|
||||
#ifdef UNICORN_SHARED
|
||||
#define UNICORN_EXPORT __declspec(dllexport)
|
||||
#else // defined(UNICORN_STATIC)
|
||||
#define UNICORN_EXPORT
|
||||
#endif
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
#define UNICORN_EXPORT __attribute__((visibility("default")))
|
||||
#else
|
||||
#define UNICORN_EXPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UNICORN_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define UNICORN_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#pragma message("WARNING: You need to implement UNICORN_DEPRECATED for this compiler")
|
||||
#define UNICORN_DEPRECATED
|
||||
#endif
|
||||
|
||||
// Unicorn API version
|
||||
#define UC_API_MAJOR 0
|
||||
#define UC_API_MINOR 9
|
||||
|
||||
// Macro to create combined version which can be compared to
|
||||
// result of uc_version() API.
|
||||
#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor)
|
||||
|
||||
// Scales to calculate timeout on microsecond unit
|
||||
// 1 second = 1000,000 microseconds
|
||||
#define UC_SECOND_SCALE 1000000
|
||||
// 1 milisecond = 1000 nanoseconds
|
||||
#define UC_MILISECOND_SCALE 1000
|
||||
|
||||
// Handle using with all API
|
||||
typedef size_t uch;
|
||||
|
||||
// Architecture type
|
||||
typedef enum uc_arch {
|
||||
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
|
||||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||
UC_ARCH_MIPS, // Mips architecture
|
||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||
UC_ARCH_PPC, // PowerPC architecture
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_MAX,
|
||||
UC_ARCH_ALL = 0xFFFF, // All architectures - for uc_support()
|
||||
} uc_arch;
|
||||
|
||||
// Mode type
|
||||
typedef enum uc_mode {
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_ARM = 0, // 32-bit ARM
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode (X86)
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode (X86)
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC)
|
||||
UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
|
||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (PPC)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 31, // big-endian mode
|
||||
UC_MODE_MIPS32 = UC_MODE_32, // Mips32 ISA (Mips)
|
||||
UC_MODE_MIPS64 = UC_MODE_64, // Mips64 ISA (Mips)
|
||||
} uc_mode;
|
||||
|
||||
// All type of errors encountered by Unicorn API.
|
||||
// These are values returned by uc_errno()
|
||||
typedef enum uc_err {
|
||||
UC_ERR_OK = 0, // No error: everything was fine
|
||||
UC_ERR_OOM, // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
UC_ERR_ARCH, // Unsupported architecture: uc_open()
|
||||
UC_ERR_HANDLE, // Invalid handle
|
||||
UC_ERR_UCH, // Invalid handle (uch)
|
||||
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||
UC_ERR_MEM_READ, // Quit emulation due to invalid memory READ: uc_emu_start()
|
||||
UC_ERR_MEM_WRITE, // Quit emulation due to invalid memory WRITE: uc_emu_start()
|
||||
UC_ERR_CODE_INVALID, // Quit emulation due to invalid code address: uc_emu_start()
|
||||
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
|
||||
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
|
||||
} uc_err;
|
||||
|
||||
|
||||
// Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
||||
// @address: address where the code is being executed
|
||||
// @size: size of machine instruction being executed
|
||||
// @user_data: user data passed to tracing APIs.
|
||||
typedef void (*uc_cb_hookcode_t)(uch handle, uint64_t address, uint32_t size, void *user_data);
|
||||
|
||||
// Callback function for tracing interrupts (for uc_hook_intr())
|
||||
// @intno: interrupt number
|
||||
// @user_data: user data passed to tracing APIs.
|
||||
typedef void (*uc_cb_hookintr_t)(uch handle, uint32_t intno, void *user_data);
|
||||
|
||||
// Callback function for tracing IN instruction of X86
|
||||
// @port: port number
|
||||
// @size: data size (1/2/4) to be read from this port
|
||||
// @user_data: user data passed to tracing APIs.
|
||||
typedef uint32_t (*uc_cb_insn_in_t)(uch handle, uint32_t port, int size, void *user_data);
|
||||
|
||||
// x86's handler for OUT
|
||||
// @port: port number
|
||||
// @size: data size (1/2/4) to be written to this port
|
||||
// @value: data value to be written to this port
|
||||
typedef void (*uc_cb_insn_out_t)(uch handle, uint32_t port, int size, uint32_t value, void *user_data);
|
||||
|
||||
// All type of memory accesses for UC_HOOK_MEM_*
|
||||
typedef enum uc_mem_type {
|
||||
UC_MEM_READ = 16, // Memory is read from
|
||||
UC_MEM_WRITE, // Memory is written to
|
||||
UC_MEM_READ_WRITE, // Memory is accessed (either READ or WRITE)
|
||||
} uc_mem_type;
|
||||
|
||||
// All type of hooks for uc_hook_add() API.
|
||||
typedef enum uc_hook_t {
|
||||
UC_HOOK_INTR = 32, // Hook all interrupt events
|
||||
UC_HOOK_INSN, // Hook a particular instruction
|
||||
UC_HOOK_CODE, // Hook a range of code
|
||||
UC_HOOK_BLOCK, // Hook basic blocks
|
||||
UC_HOOK_MEM_INVALID, // Hook for all invalid memory access events
|
||||
UC_HOOK_MEM_READ, // Hook all memory read events.
|
||||
UC_HOOK_MEM_WRITE, // Hook all memory write events.
|
||||
UC_HOOK_MEM_READ_WRITE, // Hook all memory accesses (either READ or WRITE).
|
||||
} uc_hook_t;
|
||||
|
||||
// Callback function for hooking memory (UC_HOOK_MEM_*)
|
||||
// @type: this memory is being READ, or WRITE
|
||||
// @address: address where the code is being executed
|
||||
// @size: size of data being read or written
|
||||
// @value: value of data being written to memory, or irrelevant if type = READ.
|
||||
// @user_data: user data passed to tracing APIs
|
||||
typedef void (*uc_cb_hookmem_t)(uch handle, uc_mem_type type,
|
||||
uint64_t address, int size, int64_t value, void *user_data);
|
||||
|
||||
// Callback function for handling memory events (for UC_HOOK_MEM_INVALID)
|
||||
// @type: this memory is being READ, or WRITE
|
||||
// @address: address where the code is being executed
|
||||
// @size: size of data being read or written
|
||||
// @value: value of data being written to memory, or irrelevant if type = READ.
|
||||
// @user_data: user data passed to tracing APIs
|
||||
// @return: return true to continue, or false to stop program (due to invalid memory).
|
||||
typedef bool (*uc_cb_eventmem_t)(uch handle, uc_mem_type type,
|
||||
uint64_t address, int size, int64_t value, void *user_data);
|
||||
|
||||
|
||||
/*
|
||||
Return combined API version & major and minor version numbers.
|
||||
|
||||
@major: major number of API version
|
||||
@minor: minor number of API version
|
||||
|
||||
@return hexical number as (major << 8 | minor), which encodes both
|
||||
major & minor versions.
|
||||
NOTE: This returned value can be compared with version number made
|
||||
with macro UC_MAKE_VERSION
|
||||
|
||||
For example, second API version would return 1 in @major, and 1 in @minor
|
||||
The return value would be 0x0101
|
||||
|
||||
NOTE: if you only care about returned value, but not major and minor values,
|
||||
set both @major & @minor arguments to NULL.
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
unsigned int uc_version(unsigned int *major, unsigned int *minor);
|
||||
|
||||
|
||||
/*
|
||||
This API can be used to either ask for archs supported by this library.
|
||||
|
||||
To check if a particular arch is supported by this library, set @query to
|
||||
arch mode (UC_ARCH_* value).
|
||||
To verify if this library supports all the archs, use UC_ARCH_ALL.
|
||||
|
||||
@return True if this library supports the given arch.
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
bool uc_support(int query);
|
||||
|
||||
|
||||
/*
|
||||
Initialize UC handle: this must be done before any usage of UC.
|
||||
|
||||
@arch: architecture type (UC_ARCH_*)
|
||||
@mode: hardware mode. This is combined of UC_MODE_*
|
||||
@handle: pointer to handle, which will be updated at return time
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_open(uc_arch arch, uc_mode mode, uch *handle);
|
||||
|
||||
/*
|
||||
Close UC handle: MUST do to release the handle when it is not used anymore.
|
||||
NOTE: this must be called only when there is no longer usage of Unicorn.
|
||||
The reason is the this API releases some cached memory, thus access to any
|
||||
Unicorn API after uc_close() might crash your application.
|
||||
After this, @handle is invalid, and nolonger usable.
|
||||
|
||||
@handle: pointer to a handle returned by uc_open()
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_close(uch *handle);
|
||||
|
||||
/*
|
||||
Report the last error number when some API function fail.
|
||||
Like glibc's errno, uc_errno might not retain its old value once accessed.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
|
||||
@return: error code of uc_err enum type (UC_ERR_*, see above)
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_errno(uch handle);
|
||||
|
||||
/*
|
||||
Return a string describing given error code.
|
||||
|
||||
@code: error code (see UC_ERR_* above)
|
||||
|
||||
@return: returns a pointer to a string that describes the error code
|
||||
passed in the argument @code
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
const char *uc_strerror(uc_err code);
|
||||
|
||||
/*
|
||||
Write to register.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@regid: register ID that is to be modified.
|
||||
@value: pointer to the value that will set to register @regid
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_reg_write(uch handle, int regid, void *value);
|
||||
|
||||
/*
|
||||
Read register value.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@regid: register ID that is to be retrieved.
|
||||
@value: pointer to a variable storing the register value.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_reg_read(uch handle, int regid, void *value);
|
||||
|
||||
/*
|
||||
Write to a range of bytes in memory.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@address: starting memory address of bytes to set.
|
||||
@bytes: pointer to a variable containing data to be written to memory.
|
||||
@size: size of memory to write to.
|
||||
|
||||
NOTE: @bytes must be big enough to contain @size bytes.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_write(uch handle, uint64_t address, uint8_t *bytes, size_t size);
|
||||
|
||||
/*
|
||||
Read a range of bytes in memory.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@address: starting memory address of bytes to get.
|
||||
@bytes: pointer to a variable containing data copied from memory.
|
||||
@size: size of memory to read.
|
||||
|
||||
NOTE: @bytes must be big enough to contain @size bytes.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_read(uch handle, uint64_t address, uint8_t *bytes, size_t size);
|
||||
|
||||
/*
|
||||
Emulate machine code in a specific duration of time.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@begin: address where emulation starts
|
||||
@until: address where emulation stops (i.e when this address is hit)
|
||||
@timeout: duration to emulate the code (in microseconds). When this value is 0,
|
||||
we will emulate the code in infinite time, until the code is finished.
|
||||
@count: the number of instructions to be emulated. When this value is 0,
|
||||
we will emulate all the code available, until the code is finished.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
|
||||
/*
|
||||
Stop emulation (which was started by uc_emu_start() API.
|
||||
This is typically called from callback functions registered via tracing APIs.
|
||||
NOTE: for now, this will stop the execution only after the current block.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_stop(uch handle);
|
||||
|
||||
/*
|
||||
Register callback for a hook event.
|
||||
The callback will be run when the hook event is hit.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@h2: hook handle returned from this registration. To be used in uc_hook_del() API
|
||||
@type: hook type
|
||||
@callback: callback to be run when instruction is hit
|
||||
@user_data: user-defined data. This will be passed to callback function in its
|
||||
last argument @user_data
|
||||
@...: variable arguments (depending on @type)
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_add(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, ...);
|
||||
|
||||
/*
|
||||
Unregister (remove) a hook callback.
|
||||
This API removes the hook callback registered by uc_hook_add().
|
||||
NOTE: this should be called only when you no longer want to trace.
|
||||
After this, @hhandle is invalid, and nolonger usable.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@h2: handle returned by uc_hook_add()
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_del(uch handle, uch *h2);
|
||||
|
||||
/*
|
||||
Map memory in for emulation.
|
||||
This API adds a memory region that can be used by emulation.
|
||||
|
||||
@handle: handle returned by uc_open()
|
||||
@address: starting address of the new memory region to be mapped in.
|
||||
@size: size of the new memory region to be mapped in. This will be round up to
|
||||
the next 8KB boundary.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_map(uch handle, uint64_t address, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
1416
include/unicorn/x86.h
Normal file
1416
include/unicorn/x86.h
Normal file
File diff suppressed because it is too large
Load diff
108
make.sh
Executable file
108
make.sh
Executable file
|
@ -0,0 +1,108 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Unicorn Engine
|
||||
# By Nguyen Anh Quynh <aquynh@gmail.com>, 2015
|
||||
|
||||
# Note: to cross-compile to Windows on Linux, Mingw-glib2 is required.
|
||||
# See README on how to install Mingw-glib2.
|
||||
|
||||
MAKE_JOBS=$((${MAKE_JOBS}+0))
|
||||
[ ${MAKE_JOBS} -lt 1 ] && \
|
||||
MAKE_JOBS=4
|
||||
|
||||
# build iOS lib for all iDevices, or only specific device
|
||||
build_iOS() {
|
||||
IOS_SDK=`xcrun --sdk iphoneos --show-sdk-path`
|
||||
IOS_CC=`xcrun --sdk iphoneos -f clang`
|
||||
IOS_CFLAGS="-Os -Wimplicit -isysroot $IOS_SDK"
|
||||
IOS_LDFLAGS="-isysroot $IOS_SDK"
|
||||
if [ -z "$1" ]; then
|
||||
# build for all iDevices
|
||||
IOS_ARCHS="armv7 armv7s arm64"
|
||||
else
|
||||
IOS_ARCHS="$1"
|
||||
fi
|
||||
CC="$IOS_CC" \
|
||||
CFLAGS="$IOS_CFLAGS" \
|
||||
LDFLAGS="$IOS_LDFLAGS" \
|
||||
LIBARCHS="$IOS_ARCHS" \
|
||||
${MAKE}
|
||||
}
|
||||
|
||||
build() {
|
||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
||||
${MAKE}
|
||||
}
|
||||
|
||||
build_cross() {
|
||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
||||
CROSS=$1
|
||||
CC=$CROSS-gcc \
|
||||
AR=$CROSS-ar \
|
||||
RANLIB=$CROSS-ranlib \
|
||||
GLIB="-L/usr/$CROSS/lib/ -lglib-2.0" \
|
||||
${MAKE}
|
||||
}
|
||||
|
||||
install() {
|
||||
# Mac OSX needs to find the right directory for pkgconfig
|
||||
if [ "$UNAME" = Darwin ]; then
|
||||
# we are going to install into /usr/local, so remove old installs under /usr
|
||||
rm -rf /usr/lib/libunicorn*
|
||||
rm -rf /usr/include/unicorn
|
||||
# install into /usr/local
|
||||
PREFIX=/usr/local
|
||||
${MAKE} install
|
||||
else # not OSX
|
||||
test -d /usr/lib64 && ${MAKE} LIBDIRARCH=lib64
|
||||
${MAKE} install
|
||||
fi
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
# Mac OSX needs to find the right directory for pkgconfig
|
||||
if [ "$UNAME" = "Darwin" ]; then
|
||||
# find the directory automatically, so we can support both Macport & Brew
|
||||
PKGCFGDIR="$(pkg-config --variable pc_path pkg-config | cut -d ':' -f 1)"
|
||||
PREFIX=/usr/local
|
||||
${MAKE} uninstall
|
||||
else # not OSX
|
||||
test -d /usr/lib64 && LIBDIRARCH=lib64
|
||||
${MAKE} uninstall
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "$UNAME" = SunOS ]; then
|
||||
[ -z "${MAKE}" ] && MAKE=gmake
|
||||
INSTALL_BIN=ginstall
|
||||
CC=gcc
|
||||
fi
|
||||
|
||||
if [ -n "`echo "$UNAME" | grep BSD`" ]; then
|
||||
MAKE=gmake
|
||||
PREFIX=/usr/local
|
||||
fi
|
||||
|
||||
[ -z "${UNAME}" ] && UNAME=$(uname)
|
||||
[ -z "${MAKE}" ] && MAKE=make
|
||||
#[ -n "${MAKE_JOBS}" ] && MAKE="$MAKE -j${MAKE_JOBS}"
|
||||
export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS
|
||||
|
||||
case "$1" in
|
||||
"" ) build;;
|
||||
"default" ) build;;
|
||||
"install" ) install;;
|
||||
"uninstall" ) uninstall;;
|
||||
"cross-win32" ) build_cross i686-w64-mingw32;;
|
||||
"cross-win64" ) build_cross x86_64-w64-mingw32;;
|
||||
"cross-android" ) CROSS=arm-linux-androideabi build;;
|
||||
"clang" ) CC=clang build;;
|
||||
"gcc" ) CC=gcc build;;
|
||||
"ios" ) build_iOS;;
|
||||
"ios_armv7" ) build_iOS armv7;;
|
||||
"ios_armv7s" ) build_iOS armv7s;;
|
||||
"ios_arm64" ) build_iOS arm64;;
|
||||
* )
|
||||
echo "Usage: $0 ["`grep '^ "' $0 | cut -d '"' -f 2 | tr "\\n" "|"`"]"
|
||||
exit 1;;
|
||||
esac
|
9
pkgconfig.mk
Normal file
9
pkgconfig.mk
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Package version of Unicorn for Makefile.
|
||||
# To be used to generate unicorn.pc for pkg-config
|
||||
|
||||
# version major & minor
|
||||
PKG_MAJOR = 0
|
||||
PKG_MINOR = 9
|
||||
|
||||
# version bugfix level. Example: PKG_EXTRA = 1
|
||||
PKG_EXTRA =
|
107
qemu/CODING_STYLE
Normal file
107
qemu/CODING_STYLE
Normal file
|
@ -0,0 +1,107 @@
|
|||
QEMU Coding Style
|
||||
=================
|
||||
|
||||
Please use the script checkpatch.pl in the scripts directory to check
|
||||
patches before submitting.
|
||||
|
||||
1. Whitespace
|
||||
|
||||
Of course, the most important aspect in any coding style is whitespace.
|
||||
Crusty old coders who have trouble spotting the glasses on their noses
|
||||
can tell the difference between a tab and eight spaces from a distance
|
||||
of approximately fifteen parsecs. Many a flamewar have been fought and
|
||||
lost on this issue.
|
||||
|
||||
QEMU indents are four spaces. Tabs are never used, except in Makefiles
|
||||
where they have been irreversibly coded into the syntax.
|
||||
Spaces of course are superior to tabs because:
|
||||
|
||||
- You have just one way to specify whitespace, not two. Ambiguity breeds
|
||||
mistakes.
|
||||
- The confusion surrounding 'use tabs to indent, spaces to justify' is gone.
|
||||
- Tab indents push your code to the right, making your screen seriously
|
||||
unbalanced.
|
||||
- Tabs will be rendered incorrectly on editors who are misconfigured not
|
||||
to use tab stops of eight positions.
|
||||
- Tabs are rendered badly in patches, causing off-by-one errors in almost
|
||||
every line.
|
||||
- It is the QEMU coding style.
|
||||
|
||||
Do not leave whitespace dangling off the ends of lines.
|
||||
|
||||
2. Line width
|
||||
|
||||
Lines are 80 characters; not longer.
|
||||
|
||||
Rationale:
|
||||
- Some people like to tile their 24" screens with a 6x4 matrix of 80x24
|
||||
xterms and use vi in all of them. The best way to punish them is to
|
||||
let them keep doing it.
|
||||
- Code and especially patches is much more readable if limited to a sane
|
||||
line length. Eighty is traditional.
|
||||
- It is the QEMU coding style.
|
||||
|
||||
3. Naming
|
||||
|
||||
Variables are lower_case_with_underscores; easy to type and read. Structured
|
||||
type names are in CamelCase; harder to type but standing out. Enum type
|
||||
names and function type names should also be in CamelCase. Scalar type
|
||||
names are lower_case_with_underscores_ending_with_a_t, like the POSIX
|
||||
uint64_t and family. Note that this last convention contradicts POSIX
|
||||
and is therefore likely to be changed.
|
||||
|
||||
When wrapping standard library functions, use the prefix qemu_ to alert
|
||||
readers that they are seeing a wrapped version; otherwise avoid this prefix.
|
||||
|
||||
4. Block structure
|
||||
|
||||
Every indented statement is braced; even if the block contains just one
|
||||
statement. The opening brace is on the line that contains the control
|
||||
flow statement that introduces the new block; the closing brace is on the
|
||||
same line as the else keyword, or on a line by itself if there is no else
|
||||
keyword. Example:
|
||||
|
||||
if (a == 5) {
|
||||
printf("a was 5.\n");
|
||||
} else if (a == 6) {
|
||||
printf("a was 6.\n");
|
||||
} else {
|
||||
printf("a was something else entirely.\n");
|
||||
}
|
||||
|
||||
Note that 'else if' is considered a single statement; otherwise a long if/
|
||||
else if/else if/.../else sequence would need an indent for every else
|
||||
statement.
|
||||
|
||||
An exception is the opening brace for a function; for reasons of tradition
|
||||
and clarity it comes on a line by itself:
|
||||
|
||||
void a_function(void)
|
||||
{
|
||||
do_something();
|
||||
}
|
||||
|
||||
Rationale: a consistent (except for functions...) bracing style reduces
|
||||
ambiguity and avoids needless churn when lines are added or removed.
|
||||
Furthermore, it is the QEMU coding style.
|
||||
|
||||
5. Declarations
|
||||
|
||||
Mixed declarations (interleaving statements and declarations within blocks)
|
||||
are not allowed; declarations should be at the beginning of blocks. In other
|
||||
words, the code should not generate warnings if using GCC's
|
||||
-Wdeclaration-after-statement option.
|
||||
|
||||
6. Conditional statements
|
||||
|
||||
When comparing a variable for (in)equality with a constant, list the
|
||||
constant on the right, as in:
|
||||
|
||||
if (a == 1) {
|
||||
/* Reads like: "If a equals 1" */
|
||||
do_something();
|
||||
}
|
||||
|
||||
Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
|
||||
Besides, good compilers already warn users when '==' is mis-typed as '=',
|
||||
even when the constant is on the right.
|
339
qemu/COPYING
Normal file
339
qemu/COPYING
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.
|
504
qemu/COPYING.LIB
Normal file
504
qemu/COPYING.LIB
Normal file
|
@ -0,0 +1,504 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin St, 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.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
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 and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, 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 library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete 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 distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
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 Library or any portion
|
||||
of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
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 Library, 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 Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you 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.
|
||||
|
||||
If distribution of 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 satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be 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.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library 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.
|
||||
|
||||
9. 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 Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
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 with
|
||||
this License.
|
||||
|
||||
11. 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 Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library 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 Library.
|
||||
|
||||
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.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library 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.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser 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 Library
|
||||
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 Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
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
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. 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 LIBRARY 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
|
||||
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. 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 library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
159
qemu/HACKING
Normal file
159
qemu/HACKING
Normal file
|
@ -0,0 +1,159 @@
|
|||
1. Preprocessor
|
||||
|
||||
For variadic macros, stick with this C99-like syntax:
|
||||
|
||||
#define DPRINTF(fmt, ...) \
|
||||
do { printf("IRQ: " fmt, ## __VA_ARGS__); } while (0)
|
||||
|
||||
2. C types
|
||||
|
||||
It should be common sense to use the right type, but we have collected
|
||||
a few useful guidelines here.
|
||||
|
||||
2.1. Scalars
|
||||
|
||||
If you're using "int" or "long", odds are good that there's a better type.
|
||||
If a variable is counting something, it should be declared with an
|
||||
unsigned type.
|
||||
|
||||
If it's host memory-size related, size_t should be a good choice (use
|
||||
ssize_t only if required). Guest RAM memory offsets must use ram_addr_t,
|
||||
but only for RAM, it may not cover whole guest address space.
|
||||
|
||||
If it's file-size related, use off_t.
|
||||
If it's file-offset related (i.e., signed), use off_t.
|
||||
If it's just counting small numbers use "unsigned int";
|
||||
(on all but oddball embedded systems, you can assume that that
|
||||
type is at least four bytes wide).
|
||||
|
||||
In the event that you require a specific width, use a standard type
|
||||
like int32_t, uint32_t, uint64_t, etc. The specific types are
|
||||
mandatory for VMState fields.
|
||||
|
||||
Don't use Linux kernel internal types like u32, __u32 or __le32.
|
||||
|
||||
Use hwaddr for guest physical addresses except pcibus_t
|
||||
for PCI addresses. In addition, ram_addr_t is a QEMU internal address
|
||||
space that maps guest RAM physical addresses into an intermediate
|
||||
address space that can map to host virtual address spaces. Generally
|
||||
speaking, the size of guest memory can always fit into ram_addr_t but
|
||||
it would not be correct to store an actual guest physical address in a
|
||||
ram_addr_t.
|
||||
|
||||
For CPU virtual addresses there are several possible types.
|
||||
vaddr is the best type to use to hold a CPU virtual address in
|
||||
target-independent code. It is guaranteed to be large enough to hold a
|
||||
virtual address for any target, and it does not change size from target
|
||||
to target. It is always unsigned.
|
||||
target_ulong is a type the size of a virtual address on the CPU; this means
|
||||
it may be 32 or 64 bits depending on which target is being built. It should
|
||||
therefore be used only in target-specific code, and in some
|
||||
performance-critical built-per-target core code such as the TLB code.
|
||||
There is also a signed version, target_long.
|
||||
abi_ulong is for the *-user targets, and represents a type the size of
|
||||
'void *' in that target's ABI. (This may not be the same as the size of a
|
||||
full CPU virtual address in the case of target ABIs which use 32 bit pointers
|
||||
on 64 bit CPUs, like sparc32plus.) Definitions of structures that must match
|
||||
the target's ABI must use this type for anything that on the target is defined
|
||||
to be an 'unsigned long' or a pointer type.
|
||||
There is also a signed version, abi_long.
|
||||
|
||||
Of course, take all of the above with a grain of salt. If you're about
|
||||
to use some system interface that requires a type like size_t, pid_t or
|
||||
off_t, use matching types for any corresponding variables.
|
||||
|
||||
Also, if you try to use e.g., "unsigned int" as a type, and that
|
||||
conflicts with the signedness of a related variable, sometimes
|
||||
it's best just to use the *wrong* type, if "pulling the thread"
|
||||
and fixing all related variables would be too invasive.
|
||||
|
||||
Finally, while using descriptive types is important, be careful not to
|
||||
go overboard. If whatever you're doing causes warnings, or requires
|
||||
casts, then reconsider or ask for help.
|
||||
|
||||
2.2. Pointers
|
||||
|
||||
Ensure that all of your pointers are "const-correct".
|
||||
Unless a pointer is used to modify the pointed-to storage,
|
||||
give it the "const" attribute. That way, the reader knows
|
||||
up-front that this is a read-only pointer. Perhaps more
|
||||
importantly, if we're diligent about this, when you see a non-const
|
||||
pointer, you're guaranteed that it is used to modify the storage
|
||||
it points to, or it is aliased to another pointer that is.
|
||||
|
||||
2.3. Typedefs
|
||||
Typedefs are used to eliminate the redundant 'struct' keyword.
|
||||
|
||||
2.4. Reserved namespaces in C and POSIX
|
||||
Underscore capital, double underscore, and underscore 't' suffixes should be
|
||||
avoided.
|
||||
|
||||
3. Low level memory management
|
||||
|
||||
Use of the malloc/free/realloc/calloc/valloc/memalign/posix_memalign
|
||||
APIs is not allowed in the QEMU codebase. Instead of these routines,
|
||||
use the GLib memory allocation routines g_malloc/g_malloc0/g_new/
|
||||
g_new0/g_realloc/g_free or QEMU's qemu_memalign/qemu_blockalign/qemu_vfree
|
||||
APIs.
|
||||
|
||||
Please note that g_malloc will exit on allocation failure, so there
|
||||
is no need to test for failure (as you would have to with malloc).
|
||||
Calling g_malloc with a zero size is valid and will return NULL.
|
||||
|
||||
Memory allocated by qemu_memalign or qemu_blockalign must be freed with
|
||||
qemu_vfree, since breaking this will cause problems on Win32.
|
||||
|
||||
4. String manipulation
|
||||
|
||||
Do not use the strncpy function. As mentioned in the man page, it does *not*
|
||||
guarantee a NULL-terminated buffer, which makes it extremely dangerous to use.
|
||||
It also zeros trailing destination bytes out to the specified length. Instead,
|
||||
use this similar function when possible, but note its different signature:
|
||||
void pstrcpy(char *dest, int dest_buf_size, const char *src)
|
||||
|
||||
Don't use strcat because it can't check for buffer overflows, but:
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
|
||||
The same limitation exists with sprintf and vsprintf, so use snprintf and
|
||||
vsnprintf.
|
||||
|
||||
QEMU provides other useful string functions:
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
int stristart(const char *str, const char *val, const char **ptr)
|
||||
int qemu_strnlen(const char *s, int max_len)
|
||||
|
||||
There are also replacement character processing macros for isxyz and toxyz,
|
||||
so instead of e.g. isalnum you should use qemu_isalnum.
|
||||
|
||||
Because of the memory management rules, you must use g_strdup/g_strndup
|
||||
instead of plain strdup/strndup.
|
||||
|
||||
5. Printf-style functions
|
||||
|
||||
Whenever you add a new printf-style function, i.e., one with a format
|
||||
string argument and following "..." in its prototype, be sure to use
|
||||
gcc's printf attribute directive in the prototype.
|
||||
|
||||
This makes it so gcc's -Wformat and -Wformat-security options can do
|
||||
their jobs and cross-check format strings with the number and types
|
||||
of arguments.
|
||||
|
||||
6. C standard, implementation defined and undefined behaviors
|
||||
|
||||
C code in QEMU should be written to the C99 language specification. A copy
|
||||
of the final version of the C99 standard with corrigenda TC1, TC2, and TC3
|
||||
included, formatted as a draft, can be downloaded from:
|
||||
http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf
|
||||
|
||||
The C language specification defines regions of undefined behavior and
|
||||
implementation defined behavior (to give compiler authors enough leeway to
|
||||
produce better code). In general, code in QEMU should follow the language
|
||||
specification and avoid both undefined and implementation defined
|
||||
constructs. ("It works fine on the gcc I tested it with" is not a valid
|
||||
argument...) However there are a few areas where we allow ourselves to
|
||||
assume certain behaviors because in practice all the platforms we care about
|
||||
behave in the same way and writing strictly conformant code would be
|
||||
painful. These are:
|
||||
* you may assume that integers are 2s complement representation
|
||||
* you may assume that right shift of a signed integer duplicates
|
||||
the sign bit (ie it is an arithmetic shift, not a logical shift)
|
21
qemu/LICENSE
Normal file
21
qemu/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The following points clarify the QEMU license:
|
||||
|
||||
1) QEMU as a whole is released under the GNU General Public License,
|
||||
version 2.
|
||||
|
||||
2) Parts of QEMU have specific licenses which are compatible with the
|
||||
GNU General Public License, version 2. Hence each source file contains
|
||||
its own licensing information. Source files with no licensing information
|
||||
are released under the GNU General Public License, version 2 or (at your
|
||||
option) any later version.
|
||||
|
||||
As of July 2013, contributions under version 2 of the GNU General Public
|
||||
License (and no later version) are only accepted for the following files
|
||||
or directories: bsd-user/, linux-user/, hw/misc/vfio.c, hw/xen/xen_pt*.
|
||||
|
||||
3) The Tiny Code Generator (TCG) is released under the BSD license
|
||||
(see license headers in files).
|
||||
|
||||
4) QEMU is a trademark of Fabrice Bellard.
|
||||
|
||||
Fabrice Bellard and the QEMU team
|
192
qemu/Makefile
Normal file
192
qemu/Makefile
Normal file
|
@ -0,0 +1,192 @@
|
|||
# Makefile for QEMU - modified for Unicorn engine.
|
||||
|
||||
# Always point to the root of the build tree (needs GNU make).
|
||||
BUILD_DIR=$(CURDIR)
|
||||
|
||||
# All following code might depend on configuration variables
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
# Put the all: rule here so that config-host.mak can contain dependencies.
|
||||
all:
|
||||
include config-host.mak
|
||||
|
||||
# Check that we're not trying to do an out-of-tree build from
|
||||
# a tree that's been used for an in-tree build.
|
||||
ifneq ($(realpath $(SRC_PATH)),$(realpath .))
|
||||
ifneq ($(wildcard $(SRC_PATH)/config-host.mak),)
|
||||
$(error This is an out of tree build but your source tree ($(SRC_PATH)) \
|
||||
seems to have been used for an in-tree build. You can fix this by running \
|
||||
"make distclean && rm -rf *-linux-user *-softmmu" in your source tree)
|
||||
endif
|
||||
endif
|
||||
|
||||
CONFIG_SOFTMMU := $(if $(filter %-softmmu,$(TARGET_DIRS)),y)
|
||||
CONFIG_USER_ONLY := $(if $(filter %-user,$(TARGET_DIRS)),y)
|
||||
CONFIG_ALL=y
|
||||
-include config-all-devices.mak
|
||||
-include config-all-disas.mak
|
||||
|
||||
include $(SRC_PATH)/rules.mak
|
||||
config-host.mak: $(SRC_PATH)/configure
|
||||
@echo $@ is out-of-date, running configure
|
||||
@# TODO: The next lines include code which supports a smooth
|
||||
@# transition from old configurations without config.status.
|
||||
@# This code can be removed after QEMU 1.7.
|
||||
@if test -x config.status; then \
|
||||
./config.status; \
|
||||
else \
|
||||
sed -n "/.*Configured with/s/[^:]*: //p" $@ | sh; \
|
||||
fi
|
||||
else
|
||||
config-host.mak:
|
||||
ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
|
||||
@echo "Please call configure before running make!"
|
||||
@exit 1
|
||||
endif
|
||||
endif
|
||||
|
||||
GENERATED_HEADERS = config-host.h
|
||||
GENERATED_HEADERS += qapi-types.h qapi-visit.h
|
||||
GENERATED_SOURCES += qapi-types.c qapi-visit.c
|
||||
|
||||
# Don't try to regenerate Makefile or configure
|
||||
# We don't generate any of them
|
||||
Makefile: ;
|
||||
configure: ;
|
||||
|
||||
.PHONY: all clean cscope distclean install recurse-all
|
||||
|
||||
$(call set-vpath, $(SRC_PATH))
|
||||
|
||||
LIBS+=-lz $(LIBS_TOOLS)
|
||||
|
||||
SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR)
|
||||
SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS))
|
||||
SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %-config-devices.mak.d, $(TARGET_DIRS))
|
||||
|
||||
ifeq ($(SUBDIR_DEVICES_MAK),)
|
||||
config-all-devices.mak:
|
||||
$(call quiet-command,echo '# no devices' > $@," GEN $@")
|
||||
else
|
||||
config-all-devices.mak: $(SUBDIR_DEVICES_MAK)
|
||||
$(call quiet-command, sed -n \
|
||||
's|^\([^=]*\)=\(.*\)$$|\1:=$$(findstring y,$$(\1)\2)|p' \
|
||||
$(SUBDIR_DEVICES_MAK) | sort -u > $@, \
|
||||
" GEN $@")
|
||||
endif
|
||||
|
||||
-include $(SUBDIR_DEVICES_MAK_DEP)
|
||||
|
||||
%/config-devices.mak: default-configs/%.mak
|
||||
$(call quiet-command,$(SHELL) $(SRC_PATH)/scripts/make_device_config.sh $@ $<, " GEN $@")
|
||||
@if test -f $@; then \
|
||||
if cmp -s $@.old $@; then \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
else \
|
||||
if test -f $@.old; then \
|
||||
echo "WARNING: $@ (user modified) out of date.";\
|
||||
else \
|
||||
echo "WARNING: $@ out of date.";\
|
||||
fi; \
|
||||
echo "Run \"make defconfig\" to regenerate."; \
|
||||
rm $@.tmp; \
|
||||
fi; \
|
||||
else \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
fi
|
||||
|
||||
defconfig:
|
||||
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
|
||||
|
||||
ifneq ($(wildcard config-host.mak),)
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
endif
|
||||
|
||||
dummy := $(call unnest-vars,, \
|
||||
util-obj-y \
|
||||
block-obj-y \
|
||||
block-obj-m \
|
||||
common-obj-y \
|
||||
common-obj-m)
|
||||
|
||||
all: $(TOOLS) $(HELPERS-y) recurse-all modules
|
||||
|
||||
config-host.h: config-host.h-timestamp
|
||||
config-host.h-timestamp: config-host.mak
|
||||
|
||||
SUBDIR_RULES=$(patsubst %,subdir-%, $(TARGET_DIRS))
|
||||
SOFTMMU_SUBDIR_RULES=$(filter %-softmmu,$(SUBDIR_RULES))
|
||||
|
||||
$(SOFTMMU_SUBDIR_RULES): $(block-obj-y)
|
||||
$(SOFTMMU_SUBDIR_RULES): config-all-devices.mak
|
||||
|
||||
subdir-%:
|
||||
$(call quiet-command,$(MAKE) $(SUBDIR_MAKEFLAGS) -C $* V="$(V)" TARGET_DIR="$*/" all,)
|
||||
|
||||
$(SUBDIR_RULES): qapi-types.c qapi-types.h qapi-visit.c qapi-visit.h $(common-obj-y) $(util-obj-y)
|
||||
|
||||
ALL_SUBDIRS=$(TARGET_DIRS)
|
||||
|
||||
recurse-all: $(SUBDIR_RULES)
|
||||
|
||||
######################################################################
|
||||
# Build libraries
|
||||
|
||||
util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
|
||||
|
||||
######################################################################
|
||||
|
||||
gen-out-type = $(subst .,-,$(suffix $@))
|
||||
|
||||
qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
|
||||
|
||||
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json
|
||||
|
||||
qapi-types.c qapi-types.h :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py \
|
||||
$(gen-out-type) -o "." -b -i $<, \
|
||||
" GEN $@")
|
||||
qapi-visit.c qapi-visit.h :\
|
||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-visit.py $(qapi-py)
|
||||
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py \
|
||||
$(gen-out-type) -o "." -b -i $<, \
|
||||
" GEN $@")
|
||||
|
||||
clean:
|
||||
# avoid old build problems by removing potentially incorrect old files
|
||||
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
|
||||
find . \( -name '*.l[oa]' -o -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
|
||||
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
|
||||
rm -rf .libs */.libs
|
||||
@# May not be present in GENERATED_HEADERS
|
||||
rm -f $(foreach f,$(GENERATED_HEADERS),$(f) $(f)-timestamp)
|
||||
rm -f $(foreach f,$(GENERATED_SOURCES),$(f) $(f)-timestamp)
|
||||
rm -rf qapi-generated
|
||||
for d in $(ALL_SUBDIRS); do \
|
||||
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
|
||||
done
|
||||
|
||||
distclean: clean
|
||||
rm -f config-host.mak config-host.h* config-host.ld qemu-img-cmds.texi qemu-monitor.texi
|
||||
rm -f config-all-devices.mak config-all-disas.mak
|
||||
rm -f config.log
|
||||
for d in $(TARGET_DIRS); do \
|
||||
rm -rf $$d || exit 1 ; \
|
||||
done
|
||||
rm -Rf .sdk
|
||||
|
||||
|
||||
cscope:
|
||||
rm -f ./cscope.*
|
||||
find "$(SRC_PATH)" -name "*.[chsS]" -print | sed 's,^\./,,' > ./cscope.files
|
||||
cscope -b
|
||||
|
||||
|
||||
# Add a dependency on the generated files, so that they are always
|
||||
# rebuilt before other object files
|
||||
ifneq ($(filter-out %clean,$(MAKECMDGOALS)),$(if $(MAKECMDGOALS),,fail))
|
||||
Makefile: $(GENERATED_HEADERS)
|
||||
endif
|
||||
|
31
qemu/Makefile.objs
Normal file
31
qemu/Makefile.objs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#######################################################################
|
||||
# Common libraries for tools and emulators
|
||||
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o
|
||||
|
||||
#######################################################################
|
||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y =
|
||||
block-obj-y += ../uc.o ../hook.o
|
||||
#block-obj-$(CONFIG_POSIX) += aio-posix.o
|
||||
#block-obj-$(CONFIG_WIN32) += aio-win32.o
|
||||
|
||||
#######################################################################
|
||||
# Target independent part of system emulation. The long term path is to
|
||||
# suppress *all* target specific code in case of system emulation, i.e. a
|
||||
# single QEMU executable should support all CPUs and machines.
|
||||
|
||||
ifeq ($(CONFIG_SOFTMMU),y)
|
||||
common-obj-y += hw/
|
||||
common-obj-y += accel.o
|
||||
|
||||
common-obj-y += vl.o main-loop.o qemu-timer.o
|
||||
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# Target-independent parts used in system and user emulation
|
||||
common-obj-y += qemu-log.o
|
||||
common-obj-y += tcg-runtime.o
|
||||
common-obj-y += hw/
|
||||
common-obj-y += qom/
|
119
qemu/Makefile.target
Normal file
119
qemu/Makefile.target
Normal file
|
@ -0,0 +1,119 @@
|
|||
# -*- Mode: makefile -*-
|
||||
|
||||
include ../config-host.mak
|
||||
include config-target.mak
|
||||
include config-devices.mak
|
||||
include $(SRC_PATH)/rules.mak
|
||||
|
||||
$(call set-vpath, $(SRC_PATH))
|
||||
QEMU_CFLAGS += -I.. -I$(SRC_PATH)/target-$(TARGET_BASE_ARCH) -DNEED_CPU_H
|
||||
|
||||
QEMU_CFLAGS+=-I$(SRC_PATH)/include
|
||||
|
||||
ifdef CONFIG_USER_ONLY
|
||||
# user emulator name
|
||||
QEMU_PROG=qemu-$(TARGET_NAME)
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
else
|
||||
# system emulator name
|
||||
QEMU_PROG=qemu-system-$(TARGET_NAME)$(EXESUF)
|
||||
ifneq (,$(findstring -mwindows,$(libs_softmmu)))
|
||||
# Terminate program name with a 'w' because the linker builds a windows executable.
|
||||
QEMU_PROGW=qemu-system-$(TARGET_NAME)w$(EXESUF)
|
||||
$(QEMU_PROG): $(QEMU_PROGW)
|
||||
$(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
|
||||
QEMU_PROG_BUILD = $(QEMU_PROGW)
|
||||
else
|
||||
QEMU_PROG_BUILD = $(QEMU_PROG)
|
||||
endif
|
||||
endif
|
||||
|
||||
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
|
||||
|
||||
config-target.h: config-target.h-timestamp
|
||||
config-target.h-timestamp: config-target.mak
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
# Dummy command so that make thinks it has done something
|
||||
@true
|
||||
|
||||
#########################################################
|
||||
# cpu emulator library
|
||||
obj-y = exec.o translate-all.o cpu-exec.o
|
||||
obj-y += tcg/tcg.o tcg/optimize.o
|
||||
obj-y += fpu/softfloat.o
|
||||
obj-y += target-$(TARGET_BASE_ARCH)/
|
||||
|
||||
#########################################################
|
||||
# System emulator target
|
||||
ifdef CONFIG_SOFTMMU
|
||||
obj-y += cpus.o ioport.o
|
||||
obj-y += hw/
|
||||
obj-y += memory.o cputlb.o
|
||||
obj-y += memory_mapping.o
|
||||
LIBS+=$(libs_softmmu)
|
||||
|
||||
# Hardware support
|
||||
ifeq ($(TARGET_NAME), sparc64)
|
||||
obj-y += hw/sparc64/
|
||||
else
|
||||
obj-y += hw/$(TARGET_BASE_ARCH)/
|
||||
endif
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
# Workaround for http://gcc.gnu.org/PR55489, see configure.
|
||||
%/translate.o: QEMU_CFLAGS += $(TRANSLATE_OPT_CFLAGS)
|
||||
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
all-obj-y := $(obj-y)
|
||||
|
||||
block-obj-y :=
|
||||
common-obj-y :=
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
|
||||
dummy := $(call unnest-vars,..,util-obj-y)
|
||||
|
||||
target-obj-y-save := $(target-obj-y) $(util-obj-y)
|
||||
|
||||
dummy := $(call unnest-vars,.., \
|
||||
block-obj-y \
|
||||
block-obj-m)
|
||||
|
||||
dummy := $(call unnest-vars,..,common-obj-y,common-obj-m)
|
||||
|
||||
target-obj-y := $(target-obj-y-save)
|
||||
all-obj-y += $(common-obj-y)
|
||||
all-obj-y += $(target-obj-y)
|
||||
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
|
||||
|
||||
# determine shared lib extension
|
||||
IS_APPLE := $(shell $(CC) -dM -E - < /dev/null | grep __apple_build_version__ | wc -l | tr -d " ")
|
||||
ifeq ($(IS_APPLE),1)
|
||||
EXT = dylib
|
||||
else
|
||||
# Cygwin?
|
||||
IS_CYGWIN := $(shell $(CC) -dumpmachine | grep -i cygwin | wc -l)
|
||||
ifeq ($(IS_CYGWIN),1)
|
||||
EXT = dll
|
||||
else
|
||||
EXT = so
|
||||
endif
|
||||
endif
|
||||
|
||||
# build either PROG or PROGW
|
||||
$(QEMU_PROG_BUILD): $(all-obj-y)
|
||||
|
||||
clean:
|
||||
rm -f *.a *~ $(PROGS)
|
||||
rm -f $(shell find . -name '*.[od]')
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
$(call install-prog,$(PROGS),$(DESTDIR)$(bindir))
|
||||
endif
|
||||
|
||||
GENERATED_HEADERS += config-target.h
|
||||
Makefile: $(GENERATED_HEADERS)
|
||||
|
1
qemu/VERSION
Normal file
1
qemu/VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
2.2.1
|
3168
qemu/aarch64.h
Normal file
3168
qemu/aarch64.h
Normal file
File diff suppressed because it is too large
Load diff
123
qemu/accel.c
Normal file
123
qemu/accel.c
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* QEMU System Emulator, accelerator interfaces
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2014 Red Hat Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
|
||||
|
||||
#include "sysemu/accel.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qom/object.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
// use default size for TCG translated block
|
||||
#define TCG_TB_SIZE 0
|
||||
|
||||
static bool tcg_allowed = true;
|
||||
static int tcg_init(MachineState *ms);
|
||||
static AccelClass *accel_find(struct uc_struct *uc, const char *opt_name);
|
||||
static int accel_init_machine(AccelClass *acc, MachineState *ms);
|
||||
static void tcg_accel_class_init(struct uc_struct *uc, ObjectClass *oc, void *data);
|
||||
|
||||
static int tcg_init(MachineState *ms)
|
||||
{
|
||||
ms->uc->tcg_exec_init(ms->uc, TCG_TB_SIZE * 1024 * 1024); // arch-dependent
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
.parent = TYPE_OBJECT,
|
||||
.class_size = sizeof(AccelClass),
|
||||
.instance_size = sizeof(AccelState),
|
||||
};
|
||||
|
||||
#define TYPE_TCG_ACCEL ACCEL_CLASS_NAME("tcg")
|
||||
|
||||
static const TypeInfo tcg_accel_type = {
|
||||
.name = TYPE_TCG_ACCEL,
|
||||
.parent = TYPE_ACCEL,
|
||||
.class_init = tcg_accel_class_init,
|
||||
};
|
||||
|
||||
|
||||
int configure_accelerator(MachineState *ms)
|
||||
{
|
||||
int ret;
|
||||
bool accel_initialised = false;
|
||||
AccelClass *acc;
|
||||
|
||||
acc = accel_find(ms->uc, "tcg");
|
||||
ret = accel_init_machine(acc, ms);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "failed to initialize %s: %s\n",
|
||||
acc->name,
|
||||
strerror(-ret));
|
||||
} else {
|
||||
accel_initialised = true;
|
||||
}
|
||||
|
||||
return !accel_initialised;
|
||||
}
|
||||
|
||||
void register_accel_types(struct uc_struct *uc)
|
||||
{
|
||||
type_register_static(uc, &accel_type);
|
||||
type_register_static(uc, &tcg_accel_type);
|
||||
}
|
||||
|
||||
static void tcg_accel_class_init(struct uc_struct *uc, ObjectClass *oc, void *data)
|
||||
{
|
||||
AccelClass *ac = ACCEL_CLASS(uc, oc);
|
||||
ac->name = "tcg";
|
||||
ac->init_machine = tcg_init;
|
||||
ac->allowed = &tcg_allowed;
|
||||
}
|
||||
|
||||
/* Lookup AccelClass from opt_name. Returns NULL if not found */
|
||||
static AccelClass *accel_find(struct uc_struct *uc, const char *opt_name)
|
||||
{
|
||||
char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name);
|
||||
AccelClass *ac = ACCEL_CLASS(uc, object_class_by_name(uc, class_name));
|
||||
g_free(class_name);
|
||||
return ac;
|
||||
}
|
||||
|
||||
static int accel_init_machine(AccelClass *acc, MachineState *ms)
|
||||
{
|
||||
ObjectClass *oc = OBJECT_CLASS(acc);
|
||||
const char *cname = object_class_get_name(oc);
|
||||
AccelState *accel = ACCEL(ms->uc, object_new(ms->uc, cname));
|
||||
int ret;
|
||||
ms->accelerator = accel;
|
||||
*(acc->allowed) = true;
|
||||
ret = acc->init_machine(ms);
|
||||
if (ret < 0) {
|
||||
ms->accelerator = NULL;
|
||||
*(acc->allowed) = false;
|
||||
object_unref(ms->uc, OBJECT(accel));
|
||||
}
|
||||
return ret;
|
||||
}
|
3168
qemu/arm.h
Normal file
3168
qemu/arm.h
Normal file
File diff suppressed because it is too large
Load diff
1
qemu/config-all-disas.mak
Normal file
1
qemu/config-all-disas.mak
Normal file
|
@ -0,0 +1 @@
|
|||
# Automatically generated by configure - do not modify
|
1938
qemu/configure
vendored
Executable file
1938
qemu/configure
vendored
Executable file
File diff suppressed because it is too large
Load diff
416
qemu/cpu-exec.c
Normal file
416
qemu/cpu-exec.c
Normal file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* emulator main execution loop
|
||||
*
|
||||
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
|
||||
|
||||
#include "tcg.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
#include "uc_priv.h"
|
||||
|
||||
static tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr);
|
||||
static TranslationBlock *tb_find_slow(CPUArchState *env, target_ulong pc,
|
||||
target_ulong cs_base, uint64_t flags);
|
||||
static TranslationBlock *tb_find_fast(CPUArchState *env);
|
||||
static void cpu_handle_debug_exception(CPUArchState *env);
|
||||
|
||||
void cpu_loop_exit(CPUState *cpu)
|
||||
{
|
||||
cpu->current_tb = NULL;
|
||||
siglongjmp(cpu->jmp_env, 1);
|
||||
}
|
||||
|
||||
/* exit the current TB from a signal handler. The host registers are
|
||||
restored in a state compatible with the CPU emulator
|
||||
*/
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
|
||||
void cpu_resume_from_signal(CPUState *cpu, void *puc)
|
||||
{
|
||||
#endif
|
||||
/* XXX: restore cpu registers saved in host registers */
|
||||
|
||||
cpu->exception_index = -1;
|
||||
siglongjmp(cpu->jmp_env, 1);
|
||||
}
|
||||
|
||||
/* main execution loop */
|
||||
|
||||
int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
TCGContext *tcg_ctx = env->uc->tcg_ctx;
|
||||
CPUClass *cc = CPU_GET_CLASS(uc, cpu);
|
||||
#ifdef TARGET_I386
|
||||
X86CPU *x86_cpu = X86_CPU(uc, cpu);
|
||||
#endif
|
||||
int ret, interrupt_request;
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
uintptr_t next_tb;
|
||||
|
||||
/* This must be volatile so it is not trashed by longjmp() */
|
||||
volatile bool have_tb_lock = false;
|
||||
|
||||
if (cpu->halted) {
|
||||
if (!cpu_has_work(cpu)) {
|
||||
return EXCP_HALTED;
|
||||
}
|
||||
|
||||
cpu->halted = 0;
|
||||
}
|
||||
|
||||
uc->current_cpu = cpu;
|
||||
|
||||
/* As long as current_cpu is null, up to the assignment just above,
|
||||
* requests by other threads to exit the execution loop are expected to
|
||||
* be issued using the exit_request global. We must make sure that our
|
||||
* evaluation of the global value is performed past the current_cpu
|
||||
* value transition point, which requires a memory barrier as well as
|
||||
* an instruction scheduling constraint on modern architectures. */
|
||||
smp_mb();
|
||||
|
||||
if (unlikely(uc->exit_request)) {
|
||||
cpu->exit_request = 1;
|
||||
}
|
||||
|
||||
cc->cpu_exec_enter(cpu);
|
||||
cpu->exception_index = -1;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
for(;;) {
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
if (uc->stop_request || uc->invalid_error)
|
||||
break;
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (cpu->exception_index >= 0) {
|
||||
//printf(">>> GOT INTERRUPT. exception idx = %x\n", cpu->exception_index); // qq
|
||||
if (uc->stop_interrupt && uc->stop_interrupt(cpu->exception_index)) {
|
||||
cpu->halted = 1;
|
||||
uc->invalid_error = UC_ERR_INSN_INVALID;
|
||||
ret = EXCP_HLT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((uc->arch == UC_ARCH_X86 && cpu->exception_index == 0x99) || // X86's Int 0x99
|
||||
(uc->arch == UC_ARCH_ARM && cpu->exception_index == 2) || /* ARM's EXCP_SWI */
|
||||
(uc->arch == UC_ARCH_ARM64 && cpu->exception_index == 2) || /* ARM's EXCP_SWI */
|
||||
(uc->arch == UC_ARCH_MIPS && cpu->exception_index == 17) || /* Mips's EXCP_SYSCALL */
|
||||
(uc->arch == UC_ARCH_SPARC && cpu->exception_index == 0x80) || /* Sparc's TT_TRAP */
|
||||
(uc->arch == UC_ARCH_SPARC && cpu->exception_index == 0x100) || /* Sparc64's TT_TRAP */
|
||||
(uc->arch == UC_ARCH_M68K && cpu->exception_index == 0x2f) /* M68K's EXCP_TRAP15 */
|
||||
) {
|
||||
cpu->halted = 1;
|
||||
//cpu->exception_index = EXCP_HLT;
|
||||
//no_shutdown = 0;
|
||||
//printf(">>> calling shutdown-request...\n");
|
||||
//printf(">>> ** current EIP = %x\n", X86_CPU(cpu)->env.eip);
|
||||
//qemu_system_shutdown_request();
|
||||
//pause_all_vcpus();
|
||||
//cpu_loop_exit(cpu);
|
||||
ret = EXCP_HLT;
|
||||
break;
|
||||
}
|
||||
if (cpu->exception_index >= EXCP_INTERRUPT) {
|
||||
/* exit request from the cpu execution loop */
|
||||
ret = cpu->exception_index;
|
||||
if (ret == EXCP_DEBUG) {
|
||||
cpu_handle_debug_exception(env);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* if user mode only, we simulate a fake exception
|
||||
which will be handled outside the cpu execution
|
||||
loop */
|
||||
#if defined(TARGET_I386)
|
||||
cc->do_interrupt(cpu);
|
||||
#endif
|
||||
ret = cpu->exception_index;
|
||||
break;
|
||||
#else
|
||||
// Unicorn: call interrupt callback if registered
|
||||
if (uc->hook_intr_idx)
|
||||
((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)(
|
||||
(uch)uc, cpu->exception_index,
|
||||
uc->hook_callbacks[uc->hook_intr_idx].user_data);
|
||||
cpu->exception_index = -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
next_tb = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
interrupt_request = cpu->interrupt_request;
|
||||
|
||||
if (unlikely(interrupt_request)) {
|
||||
if (unlikely(cpu->singlestep_enabled & SSTEP_NOIRQ)) {
|
||||
/* Mask out external interrupts for this step. */
|
||||
interrupt_request &= ~CPU_INTERRUPT_SSTEP_MASK;
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_HALT) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
|
||||
cpu->halted = 1;
|
||||
cpu->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#if defined(TARGET_I386)
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#else
|
||||
if (interrupt_request & CPU_INTERRUPT_RESET) {
|
||||
cpu_reset(cpu);
|
||||
}
|
||||
#endif
|
||||
/* The target hook has 3 exit conditions:
|
||||
False when the interrupt isn't processed,
|
||||
True when it is, and we should restart on a new TB,
|
||||
and via longjmp via cpu_loop_exit. */
|
||||
if (cc->cpu_exec_interrupt(cpu, interrupt_request)) {
|
||||
next_tb = 0;
|
||||
}
|
||||
/* Don't use the cached interrupt_request value,
|
||||
do_interrupt may have updated the EXITTB flag. */
|
||||
if (cpu->interrupt_request & CPU_INTERRUPT_EXITTB) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
next_tb = 0;
|
||||
}
|
||||
}
|
||||
if (unlikely(cpu->exit_request)) {
|
||||
cpu->exit_request = 0;
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
spin_lock(&tcg_ctx->tb_ctx.tb_lock);
|
||||
have_tb_lock = true;
|
||||
tb = tb_find_fast(env); // qq
|
||||
if (!tb) { // invalid TB due to invalid code?
|
||||
break;
|
||||
}
|
||||
/* Note: we do it here to avoid a gcc bug on Mac OS X when
|
||||
doing it in tb_find_slow */
|
||||
if (tcg_ctx->tb_ctx.tb_invalidated_flag) {
|
||||
/* as some TB could have been invalidated because
|
||||
of memory exceptions while generating the code, we
|
||||
must recompute the hash index here */
|
||||
next_tb = 0;
|
||||
tcg_ctx->tb_ctx.tb_invalidated_flag = 0;
|
||||
}
|
||||
/* see if we can patch the calling TB. When the TB
|
||||
spans two pages, we cannot safely do a direct
|
||||
jump. */
|
||||
if (next_tb != 0 && tb->page_addr[1] == -1) {
|
||||
tb_add_jump((TranslationBlock *)(next_tb & ~TB_EXIT_MASK),
|
||||
next_tb & TB_EXIT_MASK, tb);
|
||||
}
|
||||
have_tb_lock = false;
|
||||
spin_unlock(&tcg_ctx->tb_ctx.tb_lock);
|
||||
|
||||
/* cpu_interrupt might be called while translating the
|
||||
TB, but before it is linked into a potentially
|
||||
infinite loop and becomes env->current_tb. Avoid
|
||||
starting execution if there is a pending interrupt. */
|
||||
cpu->current_tb = tb;
|
||||
barrier();
|
||||
if (likely(!cpu->exit_request)) {
|
||||
tc_ptr = tb->tc_ptr;
|
||||
/* execute the generated code */
|
||||
next_tb = cpu_tb_exec(cpu, tc_ptr); // qq
|
||||
switch (next_tb & TB_EXIT_MASK) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
/* Something asked us to stop executing
|
||||
* chained TBs; just continue round the main
|
||||
* loop. Whatever requested the exit will also
|
||||
* have set something else (eg exit_request or
|
||||
* interrupt_request) which we will handle
|
||||
* next time around the loop.
|
||||
*/
|
||||
tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
next_tb = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
cpu->current_tb = NULL;
|
||||
/* reset soft MMU for next block (it can currently
|
||||
only be set by a memory fault) */
|
||||
} /* for(;;) */
|
||||
} else {
|
||||
/* Reload env after longjmp - the compiler may have smashed all
|
||||
* local variables as longjmp is marked 'noreturn'. */
|
||||
cpu = uc->current_cpu;
|
||||
env = cpu->env_ptr;
|
||||
cc = CPU_GET_CLASS(uc, cpu);
|
||||
#ifdef TARGET_I386
|
||||
x86_cpu = X86_CPU(uc, cpu);
|
||||
#endif
|
||||
if (have_tb_lock) {
|
||||
spin_unlock(&tcg_ctx->tb_ctx.tb_lock);
|
||||
have_tb_lock = false;
|
||||
}
|
||||
}
|
||||
} /* for(;;) */
|
||||
|
||||
cc->cpu_exec_exit(cpu);
|
||||
|
||||
/* fail safe : never use current_cpu outside cpu_exec() */
|
||||
uc->current_cpu = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Execute a TB, and fix up the CPU state afterwards if necessary */
|
||||
static tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
TCGContext *tcg_ctx = env->uc->tcg_ctx;
|
||||
uintptr_t next_tb;
|
||||
|
||||
next_tb = tcg_qemu_tb_exec(env, tb_ptr);
|
||||
|
||||
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
|
||||
/* We didn't start executing this TB (eg because the instruction
|
||||
* counter hit zero); we must restore the guest PC to the address
|
||||
* of the start of the TB.
|
||||
*/
|
||||
CPUClass *cc = CPU_GET_CLASS(env->uc, cpu);
|
||||
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
if (cc->synchronize_from_tb) {
|
||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||
if (env->uc->emu_counter <= env->uc->emu_count)
|
||||
cc->synchronize_from_tb(cpu, tb); // qq
|
||||
} else {
|
||||
assert(cc->set_pc);
|
||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||
if (env->uc->emu_counter <= env->uc->emu_count)
|
||||
cc->set_pc(cpu, tb->pc);
|
||||
}
|
||||
}
|
||||
if ((next_tb & TB_EXIT_MASK) == TB_EXIT_REQUESTED) {
|
||||
/* We were asked to stop executing TBs (probably a pending
|
||||
* interrupt. We've now stopped, so clear the flag.
|
||||
*/
|
||||
cpu->tcg_exit_req = 0;
|
||||
}
|
||||
return next_tb;
|
||||
}
|
||||
|
||||
static TranslationBlock *tb_find_slow(CPUArchState *env, target_ulong pc,
|
||||
target_ulong cs_base, uint64_t flags) // qq
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
TCGContext *tcg_ctx = env->uc->tcg_ctx;
|
||||
TranslationBlock *tb, **ptb1;
|
||||
unsigned int h;
|
||||
tb_page_addr_t phys_pc, phys_page1;
|
||||
target_ulong virt_page2;
|
||||
|
||||
tcg_ctx->tb_ctx.tb_invalidated_flag = 0;
|
||||
|
||||
/* find translated block using physical mappings */
|
||||
phys_pc = get_page_addr_code(env, pc); // qq
|
||||
if (phys_pc == -1) { // invalid code?
|
||||
return NULL;
|
||||
}
|
||||
phys_page1 = phys_pc & TARGET_PAGE_MASK;
|
||||
h = tb_phys_hash_func(phys_pc);
|
||||
ptb1 = &tcg_ctx->tb_ctx.tb_phys_hash[h];
|
||||
for(;;) {
|
||||
tb = *ptb1;
|
||||
if (!tb)
|
||||
goto not_found;
|
||||
if (tb->pc == pc &&
|
||||
tb->page_addr[0] == phys_page1 &&
|
||||
tb->cs_base == cs_base &&
|
||||
tb->flags == flags) {
|
||||
/* check next page if needed */
|
||||
if (tb->page_addr[1] != -1) {
|
||||
tb_page_addr_t phys_page2;
|
||||
|
||||
virt_page2 = (pc & TARGET_PAGE_MASK) +
|
||||
TARGET_PAGE_SIZE;
|
||||
phys_page2 = get_page_addr_code(env, virt_page2);
|
||||
if (tb->page_addr[1] == phys_page2)
|
||||
goto found;
|
||||
} else {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
ptb1 = &tb->phys_hash_next;
|
||||
}
|
||||
not_found:
|
||||
/* if no translated code available, then translate it now */
|
||||
tb = tb_gen_code(cpu, pc, cs_base, flags, 0); // qq
|
||||
|
||||
found:
|
||||
/* Move the last found TB to the head of the list */
|
||||
if (likely(*ptb1)) {
|
||||
*ptb1 = tb->phys_hash_next;
|
||||
tb->phys_hash_next = tcg_ctx->tb_ctx.tb_phys_hash[h];
|
||||
tcg_ctx->tb_ctx.tb_phys_hash[h] = tb;
|
||||
}
|
||||
/* we add the TB in the virtual pc hash table */
|
||||
cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
|
||||
return tb;
|
||||
}
|
||||
|
||||
static TranslationBlock *tb_find_fast(CPUArchState *env) // qq
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
TranslationBlock *tb;
|
||||
target_ulong cs_base, pc;
|
||||
int flags;
|
||||
|
||||
/* we record a subset of the CPU state. It will
|
||||
always be the same before a given translated block
|
||||
is executed. */
|
||||
cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
|
||||
tb = cpu->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
|
||||
if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
|
||||
tb->flags != flags)) {
|
||||
tb = tb_find_slow(env, pc, cs_base, flags); // qq
|
||||
}
|
||||
return tb;
|
||||
}
|
||||
|
||||
static void cpu_handle_debug_exception(CPUArchState *env)
|
||||
{
|
||||
CPUState *cpu = ENV_GET_CPU(env);
|
||||
CPUClass *cc = CPU_GET_CLASS(env->uc, cpu);
|
||||
CPUWatchpoint *wp;
|
||||
|
||||
if (!cpu->watchpoint_hit) {
|
||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||
wp->flags &= ~BP_WATCHPOINT_HIT;
|
||||
}
|
||||
}
|
||||
|
||||
cc->debug_excp_handler(cpu);
|
||||
}
|
298
qemu/cpus.c
Normal file
298
qemu/cpus.c
Normal file
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
|
||||
|
||||
/* Needed early for CONFIG_BSD etc. */
|
||||
#include "config-host.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
#include "exec/address-spaces.h" // debug, can be removed later
|
||||
|
||||
#include "uc_priv.h"
|
||||
|
||||
static bool cpu_can_run(CPUState *cpu);
|
||||
static void cpu_handle_guest_debug(CPUState *cpu);
|
||||
static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env);
|
||||
static bool tcg_exec_all(struct uc_struct* uc);
|
||||
static void qemu_tcg_init_vcpu(CPUState *cpu);
|
||||
static void *qemu_tcg_cpu_thread_fn(void *arg);
|
||||
|
||||
void vm_start(struct uc_struct* uc)
|
||||
{
|
||||
resume_all_vcpus(uc);
|
||||
|
||||
//sleep(3);
|
||||
// kick off TCG thread
|
||||
qemu_mutex_unlock_iothread(uc);
|
||||
}
|
||||
|
||||
bool cpu_is_stopped(CPUState *cpu)
|
||||
{
|
||||
return cpu->stopped;
|
||||
}
|
||||
|
||||
void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data)
|
||||
{
|
||||
if (qemu_cpu_is_self(cpu)) {
|
||||
func(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// send halt_cond/tcg_halt_cond to @cpu
|
||||
bool qemu_cpu_is_self(CPUState *cpu)
|
||||
{
|
||||
return qemu_thread_is_self(cpu->thread);
|
||||
}
|
||||
|
||||
void pause_all_vcpus(struct uc_struct *uc)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
qemu_thread_join(cpu->thread); // qq: fix qemu_thread_join() to work for instance
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void resume_all_vcpus(struct uc_struct *uc)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
{
|
||||
// Fix call multiple time (vu).
|
||||
// We have to check whether this is the second time, then reset all CPU.
|
||||
bool created = false;
|
||||
CPU_FOREACH(cpu) {
|
||||
created |= cpu->created;
|
||||
}
|
||||
if (!created) {
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu->created = true;
|
||||
cpu->halted = 0;
|
||||
qemu_init_vcpu(cpu);
|
||||
}
|
||||
qemu_mutex_lock_iothread(uc);
|
||||
}
|
||||
}
|
||||
|
||||
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu_resume(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
cpu->nr_cores = smp_cores;
|
||||
cpu->nr_threads = smp_threads;
|
||||
cpu->stopped = true;
|
||||
cpu->uc->tcg_cpu_thread = NULL;
|
||||
|
||||
if (tcg_enabled(cpu->uc)) {
|
||||
qemu_tcg_init_vcpu(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
struct uc_struct *uc = cpu->uc;
|
||||
|
||||
//qemu_tcg_init_cpu_signals();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
||||
qemu_mutex_lock(&uc->qemu_global_mutex);
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
cpu->created = true;
|
||||
}
|
||||
qemu_cond_signal(&uc->qemu_cpu_cond);
|
||||
|
||||
|
||||
/* wait for initial kick-off after machine start */
|
||||
while (QTAILQ_FIRST(&uc->cpus)->stopped) {
|
||||
qemu_cond_wait(uc->tcg_halt_cond, &uc->qemu_global_mutex);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
#if 0
|
||||
int count = 0;
|
||||
if (count < 10) {
|
||||
count++;
|
||||
unsigned int eip = X86_CPU(mycpu)->env.eip;
|
||||
printf(">>> current EIP = %x\n", eip);
|
||||
printf(">>> ECX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_ECX]);
|
||||
printf(">>> EDX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_EDX]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tcg_exec_all(uc))
|
||||
break;
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
cpu->thread_id = 0;
|
||||
cpu->created = false;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock(&uc->qemu_global_mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For temporary buffers for forming a name */
|
||||
#define VCPU_THREAD_NAME_SIZE 16
|
||||
|
||||
static void qemu_tcg_init_vcpu(CPUState *cpu)
|
||||
{
|
||||
struct uc_struct *uc = cpu->uc;
|
||||
char thread_name[VCPU_THREAD_NAME_SIZE];
|
||||
|
||||
tcg_cpu_address_space_init(cpu, cpu->as);
|
||||
|
||||
/* share a single thread for all cpus with TCG */
|
||||
if (!uc->tcg_cpu_thread) {
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
cpu->halt_cond = g_malloc0(sizeof(QemuCond));
|
||||
qemu_cond_init(cpu->halt_cond);
|
||||
uc->tcg_halt_cond = cpu->halt_cond;
|
||||
snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG",
|
||||
cpu->cpu_index);
|
||||
qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn,
|
||||
cpu, QEMU_THREAD_JOINABLE);
|
||||
#ifdef _WIN32
|
||||
cpu->hThread = qemu_thread_get_handle(cpu->thread);
|
||||
#endif
|
||||
while (!cpu->created) {
|
||||
qemu_cond_wait(&uc->qemu_cpu_cond, &uc->qemu_global_mutex);
|
||||
}
|
||||
uc->tcg_cpu_thread = cpu->thread;
|
||||
} else {
|
||||
cpu->thread = uc->tcg_cpu_thread;
|
||||
cpu->halt_cond = uc->tcg_halt_cond;
|
||||
}
|
||||
}
|
||||
|
||||
static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env)
|
||||
{
|
||||
return cpu_exec(uc, env);
|
||||
}
|
||||
|
||||
static bool tcg_exec_all(struct uc_struct* uc)
|
||||
{
|
||||
int r;
|
||||
bool finish = false;
|
||||
CPUState *next_cpu = uc->next_cpu;
|
||||
|
||||
if (next_cpu == NULL) {
|
||||
next_cpu = first_cpu;
|
||||
}
|
||||
|
||||
for (; next_cpu != NULL && !uc->exit_request; next_cpu = CPU_NEXT(next_cpu)) {
|
||||
CPUState *cpu = next_cpu;
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
|
||||
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
||||
// (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||
if (cpu_can_run(cpu)) {
|
||||
r = tcg_cpu_exec(uc, env);
|
||||
if (uc->stop_request) {
|
||||
//printf(">>> got STOP request!!!\n");
|
||||
finish = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// save invalid memory access error & quit
|
||||
if (env->invalid_error) {
|
||||
// printf(">>> invalid memory accessed, STOP = %u!!!\n", env->invalid_error);
|
||||
uc->invalid_addr = env->invalid_addr;
|
||||
uc->invalid_error = env->invalid_error;
|
||||
finish = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// printf(">>> stop with r = %x, HLT=%x\n", r, EXCP_HLT);
|
||||
if (r == EXCP_DEBUG) {
|
||||
cpu_handle_guest_debug(cpu);
|
||||
break;
|
||||
}
|
||||
if (r == EXCP_HLT) {
|
||||
//printf(">>> got HLT!!!\n");
|
||||
finish = true;
|
||||
break;
|
||||
}
|
||||
} else if (cpu->stop || cpu->stopped) {
|
||||
printf(">>> got stopped!!!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
uc->exit_request = 0;
|
||||
|
||||
return finish;
|
||||
}
|
||||
|
||||
static bool cpu_can_run(CPUState *cpu)
|
||||
{
|
||||
if (cpu->stop) {
|
||||
return false;
|
||||
}
|
||||
if (cpu_is_stopped(cpu)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void cpu_handle_guest_debug(CPUState *cpu)
|
||||
{
|
||||
cpu->stopped = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifndef _WIN32
|
||||
static void qemu_tcg_init_cpu_signals(void)
|
||||
{
|
||||
sigset_t set;
|
||||
struct sigaction sigact;
|
||||
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_handler = cpu_signal;
|
||||
sigaction(SIG_IPI, &sigact, NULL);
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIG_IPI);
|
||||
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
|
||||
}
|
||||
#else /* _WIN32 */
|
||||
static void qemu_tcg_init_cpu_signals(void)
|
||||
{
|
||||
}
|
||||
#endif /* _WIN32 */
|
||||
#endif
|
||||
|
414
qemu/cputlb.c
Normal file
414
qemu/cputlb.c
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* Common CPU TLB handling
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */
|
||||
|
||||
#include "config.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
|
||||
#include "exec/cputlb.h"
|
||||
|
||||
#include "exec/memory-internal.h"
|
||||
#include "exec/ram_addr.h"
|
||||
#include "tcg/tcg.h"
|
||||
|
||||
#include "uc_priv.h"
|
||||
|
||||
//#define DEBUG_TLB
|
||||
//#define DEBUG_TLB_CHECK
|
||||
|
||||
static void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr);
|
||||
static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe);
|
||||
static ram_addr_t qemu_ram_addr_from_host_nofail(struct uc_struct *uc, void *ptr);
|
||||
static void tlb_add_large_page(CPUArchState *env, target_ulong vaddr,
|
||||
target_ulong size);
|
||||
static void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr);
|
||||
|
||||
/* statistics */
|
||||
//int tlb_flush_count;
|
||||
|
||||
/* NOTE:
|
||||
* If flush_global is true (the usual case), flush all tlb entries.
|
||||
* If flush_global is false, flush (at least) all tlb entries not
|
||||
* marked global.
|
||||
*
|
||||
* Since QEMU doesn't currently implement a global/not-global flag
|
||||
* for tlb entries, at the moment tlb_flush() will also flush all
|
||||
* tlb entries in the flush_global == false case. This is OK because
|
||||
* CPU architectures generally permit an implementation to drop
|
||||
* entries from the TLB at any time, so flushing more entries than
|
||||
* required is only an efficiency issue, not a correctness issue.
|
||||
*/
|
||||
void tlb_flush(CPUState *cpu, int flush_global)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_flush:\n");
|
||||
#endif
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
cpu->current_tb = NULL;
|
||||
|
||||
memset(env->tlb_table, -1, sizeof(env->tlb_table));
|
||||
memset(env->tlb_v_table, -1, sizeof(env->tlb_v_table));
|
||||
memset(cpu->tb_jmp_cache, 0, sizeof(cpu->tb_jmp_cache));
|
||||
|
||||
env->vtlb_index = 0;
|
||||
env->tlb_flush_addr = -1;
|
||||
env->tlb_flush_mask = 0;
|
||||
//tlb_flush_count++;
|
||||
}
|
||||
|
||||
void tlb_flush_page(CPUState *cpu, target_ulong addr)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
int i;
|
||||
int mmu_idx;
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
|
||||
#endif
|
||||
/* Check if we need to flush due to large pages. */
|
||||
if ((addr & env->tlb_flush_mask) == env->tlb_flush_addr) {
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_flush_page: forced full flush ("
|
||||
TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
|
||||
env->tlb_flush_addr, env->tlb_flush_mask);
|
||||
#endif
|
||||
tlb_flush(cpu, 1);
|
||||
return;
|
||||
}
|
||||
/* must reset current TB so that interrupts cannot modify the
|
||||
links while we are modifying them */
|
||||
cpu->current_tb = NULL;
|
||||
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
|
||||
}
|
||||
|
||||
/* check whether there are entries that need to be flushed in the vtlb */
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
int k;
|
||||
for (k = 0; k < CPU_VTLB_SIZE; k++) {
|
||||
tlb_flush_entry(&env->tlb_v_table[mmu_idx][k], addr);
|
||||
}
|
||||
}
|
||||
|
||||
tb_flush_jmp_cache(cpu, addr);
|
||||
}
|
||||
|
||||
/* update the TLBs so that writes to code in the virtual page 'addr'
|
||||
can be detected */
|
||||
void tlb_protect_code(struct uc_struct *uc, ram_addr_t ram_addr)
|
||||
{
|
||||
cpu_physical_memory_reset_dirty(uc, ram_addr, TARGET_PAGE_SIZE,
|
||||
DIRTY_MEMORY_CODE);
|
||||
}
|
||||
|
||||
/* update the TLB so that writes in physical page 'phys_addr' are no longer
|
||||
tested for self modifying code */
|
||||
void tlb_unprotect_code_phys(CPUState *cpu, ram_addr_t ram_addr,
|
||||
target_ulong vaddr)
|
||||
{
|
||||
cpu_physical_memory_set_dirty_flag(cpu->uc, ram_addr, DIRTY_MEMORY_CODE);
|
||||
}
|
||||
|
||||
void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start,
|
||||
uintptr_t length)
|
||||
{
|
||||
uintptr_t addr;
|
||||
|
||||
if (tlb_is_dirty_ram(tlb_entry)) {
|
||||
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
|
||||
if ((addr - start) < length) {
|
||||
tlb_entry->addr_write |= TLB_NOTDIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_tlb_reset_dirty_all(struct uc_struct *uc,
|
||||
ram_addr_t start1, ram_addr_t length)
|
||||
{
|
||||
CPUState *cpu;
|
||||
CPUArchState *env;
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
int mmu_idx;
|
||||
|
||||
env = cpu->env_ptr;
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < CPU_TLB_SIZE; i++) {
|
||||
tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
|
||||
start1, length);
|
||||
}
|
||||
|
||||
for (i = 0; i < CPU_VTLB_SIZE; i++) {
|
||||
tlb_reset_dirty_range(&env->tlb_v_table[mmu_idx][i],
|
||||
start1, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* update the TLB corresponding to virtual page vaddr
|
||||
so that it is no longer dirty */
|
||||
void tlb_set_dirty(CPUArchState *env, target_ulong vaddr)
|
||||
{
|
||||
int i;
|
||||
int mmu_idx;
|
||||
|
||||
vaddr &= TARGET_PAGE_MASK;
|
||||
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
|
||||
}
|
||||
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
int k;
|
||||
for (k = 0; k < CPU_VTLB_SIZE; k++) {
|
||||
tlb_set_dirty1(&env->tlb_v_table[mmu_idx][k], vaddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Add a new TLB entry. At most one entry for a given virtual address
|
||||
is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
|
||||
supplied size is only used by tlb_flush_page. */
|
||||
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
|
||||
hwaddr paddr, int prot,
|
||||
int mmu_idx, target_ulong size)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
MemoryRegionSection *section;
|
||||
unsigned int index;
|
||||
target_ulong address;
|
||||
target_ulong code_address;
|
||||
uintptr_t addend;
|
||||
CPUTLBEntry *te;
|
||||
hwaddr iotlb, xlat, sz;
|
||||
unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE;
|
||||
|
||||
assert(size >= TARGET_PAGE_SIZE);
|
||||
if (size != TARGET_PAGE_SIZE) {
|
||||
tlb_add_large_page(env, vaddr, size);
|
||||
}
|
||||
|
||||
sz = size;
|
||||
section = address_space_translate_for_iotlb(cpu->as, paddr,
|
||||
&xlat, &sz);
|
||||
assert(sz >= TARGET_PAGE_SIZE);
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
|
||||
" prot=%x idx=%d\n",
|
||||
vaddr, paddr, prot, mmu_idx);
|
||||
#endif
|
||||
|
||||
address = vaddr;
|
||||
if (!memory_region_is_ram(section->mr) && !memory_region_is_romd(section->mr)) {
|
||||
/* IO memory case */
|
||||
address |= TLB_MMIO;
|
||||
addend = 0;
|
||||
} else {
|
||||
/* TLB_MMIO for rom/romd handled below */
|
||||
addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat;
|
||||
}
|
||||
|
||||
code_address = address;
|
||||
iotlb = memory_region_section_get_iotlb(cpu, section, vaddr, paddr, xlat,
|
||||
prot, &address);
|
||||
|
||||
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
te = &env->tlb_table[mmu_idx][index];
|
||||
|
||||
/* do not discard the translation in te, evict it into a victim tlb */
|
||||
env->tlb_v_table[mmu_idx][vidx] = *te;
|
||||
env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index];
|
||||
|
||||
/* refill the tlb */
|
||||
env->iotlb[mmu_idx][index] = iotlb - vaddr;
|
||||
te->addend = addend - vaddr;
|
||||
if (prot & PAGE_READ) {
|
||||
te->addr_read = address;
|
||||
} else {
|
||||
te->addr_read = -1;
|
||||
}
|
||||
|
||||
if (prot & PAGE_EXEC) {
|
||||
te->addr_code = code_address;
|
||||
} else {
|
||||
te->addr_code = -1;
|
||||
}
|
||||
if (prot & PAGE_WRITE) {
|
||||
if ((memory_region_is_ram(section->mr) && section->readonly)
|
||||
|| memory_region_is_romd(section->mr)) {
|
||||
/* Write access calls the I/O callback. */
|
||||
te->addr_write = address | TLB_MMIO;
|
||||
} else if (memory_region_is_ram(section->mr)
|
||||
&& cpu_physical_memory_is_clean(cpu->uc, section->mr->ram_addr
|
||||
+ xlat)) {
|
||||
te->addr_write = address | TLB_NOTDIRTY;
|
||||
} else {
|
||||
te->addr_write = address;
|
||||
}
|
||||
} else {
|
||||
te->addr_write = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE: this function can trigger an exception */
|
||||
/* NOTE2: the returned address is not exactly the physical address: it
|
||||
* is actually a ram_addr_t (in system mode; the user mode emulation
|
||||
* version of this function returns a guest virtual address).
|
||||
*/
|
||||
tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
{
|
||||
int mmu_idx, page_index, pd;
|
||||
void *p;
|
||||
MemoryRegion *mr;
|
||||
CPUState *cpu = ENV_GET_CPU(env1);
|
||||
|
||||
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
mmu_idx = cpu_mmu_index(env1);
|
||||
if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
|
||||
(addr & TARGET_PAGE_MASK))) {
|
||||
cpu_ldub_code(env1, addr);
|
||||
}
|
||||
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(cpu->as, pd);
|
||||
if (memory_region_is_unassigned(cpu->uc, mr)) {
|
||||
CPUClass *cc = CPU_GET_CLASS(env1->uc, cpu);
|
||||
|
||||
if (cc->do_unassigned_access) {
|
||||
cc->do_unassigned_access(cpu, addr, false, true, 0, 4);
|
||||
} else {
|
||||
//cpu_abort(cpu, "Trying to execute code outside RAM or ROM at 0x"
|
||||
// TARGET_FMT_lx "\n", addr); // qq
|
||||
env1->invalid_addr = addr;
|
||||
env1->invalid_error = UC_ERR_CODE_INVALID;
|
||||
return -1; // qq FIXME
|
||||
}
|
||||
}
|
||||
p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
|
||||
return qemu_ram_addr_from_host_nofail(cpu->uc, p);
|
||||
}
|
||||
|
||||
static ram_addr_t qemu_ram_addr_from_host_nofail(struct uc_struct *uc, void *ptr)
|
||||
{
|
||||
ram_addr_t ram_addr;
|
||||
|
||||
if (qemu_ram_addr_from_host(uc, ptr, &ram_addr) == NULL) {
|
||||
fprintf(stderr, "Bad ram pointer %p\n", ptr);
|
||||
abort();
|
||||
}
|
||||
return ram_addr;
|
||||
}
|
||||
|
||||
static void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
|
||||
{
|
||||
if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) {
|
||||
tlb_entry->addr_write = vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Our TLB does not support large pages, so remember the area covered by
|
||||
large pages and trigger a full TLB flush if these are invalidated. */
|
||||
static void tlb_add_large_page(CPUArchState *env, target_ulong vaddr,
|
||||
target_ulong size)
|
||||
{
|
||||
target_ulong mask = ~(size - 1);
|
||||
|
||||
if (env->tlb_flush_addr == (target_ulong)-1) {
|
||||
env->tlb_flush_addr = vaddr & mask;
|
||||
env->tlb_flush_mask = mask;
|
||||
return;
|
||||
}
|
||||
/* Extend the existing region to include the new page.
|
||||
This is a compromise between unnecessary flushes and the cost
|
||||
of maintaining a full variable size TLB. */
|
||||
mask &= env->tlb_flush_mask;
|
||||
while (((env->tlb_flush_addr ^ vaddr) & mask) != 0) {
|
||||
mask <<= 1;
|
||||
}
|
||||
env->tlb_flush_addr &= mask;
|
||||
env->tlb_flush_mask = mask;
|
||||
}
|
||||
|
||||
static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
|
||||
{
|
||||
return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0;
|
||||
}
|
||||
|
||||
|
||||
static void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
|
||||
{
|
||||
if (addr == (tlb_entry->addr_read &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
|
||||
addr == (tlb_entry->addr_write &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
|
||||
addr == (tlb_entry->addr_code &
|
||||
(TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
|
||||
memset(tlb_entry, -1, sizeof(*tlb_entry));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define MMUSUFFIX _mmu
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
||||
#undef MMUSUFFIX
|
||||
|
||||
#define MMUSUFFIX _cmmu
|
||||
#undef GETPC_ADJ
|
||||
#define GETPC_ADJ 0
|
||||
#undef GETRA
|
||||
#define GETRA() ((uintptr_t)0)
|
||||
#define SOFTMMU_CODE_ACCESS
|
||||
|
||||
#define SHIFT 0
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "softmmu_template.h"
|
||||
|
||||
#define SHIFT 3
|
||||
#include "softmmu_template.h"
|
6
qemu/default-configs/aarch64-softmmu.mak
Normal file
6
qemu/default-configs/aarch64-softmmu.mak
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Default configuration for aarch64-softmmu
|
||||
|
||||
# We support all the 32 bit boards so need all their config
|
||||
include arm-softmmu.mak
|
||||
|
||||
# Currently no 64-bit specific config requirements
|
17
qemu/default-configs/alpha-softmmu.mak
Normal file
17
qemu/default-configs/alpha-softmmu.mak
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Default configuration for alpha-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_IDE_CORE=y
|
||||
CONFIG_IDE_QDEV=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
90
qemu/default-configs/arm-softmmu.mak
Normal file
90
qemu/default-configs/arm-softmmu.mak
Normal file
|
@ -0,0 +1,90 @@
|
|||
# Default configuration for arm-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_VGA=y
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_NAND=y
|
||||
CONFIG_ECC=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_SD=y
|
||||
CONFIG_MAX7310=y
|
||||
CONFIG_WM8750=y
|
||||
CONFIG_TWL92230=y
|
||||
CONFIG_TSC2005=y
|
||||
CONFIG_LM832X=y
|
||||
CONFIG_TMP105=y
|
||||
CONFIG_STELLARIS=y
|
||||
CONFIG_STELLARIS_INPUT=y
|
||||
CONFIG_STELLARIS_ENET=y
|
||||
CONFIG_SSD0303=y
|
||||
CONFIG_SSD0323=y
|
||||
CONFIG_ADS7846=y
|
||||
CONFIG_MAX111X=y
|
||||
CONFIG_SSI=y
|
||||
CONFIG_SSI_SD=y
|
||||
CONFIG_SSI_M25P80=y
|
||||
CONFIG_LAN9118=y
|
||||
CONFIG_SMC91C111=y
|
||||
CONFIG_ALLWINNER_EMAC=y
|
||||
CONFIG_DS1338=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_MICRODRIVE=y
|
||||
CONFIG_USB_MUSB=y
|
||||
|
||||
CONFIG_ARM11MPCORE=y
|
||||
CONFIG_A9MPCORE=y
|
||||
CONFIG_A15MPCORE=y
|
||||
|
||||
CONFIG_ARM_GIC=y
|
||||
CONFIG_ARM_GIC_KVM=$(CONFIG_KVM)
|
||||
CONFIG_ARM_TIMER=y
|
||||
CONFIG_ARM_MPTIMER=y
|
||||
CONFIG_A9_GTIMER=y
|
||||
CONFIG_PL011=y
|
||||
CONFIG_PL022=y
|
||||
CONFIG_PL031=y
|
||||
CONFIG_PL041=y
|
||||
CONFIG_PL050=y
|
||||
CONFIG_PL061=y
|
||||
CONFIG_PL080=y
|
||||
CONFIG_PL110=y
|
||||
CONFIG_PL181=y
|
||||
CONFIG_PL190=y
|
||||
CONFIG_PL310=y
|
||||
CONFIG_PL330=y
|
||||
CONFIG_CADENCE=y
|
||||
CONFIG_XGMAC=y
|
||||
CONFIG_EXYNOS4=y
|
||||
CONFIG_PXA2XX=y
|
||||
CONFIG_BITBANG_I2C=y
|
||||
CONFIG_FRAMEBUFFER=y
|
||||
CONFIG_XILINX_SPIPS=y
|
||||
|
||||
CONFIG_ARM11SCU=y
|
||||
CONFIG_A9SCU=y
|
||||
CONFIG_DIGIC=y
|
||||
CONFIG_MARVELL_88W8618=y
|
||||
CONFIG_OMAP=y
|
||||
CONFIG_TSC210X=y
|
||||
CONFIG_BLIZZARD=y
|
||||
CONFIG_ONENAND=y
|
||||
CONFIG_TUSB6010=y
|
||||
CONFIG_IMX=y
|
||||
CONFIG_MAINSTONE=y
|
||||
CONFIG_NSERIES=y
|
||||
CONFIG_REALVIEW=y
|
||||
CONFIG_ZAURUS=y
|
||||
CONFIG_ZYNQ=y
|
||||
|
||||
CONFIG_VERSATILE_PCI=y
|
||||
CONFIG_VERSATILE_I2C=y
|
||||
|
||||
CONFIG_SDHCI=y
|
||||
CONFIG_INTEGRATOR_DEBUG=y
|
||||
|
||||
CONFIG_ALLWINNER_A10_PIT=y
|
||||
CONFIG_ALLWINNER_A10_PIC=y
|
||||
CONFIG_ALLWINNER_A10=y
|
6
qemu/default-configs/cris-softmmu.mak
Normal file
6
qemu/default-configs/cris-softmmu.mak
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Default configuration for cris-softmmu
|
||||
|
||||
CONFIG_ETRAXFS=y
|
||||
CONFIG_NAND=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI02=y
|
47
qemu/default-configs/i386-softmmu.mak
Normal file
47
qemu/default-configs/i386-softmmu.mak
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Default configuration for i386-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_VGA=y
|
||||
CONFIG_QXL=$(CONFIG_SPICE)
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_VMMOUSE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_HPET=y
|
||||
CONFIG_APPLESMC=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_PCI_HOTPLUG_OLD=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
CONFIG_ISA_DEBUG=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_VMPORT=y
|
||||
CONFIG_SGA=y
|
||||
CONFIG_LPC_ICH9=y
|
||||
CONFIG_PCI_Q35=y
|
||||
CONFIG_APIC=y
|
||||
CONFIG_IOAPIC=y
|
||||
CONFIG_ICC_BUS=y
|
||||
CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
10
qemu/default-configs/lm32-softmmu.mak
Normal file
10
qemu/default-configs/lm32-softmmu.mak
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Default configuration for lm32-softmmu
|
||||
|
||||
CONFIG_LM32=y
|
||||
CONFIG_MILKYMIST=y
|
||||
CONFIG_MILKYMIST_TMU2=$(CONFIG_GLX)
|
||||
CONFIG_FRAMEBUFFER=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_SD=y
|
6
qemu/default-configs/m68k-softmmu.mak
Normal file
6
qemu/default-configs/m68k-softmmu.mak
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Default configuration for m68k-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_COLDFIRE=y
|
||||
CONFIG_PTIMER=y
|
11
qemu/default-configs/microblaze-softmmu.mak
Normal file
11
qemu/default-configs/microblaze-softmmu.mak
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Default configuration for microblaze-softmmu
|
||||
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_AXI=y
|
||||
CONFIG_XILINX_SPI=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_SSI=y
|
||||
CONFIG_SSI_M25P80=y
|
11
qemu/default-configs/microblazeel-softmmu.mak
Normal file
11
qemu/default-configs/microblazeel-softmmu.mak
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Default configuration for microblazeel-softmmu
|
||||
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_AXI=y
|
||||
CONFIG_XILINX_SPI=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_SSI=y
|
||||
CONFIG_SSI_M25P80=y
|
36
qemu/default-configs/mips-softmmu.mak
Normal file
36
qemu/default-configs/mips-softmmu.mak
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Default configuration for mips-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_PIIX4=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
36
qemu/default-configs/mips64-softmmu.mak
Normal file
36
qemu/default-configs/mips64-softmmu.mak
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Default configuration for mips64-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_PIIX4=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
39
qemu/default-configs/mips64el-softmmu.mak
Normal file
39
qemu/default-configs/mips64el-softmmu.mak
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Default configuration for mips64el-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_PIIX4=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_IDE_VIA=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_FULONG=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_VT82C686=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
36
qemu/default-configs/mipsel-softmmu.mak
Normal file
36
qemu/default-configs/mipsel-softmmu.mak
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Default configuration for mipsel-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ESP=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_ISA_MM=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_PIIX4=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_RC4030=y
|
||||
CONFIG_DP8393X=y
|
||||
CONFIG_DS1225Y=y
|
||||
CONFIG_MIPSNET=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_G364FB=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_JAZZ_LED=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_EMPTY_SLOT=y
|
5
qemu/default-configs/moxie-softmmu.mak
Normal file
5
qemu/default-configs/moxie-softmmu.mak
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Default configuration for moxie-softmmu
|
||||
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_VGA=y
|
4
qemu/default-configs/or32-softmmu.mak
Normal file
4
qemu/default-configs/or32-softmmu.mak
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Default configuration for or32-softmmu
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_OPENCORES_ETH=y
|
32
qemu/default-configs/pci.mak
Normal file
32
qemu/default-configs/pci.mak
Normal file
|
@ -0,0 +1,32 @@
|
|||
CONFIG_PCI=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_USB_UHCI=y
|
||||
CONFIG_USB_OHCI=y
|
||||
CONFIG_USB_EHCI=y
|
||||
CONFIG_USB_XHCI=y
|
||||
CONFIG_NE2000_PCI=y
|
||||
CONFIG_EEPRO100_PCI=y
|
||||
CONFIG_PCNET_PCI=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
CONFIG_AC97=y
|
||||
CONFIG_HDA=y
|
||||
CONFIG_ES1370=y
|
||||
CONFIG_LSI_SCSI_PCI=y
|
||||
CONFIG_VMW_PVSCSI_SCSI_PCI=y
|
||||
CONFIG_MEGASAS_SCSI_PCI=y
|
||||
CONFIG_RTL8139_PCI=y
|
||||
CONFIG_E1000_PCI=y
|
||||
CONFIG_VMXNET3_PCI=y
|
||||
CONFIG_IDE_CORE=y
|
||||
CONFIG_IDE_QDEV=y
|
||||
CONFIG_IDE_PCI=y
|
||||
CONFIG_AHCI=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_ESP_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_SERIAL_PCI=y
|
||||
CONFIG_IPACK=y
|
||||
CONFIG_WDT_IB6300ESB=y
|
||||
CONFIG_PCI_TESTDEV=y
|
||||
CONFIG_NVME_PCI=y
|
52
qemu/default-configs/ppc-softmmu.mak
Normal file
52
qemu/default-configs/ppc-softmmu.mak
Normal file
|
@ -0,0 +1,52 @@
|
|||
# Default configuration for ppc-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PREP_PCI=y
|
||||
CONFIG_I82378=y
|
||||
CONFIG_PC87312=y
|
||||
CONFIG_MACIO=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_CUDA=y
|
||||
CONFIG_ADB=y
|
||||
CONFIG_MAC_NVRAM=y
|
||||
CONFIG_MAC_DBDMA=y
|
||||
CONFIG_HEATHROW_PIC=y
|
||||
CONFIG_GRACKLE_PCI=y
|
||||
CONFIG_UNIN_PCI=y
|
||||
CONFIG_DEC_PCI=y
|
||||
CONFIG_PPCE500_PCI=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_IDE_MACIO=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PREP=y
|
||||
CONFIG_MAC=y
|
||||
CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
# For PReP
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
62
qemu/default-configs/ppc64-softmmu.mak
Normal file
62
qemu/default-configs/ppc64-softmmu.mak
Normal file
|
@ -0,0 +1,62 @@
|
|||
# Default configuration for ppc64-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PREP_PCI=y
|
||||
CONFIG_I82378=y
|
||||
CONFIG_PC87312=y
|
||||
CONFIG_MACIO=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_CUDA=y
|
||||
CONFIG_ADB=y
|
||||
CONFIG_MAC_NVRAM=y
|
||||
CONFIG_MAC_DBDMA=y
|
||||
CONFIG_HEATHROW_PIC=y
|
||||
CONFIG_GRACKLE_PCI=y
|
||||
CONFIG_UNIN_PCI=y
|
||||
CONFIG_DEC_PCI=y
|
||||
CONFIG_PPCE500_PCI=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_IDE_MACIO=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PSERIES=y
|
||||
CONFIG_PREP=y
|
||||
CONFIG_MAC=y
|
||||
CONFIG_E500=y
|
||||
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
|
||||
CONFIG_ETSEC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
||||
# For pSeries
|
||||
CONFIG_XICS=$(CONFIG_PSERIES)
|
||||
CONFIG_XICS_KVM=$(and $(CONFIG_PSERIES),$(CONFIG_KVM))
|
||||
# For PReP
|
||||
CONFIG_I82378=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
19
qemu/default-configs/ppcemb-softmmu.mak
Normal file
19
qemu/default-configs/ppcemb-softmmu.mak
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Default configuration for ppcemb-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_XILINX=y
|
||||
CONFIG_XILINX_ETHLITE=y
|
||||
CONFIG_OPENPIC=y
|
||||
CONFIG_LIBDECNUMBER=y
|
4
qemu/default-configs/s390x-softmmu.mak
Normal file
4
qemu/default-configs/s390x-softmmu.mak
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
18
qemu/default-configs/sh4-softmmu.mak
Normal file
18
qemu/default-configs/sh4-softmmu.mak
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Default configuration for sh4-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_SH4=y
|
||||
CONFIG_IDE_MMIO=y
|
||||
CONFIG_SM501=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_I82378=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_MC146818RTC=y
|
18
qemu/default-configs/sh4eb-softmmu.mak
Normal file
18
qemu/default-configs/sh4eb-softmmu.mak
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Default configuration for sh4eb-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PFLASH_CFI02=y
|
||||
CONFIG_SH4=y
|
||||
CONFIG_IDE_MMIO=y
|
||||
CONFIG_SM501=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_I82378=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_I82374=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_MC146818RTC=y
|
4
qemu/default-configs/sound.mak
Normal file
4
qemu/default-configs/sound.mak
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_SB16=y
|
||||
CONFIG_ADLIB=y
|
||||
CONFIG_GUS=y
|
||||
CONFIG_CS4231A=y
|
19
qemu/default-configs/sparc-softmmu.mak
Normal file
19
qemu/default-configs/sparc-softmmu.mak
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Default configuration for sparc-softmmu
|
||||
|
||||
CONFIG_ECC=y
|
||||
CONFIG_ESP=y
|
||||
CONFIG_ESCC=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
CONFIG_LANCE=y
|
||||
CONFIG_TCX=y
|
||||
CONFIG_CG3=y
|
||||
CONFIG_SLAVIO=y
|
||||
CONFIG_CS4231=y
|
||||
CONFIG_GRLIB=y
|
||||
CONFIG_STP2000=y
|
||||
CONFIG_ECCMEMCTL=y
|
||||
CONFIG_SUN4M=y
|
18
qemu/default-configs/sparc64-softmmu.mak
Normal file
18
qemu/default-configs/sparc64-softmmu.mak
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Default configuration for sparc64-softmmu
|
||||
|
||||
include pci.mak
|
||||
include usb.mak
|
||||
CONFIG_ISA_MMIO=y
|
||||
CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_VGA=y
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_CMD646=y
|
||||
CONFIG_PCI_APB=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_ISA_TESTDEV=y
|
0
qemu/default-configs/tricore-softmmu.mak
Normal file
0
qemu/default-configs/tricore-softmmu.mak
Normal file
4
qemu/default-configs/unicore32-softmmu.mak
Normal file
4
qemu/default-configs/unicore32-softmmu.mak
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Default configuration for unicore32-softmmu
|
||||
CONFIG_PUV3=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_PCKBD=y
|
9
qemu/default-configs/usb.mak
Normal file
9
qemu/default-configs/usb.mak
Normal file
|
@ -0,0 +1,9 @@
|
|||
CONFIG_USB_TABLET_WACOM=y
|
||||
CONFIG_USB_STORAGE_BOT=y
|
||||
CONFIG_USB_STORAGE_UAS=y
|
||||
CONFIG_USB_STORAGE_MTP=y
|
||||
CONFIG_USB_SMARTCARD=y
|
||||
CONFIG_USB_AUDIO=y
|
||||
CONFIG_USB_SERIAL=y
|
||||
CONFIG_USB_NETWORK=y
|
||||
CONFIG_USB_BLUETOOTH=y
|
47
qemu/default-configs/x86_64-softmmu.mak
Normal file
47
qemu/default-configs/x86_64-softmmu.mak
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Default configuration for x86_64-softmmu
|
||||
|
||||
include pci.mak
|
||||
include sound.mak
|
||||
include usb.mak
|
||||
CONFIG_VGA=y
|
||||
CONFIG_QXL=$(CONFIG_SPICE)
|
||||
CONFIG_VGA_PCI=y
|
||||
CONFIG_VGA_ISA=y
|
||||
CONFIG_VGA_CIRRUS=y
|
||||
CONFIG_VMWARE_VGA=y
|
||||
CONFIG_VMMOUSE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_PARALLEL=y
|
||||
CONFIG_I8254=y
|
||||
CONFIG_PCSPK=y
|
||||
CONFIG_PCKBD=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_APM=y
|
||||
CONFIG_I8257=y
|
||||
CONFIG_IDE_ISA=y
|
||||
CONFIG_IDE_PIIX=y
|
||||
CONFIG_NE2000_ISA=y
|
||||
CONFIG_PIIX_PCI=y
|
||||
CONFIG_HPET=y
|
||||
CONFIG_APPLESMC=y
|
||||
CONFIG_I8259=y
|
||||
CONFIG_PFLASH_CFI01=y
|
||||
CONFIG_TPM_TIS=$(CONFIG_TPM)
|
||||
CONFIG_PCI_HOTPLUG_OLD=y
|
||||
CONFIG_MC146818RTC=y
|
||||
CONFIG_PAM=y
|
||||
CONFIG_PCI_PIIX=y
|
||||
CONFIG_WDT_IB700=y
|
||||
CONFIG_XEN_I386=$(CONFIG_XEN)
|
||||
CONFIG_ISA_DEBUG=y
|
||||
CONFIG_ISA_TESTDEV=y
|
||||
CONFIG_VMPORT=y
|
||||
CONFIG_SGA=y
|
||||
CONFIG_LPC_ICH9=y
|
||||
CONFIG_PCI_Q35=y
|
||||
CONFIG_APIC=y
|
||||
CONFIG_IOAPIC=y
|
||||
CONFIG_ICC_BUS=y
|
||||
CONFIG_PVPANIC=y
|
||||
CONFIG_MEM_HOTPLUG=y
|
5
qemu/default-configs/xtensa-softmmu.mak
Normal file
5
qemu/default-configs/xtensa-softmmu.mak
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Default configuration for Xtensa
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_OPENCORES_ETH=y
|
||||
CONFIG_PFLASH_CFI01=y
|
5
qemu/default-configs/xtensaeb-softmmu.mak
Normal file
5
qemu/default-configs/xtensaeb-softmmu.mak
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Default configuration for Xtensa
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_OPENCORES_ETH=y
|
||||
CONFIG_PFLASH_CFI01=y
|
104
qemu/docs/aio_notify.promela
Normal file
104
qemu/docs/aio_notify.promela
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This model describes the interaction between aio_set_dispatching()
|
||||
* and aio_notify().
|
||||
*
|
||||
* Author: Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This file is in the public domain. If you really want a license,
|
||||
* the WTFPL will do.
|
||||
*
|
||||
* To simulate it:
|
||||
* spin -p docs/aio_notify.promela
|
||||
*
|
||||
* To verify it:
|
||||
* spin -a docs/aio_notify.promela
|
||||
* gcc -O2 pan.c
|
||||
* ./a.out -a
|
||||
*/
|
||||
|
||||
#define MAX 4
|
||||
#define LAST (1 << (MAX - 1))
|
||||
#define FINAL ((LAST << 1) - 1)
|
||||
|
||||
bool dispatching;
|
||||
bool event;
|
||||
|
||||
int req, done;
|
||||
|
||||
active proctype waiter()
|
||||
{
|
||||
int fetch, blocking;
|
||||
|
||||
do
|
||||
:: done != FINAL -> {
|
||||
// Computing "blocking" is separate from execution of the
|
||||
// "bottom half"
|
||||
blocking = (req == 0);
|
||||
|
||||
// This is our "bottom half"
|
||||
atomic { fetch = req; req = 0; }
|
||||
done = done | fetch;
|
||||
|
||||
// Wait for a nudge from the other side
|
||||
do
|
||||
:: event == 1 -> { event = 0; break; }
|
||||
:: !blocking -> break;
|
||||
od;
|
||||
|
||||
dispatching = 1;
|
||||
|
||||
// If you are simulating this model, you may want to add
|
||||
// something like this here:
|
||||
//
|
||||
// int foo; foo++; foo++; foo++;
|
||||
//
|
||||
// This only wastes some time and makes it more likely
|
||||
// that the notifier process hits the "fast path".
|
||||
|
||||
dispatching = 0;
|
||||
}
|
||||
:: else -> break;
|
||||
od
|
||||
}
|
||||
|
||||
active proctype notifier()
|
||||
{
|
||||
int next = 1;
|
||||
int sets = 0;
|
||||
|
||||
do
|
||||
:: next <= LAST -> {
|
||||
// generate a request
|
||||
req = req | next;
|
||||
next = next << 1;
|
||||
|
||||
// aio_notify
|
||||
if
|
||||
:: dispatching == 0 -> sets++; event = 1;
|
||||
:: else -> skip;
|
||||
fi;
|
||||
|
||||
// Test both synchronous and asynchronous delivery
|
||||
if
|
||||
:: 1 -> do
|
||||
:: req == 0 -> break;
|
||||
od;
|
||||
:: 1 -> skip;
|
||||
fi;
|
||||
}
|
||||
:: else -> break;
|
||||
od;
|
||||
printf("Skipped %d event_notifier_set\n", MAX - sets);
|
||||
}
|
||||
|
||||
#define p (done == FINAL)
|
||||
|
||||
never {
|
||||
do
|
||||
:: 1 // after an arbitrarily long prefix
|
||||
:: p -> break // p becomes true
|
||||
od;
|
||||
do
|
||||
:: !p -> accept: break // it then must remains true forever after
|
||||
od
|
||||
}
|
352
qemu/docs/atomics.txt
Normal file
352
qemu/docs/atomics.txt
Normal file
|
@ -0,0 +1,352 @@
|
|||
CPUs perform independent memory operations effectively in random order.
|
||||
but this can be a problem for CPU-CPU interaction (including interactions
|
||||
between QEMU and the guest). Multi-threaded programs use various tools
|
||||
to instruct the compiler and the CPU to restrict the order to something
|
||||
that is consistent with the expectations of the programmer.
|
||||
|
||||
The most basic tool is locking. Mutexes, condition variables and
|
||||
semaphores are used in QEMU, and should be the default approach to
|
||||
synchronization. Anything else is considerably harder, but it's
|
||||
also justified more often than one would like. The two tools that
|
||||
are provided by qemu/atomic.h are memory barriers and atomic operations.
|
||||
|
||||
Macros defined by qemu/atomic.h fall in three camps:
|
||||
|
||||
- compiler barriers: barrier();
|
||||
|
||||
- weak atomic access and manual memory barriers: atomic_read(),
|
||||
atomic_set(), smp_rmb(), smp_wmb(), smp_mb(), smp_read_barrier_depends();
|
||||
|
||||
- sequentially consistent atomic access: everything else.
|
||||
|
||||
|
||||
COMPILER MEMORY BARRIER
|
||||
=======================
|
||||
|
||||
barrier() prevents the compiler from moving the memory accesses either
|
||||
side of it to the other side. The compiler barrier has no direct effect
|
||||
on the CPU, which may then reorder things however it wishes.
|
||||
|
||||
barrier() is mostly used within qemu/atomic.h itself. On some
|
||||
architectures, CPU guarantees are strong enough that blocking compiler
|
||||
optimizations already ensures the correct order of execution. In this
|
||||
case, qemu/atomic.h will reduce stronger memory barriers to simple
|
||||
compiler barriers.
|
||||
|
||||
Still, barrier() can be useful when writing code that can be interrupted
|
||||
by signal handlers.
|
||||
|
||||
|
||||
SEQUENTIALLY CONSISTENT ATOMIC ACCESS
|
||||
=====================================
|
||||
|
||||
Most of the operations in the qemu/atomic.h header ensure *sequential
|
||||
consistency*, where "the result of any execution is the same as if the
|
||||
operations of all the processors were executed in some sequential order,
|
||||
and the operations of each individual processor appear in this sequence
|
||||
in the order specified by its program".
|
||||
|
||||
qemu/atomic.h provides the following set of atomic read-modify-write
|
||||
operations:
|
||||
|
||||
void atomic_inc(ptr)
|
||||
void atomic_dec(ptr)
|
||||
void atomic_add(ptr, val)
|
||||
void atomic_sub(ptr, val)
|
||||
void atomic_and(ptr, val)
|
||||
void atomic_or(ptr, val)
|
||||
|
||||
typeof(*ptr) atomic_fetch_inc(ptr)
|
||||
typeof(*ptr) atomic_fetch_dec(ptr)
|
||||
typeof(*ptr) atomic_fetch_add(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_sub(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_and(ptr, val)
|
||||
typeof(*ptr) atomic_fetch_or(ptr, val)
|
||||
typeof(*ptr) atomic_xchg(ptr, val
|
||||
typeof(*ptr) atomic_cmpxchg(ptr, old, new)
|
||||
|
||||
all of which return the old value of *ptr. These operations are
|
||||
polymorphic; they operate on any type that is as wide as an int.
|
||||
|
||||
Sequentially consistent loads and stores can be done using:
|
||||
|
||||
atomic_fetch_add(ptr, 0) for loads
|
||||
atomic_xchg(ptr, val) for stores
|
||||
|
||||
However, they are quite expensive on some platforms, notably POWER and
|
||||
ARM. Therefore, qemu/atomic.h provides two primitives with slightly
|
||||
weaker constraints:
|
||||
|
||||
typeof(*ptr) atomic_mb_read(ptr)
|
||||
void atomic_mb_set(ptr, val)
|
||||
|
||||
The semantics of these primitives map to Java volatile variables,
|
||||
and are strongly related to memory barriers as used in the Linux
|
||||
kernel (see below).
|
||||
|
||||
As long as you use atomic_mb_read and atomic_mb_set, accesses cannot
|
||||
be reordered with each other, and it is also not possible to reorder
|
||||
"normal" accesses around them.
|
||||
|
||||
However, and this is the important difference between
|
||||
atomic_mb_read/atomic_mb_set and sequential consistency, it is important
|
||||
for both threads to access the same volatile variable. It is not the
|
||||
case that everything visible to thread A when it writes volatile field f
|
||||
becomes visible to thread B after it reads volatile field g. The store
|
||||
and load have to "match" (i.e., be performed on the same volatile
|
||||
field) to achieve the right semantics.
|
||||
|
||||
|
||||
These operations operate on any type that is as wide as an int or smaller.
|
||||
|
||||
|
||||
WEAK ATOMIC ACCESS AND MANUAL MEMORY BARRIERS
|
||||
=============================================
|
||||
|
||||
Compared to sequentially consistent atomic access, programming with
|
||||
weaker consistency models can be considerably more complicated.
|
||||
In general, if the algorithm you are writing includes both writes
|
||||
and reads on the same side, it is generally simpler to use sequentially
|
||||
consistent primitives.
|
||||
|
||||
When using this model, variables are accessed with atomic_read() and
|
||||
atomic_set(), and restrictions to the ordering of accesses is enforced
|
||||
using the smp_rmb(), smp_wmb(), smp_mb() and smp_read_barrier_depends()
|
||||
memory barriers.
|
||||
|
||||
atomic_read() and atomic_set() prevents the compiler from using
|
||||
optimizations that might otherwise optimize accesses out of existence
|
||||
on the one hand, or that might create unsolicited accesses on the other.
|
||||
In general this should not have any effect, because the same compiler
|
||||
barriers are already implied by memory barriers. However, it is useful
|
||||
to do so, because it tells readers which variables are shared with
|
||||
other threads, and which are local to the current thread or protected
|
||||
by other, more mundane means.
|
||||
|
||||
Memory barriers control the order of references to shared memory.
|
||||
They come in four kinds:
|
||||
|
||||
- smp_rmb() guarantees that all the LOAD operations specified before
|
||||
the barrier will appear to happen before all the LOAD operations
|
||||
specified after the barrier with respect to the other components of
|
||||
the system.
|
||||
|
||||
In other words, smp_rmb() puts a partial ordering on loads, but is not
|
||||
required to have any effect on stores.
|
||||
|
||||
- smp_wmb() guarantees that all the STORE operations specified before
|
||||
the barrier will appear to happen before all the STORE operations
|
||||
specified after the barrier with respect to the other components of
|
||||
the system.
|
||||
|
||||
In other words, smp_wmb() puts a partial ordering on stores, but is not
|
||||
required to have any effect on loads.
|
||||
|
||||
- smp_mb() guarantees that all the LOAD and STORE operations specified
|
||||
before the barrier will appear to happen before all the LOAD and
|
||||
STORE operations specified after the barrier with respect to the other
|
||||
components of the system.
|
||||
|
||||
smp_mb() puts a partial ordering on both loads and stores. It is
|
||||
stronger than both a read and a write memory barrier; it implies both
|
||||
smp_rmb() and smp_wmb(), but it also prevents STOREs coming before the
|
||||
barrier from overtaking LOADs coming after the barrier and vice versa.
|
||||
|
||||
- smp_read_barrier_depends() is a weaker kind of read barrier. On
|
||||
most processors, whenever two loads are performed such that the
|
||||
second depends on the result of the first (e.g., the first load
|
||||
retrieves the address to which the second load will be directed),
|
||||
the processor will guarantee that the first LOAD will appear to happen
|
||||
before the second with respect to the other components of the system.
|
||||
However, this is not always true---for example, it was not true on
|
||||
Alpha processors. Whenever this kind of access happens to shared
|
||||
memory (that is not protected by a lock), a read barrier is needed,
|
||||
and smp_read_barrier_depends() can be used instead of smp_rmb().
|
||||
|
||||
Note that the first load really has to have a _data_ dependency and not
|
||||
a control dependency. If the address for the second load is dependent
|
||||
on the first load, but the dependency is through a conditional rather
|
||||
than actually loading the address itself, then it's a _control_
|
||||
dependency and a full read barrier or better is required.
|
||||
|
||||
|
||||
This is the set of barriers that is required *between* two atomic_read()
|
||||
and atomic_set() operations to achieve sequential consistency:
|
||||
|
||||
| 2nd operation |
|
||||
|-----------------------------------------|
|
||||
1st operation | (after last) | atomic_read | atomic_set |
|
||||
---------------+--------------+-------------+------------|
|
||||
(before first) | | none | smp_wmb() |
|
||||
---------------+--------------+-------------+------------|
|
||||
atomic_read | smp_rmb() | smp_rmb()* | ** |
|
||||
---------------+--------------+-------------+------------|
|
||||
atomic_set | none | smp_mb()*** | smp_wmb() |
|
||||
---------------+--------------+-------------+------------|
|
||||
|
||||
* Or smp_read_barrier_depends().
|
||||
|
||||
** This requires a load-store barrier. How to achieve this varies
|
||||
depending on the machine, but in practice smp_rmb()+smp_wmb()
|
||||
should have the desired effect. For example, on PowerPC the
|
||||
lwsync instruction is a combined load-load, load-store and
|
||||
store-store barrier.
|
||||
|
||||
*** This requires a store-load barrier. On most machines, the only
|
||||
way to achieve this is a full barrier.
|
||||
|
||||
|
||||
You can see that the two possible definitions of atomic_mb_read()
|
||||
and atomic_mb_set() are the following:
|
||||
|
||||
1) atomic_mb_read(p) = atomic_read(p); smp_rmb()
|
||||
atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v); smp_mb()
|
||||
|
||||
2) atomic_mb_read(p) = smp_mb() atomic_read(p); smp_rmb()
|
||||
atomic_mb_set(p, v) = smp_wmb(); atomic_set(p, v);
|
||||
|
||||
Usually the former is used, because smp_mb() is expensive and a program
|
||||
normally has more reads than writes. Therefore it makes more sense to
|
||||
make atomic_mb_set() the more expensive operation.
|
||||
|
||||
There are two common cases in which atomic_mb_read and atomic_mb_set
|
||||
generate too many memory barriers, and thus it can be useful to manually
|
||||
place barriers instead:
|
||||
|
||||
- when a data structure has one thread that is always a writer
|
||||
and one thread that is always a reader, manual placement of
|
||||
memory barriers makes the write side faster. Furthermore,
|
||||
correctness is easy to check for in this case using the "pairing"
|
||||
trick that is explained below:
|
||||
|
||||
thread 1 thread 1
|
||||
------------------------- ------------------------
|
||||
(other writes)
|
||||
smp_wmb()
|
||||
atomic_mb_set(&a, x) atomic_set(&a, x)
|
||||
smp_wmb()
|
||||
atomic_mb_set(&b, y) atomic_set(&b, y)
|
||||
|
||||
=>
|
||||
thread 2 thread 2
|
||||
------------------------- ------------------------
|
||||
y = atomic_mb_read(&b) y = atomic_read(&b)
|
||||
smp_rmb()
|
||||
x = atomic_mb_read(&a) x = atomic_read(&a)
|
||||
smp_rmb()
|
||||
|
||||
- sometimes, a thread is accessing many variables that are otherwise
|
||||
unrelated to each other (for example because, apart from the current
|
||||
thread, exactly one other thread will read or write each of these
|
||||
variables). In this case, it is possible to "hoist" the implicit
|
||||
barriers provided by atomic_mb_read() and atomic_mb_set() outside
|
||||
a loop. For example, the above definition atomic_mb_read() gives
|
||||
the following transformation:
|
||||
|
||||
n = 0; n = 0;
|
||||
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
|
||||
n += atomic_mb_read(&a[i]); n += atomic_read(&a[i]);
|
||||
smp_rmb();
|
||||
|
||||
Similarly, atomic_mb_set() can be transformed as follows:
|
||||
smp_mb():
|
||||
|
||||
smp_wmb();
|
||||
for (i = 0; i < 10; i++) => for (i = 0; i < 10; i++)
|
||||
atomic_mb_set(&a[i], false); atomic_set(&a[i], false);
|
||||
smp_mb();
|
||||
|
||||
|
||||
The two tricks can be combined. In this case, splitting a loop in
|
||||
two lets you hoist the barriers out of the loops _and_ eliminate the
|
||||
expensive smp_mb():
|
||||
|
||||
smp_wmb();
|
||||
for (i = 0; i < 10; i++) { => for (i = 0; i < 10; i++)
|
||||
atomic_mb_set(&a[i], false); atomic_set(&a[i], false);
|
||||
atomic_mb_set(&b[i], false); smb_wmb();
|
||||
} for (i = 0; i < 10; i++)
|
||||
atomic_set(&a[i], false);
|
||||
smp_mb();
|
||||
|
||||
The other thread can still use atomic_mb_read()/atomic_mb_set()
|
||||
|
||||
|
||||
Memory barrier pairing
|
||||
----------------------
|
||||
|
||||
A useful rule of thumb is that memory barriers should always, or almost
|
||||
always, be paired with another barrier. In the case of QEMU, however,
|
||||
note that the other barrier may actually be in a driver that runs in
|
||||
the guest!
|
||||
|
||||
For the purposes of pairing, smp_read_barrier_depends() and smp_rmb()
|
||||
both count as read barriers. A read barriers shall pair with a write
|
||||
barrier or a full barrier; a write barrier shall pair with a read
|
||||
barrier or a full barrier. A full barrier can pair with anything.
|
||||
For example:
|
||||
|
||||
thread 1 thread 2
|
||||
=============== ===============
|
||||
a = 1;
|
||||
smp_wmb();
|
||||
b = 2; x = b;
|
||||
smp_rmb();
|
||||
y = a;
|
||||
|
||||
Note that the "writing" thread are accessing the variables in the
|
||||
opposite order as the "reading" thread. This is expected: stores
|
||||
before the write barrier will normally match the loads after the
|
||||
read barrier, and vice versa. The same is true for more than 2
|
||||
access and for data dependency barriers:
|
||||
|
||||
thread 1 thread 2
|
||||
=============== ===============
|
||||
b[2] = 1;
|
||||
smp_wmb();
|
||||
x->i = 2;
|
||||
smp_wmb();
|
||||
a = x; x = a;
|
||||
smp_read_barrier_depends();
|
||||
y = x->i;
|
||||
smp_read_barrier_depends();
|
||||
z = b[y];
|
||||
|
||||
smp_wmb() also pairs with atomic_mb_read(), and smp_rmb() also pairs
|
||||
with atomic_mb_set().
|
||||
|
||||
|
||||
COMPARISON WITH LINUX KERNEL MEMORY BARRIERS
|
||||
============================================
|
||||
|
||||
Here is a list of differences between Linux kernel atomic operations
|
||||
and memory barriers, and the equivalents in QEMU:
|
||||
|
||||
- atomic operations in Linux are always on a 32-bit int type and
|
||||
use a boxed atomic_t type; atomic operations in QEMU are polymorphic
|
||||
and use normal C types.
|
||||
|
||||
- atomic_read and atomic_set in Linux give no guarantee at all;
|
||||
atomic_read and atomic_set in QEMU include a compiler barrier
|
||||
(similar to the ACCESS_ONCE macro in Linux).
|
||||
|
||||
- most atomic read-modify-write operations in Linux return void;
|
||||
in QEMU, all of them return the old value of the variable.
|
||||
|
||||
- different atomic read-modify-write operations in Linux imply
|
||||
a different set of memory barriers; in QEMU, all of them enforce
|
||||
sequential consistency, which means they imply full memory barriers
|
||||
before and after the operation.
|
||||
|
||||
- Linux does not have an equivalent of atomic_mb_read() and
|
||||
atomic_mb_set(). In particular, note that set_mb() is a little
|
||||
weaker than atomic_mb_set().
|
||||
|
||||
|
||||
SOURCES
|
||||
=======
|
||||
|
||||
* Documentation/memory-barriers.txt from the Linux kernel
|
||||
|
||||
* "The JSR-133 Cookbook for Compiler Writers", available at
|
||||
http://g.oswego.edu/dl/jmm/cookbook.html
|
161
qemu/docs/blkdebug.txt
Normal file
161
qemu/docs/blkdebug.txt
Normal file
|
@ -0,0 +1,161 @@
|
|||
Block I/O error injection using blkdebug
|
||||
----------------------------------------
|
||||
Copyright (C) 2014 Red Hat Inc
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||
the COPYING file in the top-level directory.
|
||||
|
||||
The blkdebug block driver is a rule-based error injection engine. It can be
|
||||
used to exercise error code paths in block drivers including ENOSPC (out of
|
||||
space) and EIO.
|
||||
|
||||
This document gives an overview of the features available in blkdebug.
|
||||
|
||||
Background
|
||||
----------
|
||||
Block drivers have many error code paths that handle I/O errors. Image formats
|
||||
are especially complex since metadata I/O errors during cluster allocation or
|
||||
while updating tables happen halfway through request processing and require
|
||||
discipline to keep image files consistent.
|
||||
|
||||
Error injection allows test cases to trigger I/O errors at specific points.
|
||||
This way, all error paths can be tested to make sure they are correct.
|
||||
|
||||
Rules
|
||||
-----
|
||||
The blkdebug block driver takes a list of "rules" that tell the error injection
|
||||
engine when to fail an I/O request.
|
||||
|
||||
Each I/O request is evaluated against the rules. If a rule matches the request
|
||||
then its "action" is executed.
|
||||
|
||||
Rules can be placed in a configuration file; the configuration file
|
||||
follows the same .ini-like format used by QEMU's -readconfig option, and
|
||||
each section of the file represents a rule.
|
||||
|
||||
The following configuration file defines a single rule:
|
||||
|
||||
$ cat blkdebug.conf
|
||||
[inject-error]
|
||||
event = "read_aio"
|
||||
errno = "28"
|
||||
|
||||
This rule fails all aio read requests with ENOSPC (28). Note that the errno
|
||||
value depends on the host. On Linux, see
|
||||
/usr/include/asm-generic/errno-base.h for errno values.
|
||||
|
||||
Invoke QEMU as follows:
|
||||
|
||||
$ qemu-system-x86_64
|
||||
-drive if=none,cache=none,file=blkdebug:blkdebug.conf:test.img,id=drive0 \
|
||||
-device virtio-blk-pci,drive=drive0,id=virtio-blk-pci0
|
||||
|
||||
Rules support the following attributes:
|
||||
|
||||
event - which type of operation to match (e.g. read_aio, write_aio,
|
||||
flush_to_os, flush_to_disk). See the "Events" section for
|
||||
information on events.
|
||||
|
||||
state - (optional) the engine must be in this state number in order for this
|
||||
rule to match. See the "State transitions" section for information
|
||||
on states.
|
||||
|
||||
errno - the numeric errno value to return when a request matches this rule.
|
||||
The errno values depend on the host since the numeric values are not
|
||||
standarized in the POSIX specification.
|
||||
|
||||
sector - (optional) a sector number that the request must overlap in order to
|
||||
match this rule
|
||||
|
||||
once - (optional, default "off") only execute this action on the first
|
||||
matching request
|
||||
|
||||
immediately - (optional, default "off") return a NULL BlockAIOCB
|
||||
pointer and fail without an errno instead. This
|
||||
exercises the code path where BlockAIOCB fails and the
|
||||
caller's BlockCompletionFunc is not invoked.
|
||||
|
||||
Events
|
||||
------
|
||||
Block drivers provide information about the type of I/O request they are about
|
||||
to make so rules can match specific types of requests. For example, the qcow2
|
||||
block driver tells blkdebug when it accesses the L1 table so rules can match
|
||||
only L1 table accesses and not other metadata or guest data requests.
|
||||
|
||||
The core events are:
|
||||
|
||||
read_aio - guest data read
|
||||
|
||||
write_aio - guest data write
|
||||
|
||||
flush_to_os - write out unwritten block driver state (e.g. cached metadata)
|
||||
|
||||
flush_to_disk - flush the host block device's disk cache
|
||||
|
||||
See block/blkdebug.c:event_names[] for the full list of events. You may need
|
||||
to grep block driver source code to understand the meaning of specific events.
|
||||
|
||||
State transitions
|
||||
-----------------
|
||||
There are cases where more power is needed to match a particular I/O request in
|
||||
a longer sequence of requests. For example:
|
||||
|
||||
write_aio
|
||||
flush_to_disk
|
||||
write_aio
|
||||
|
||||
How do we match the 2nd write_aio but not the first? This is where state
|
||||
transitions come in.
|
||||
|
||||
The error injection engine has an integer called the "state" that always starts
|
||||
initialized to 1. The state integer is internal to blkdebug and cannot be
|
||||
observed from outside but rules can interact with it for powerful matching
|
||||
behavior.
|
||||
|
||||
Rules can be conditional on the current state and they can transition to a new
|
||||
state.
|
||||
|
||||
When a rule's "state" attribute is non-zero then the current state must equal
|
||||
the attribute in order for the rule to match.
|
||||
|
||||
For example, to match the 2nd write_aio:
|
||||
|
||||
[set-state]
|
||||
event = "write_aio"
|
||||
state = "1"
|
||||
new_state = "2"
|
||||
|
||||
[inject-error]
|
||||
event = "write_aio"
|
||||
state = "2"
|
||||
errno = "5"
|
||||
|
||||
The first write_aio request matches the set-state rule and transitions from
|
||||
state 1 to state 2. Once state 2 has been entered, the set-state rule no
|
||||
longer matches since it requires state 1. But the inject-error rule now
|
||||
matches the next write_aio request and injects EIO (5).
|
||||
|
||||
State transition rules support the following attributes:
|
||||
|
||||
event - which type of operation to match (e.g. read_aio, write_aio,
|
||||
flush_to_os, flush_to_disk). See the "Events" section for
|
||||
information on events.
|
||||
|
||||
state - (optional) the engine must be in this state number in order for this
|
||||
rule to match
|
||||
|
||||
new_state - transition to this state number
|
||||
|
||||
Suspend and resume
|
||||
------------------
|
||||
Exercising code paths in block drivers may require specific ordering amongst
|
||||
concurrent requests. The "breakpoint" feature allows requests to be halted on
|
||||
a blkdebug event and resumed later. This makes it possible to achieve
|
||||
deterministic ordering when multiple requests are in flight.
|
||||
|
||||
Breakpoints on blkdebug events are associated with a user-defined "tag" string.
|
||||
This tag serves as an identifier by which the request can be resumed at a later
|
||||
point.
|
||||
|
||||
See the qemu-io(1) break, resume, remove_break, and wait_break commands for
|
||||
details.
|
69
qemu/docs/blkverify.txt
Normal file
69
qemu/docs/blkverify.txt
Normal file
|
@ -0,0 +1,69 @@
|
|||
= Block driver correctness testing with blkverify =
|
||||
|
||||
== Introduction ==
|
||||
|
||||
This document describes how to use the blkverify protocol to test that a block
|
||||
driver is operating correctly.
|
||||
|
||||
It is difficult to test and debug block drivers against real guests. Often
|
||||
processes inside the guest will crash because corrupt sectors were read as part
|
||||
of the executable. Other times obscure errors are raised by a program inside
|
||||
the guest. These issues are extremely hard to trace back to bugs in the block
|
||||
driver.
|
||||
|
||||
Blkverify solves this problem by catching data corruption inside QEMU the first
|
||||
time bad data is read and reporting the disk sector that is corrupted.
|
||||
|
||||
== How it works ==
|
||||
|
||||
The blkverify protocol has two child block devices, the "test" device and the
|
||||
"raw" device. Read/write operations are mirrored to both devices so their
|
||||
state should always be in sync.
|
||||
|
||||
The "raw" device is a raw image, a flat file, that has identical starting
|
||||
contents to the "test" image. The idea is that the "raw" device will handle
|
||||
read/write operations correctly and not corrupt data. It can be used as a
|
||||
reference for comparison against the "test" device.
|
||||
|
||||
After a mirrored read operation completes, blkverify will compare the data and
|
||||
raise an error if it is not identical. This makes it possible to catch the
|
||||
first instance where corrupt data is read.
|
||||
|
||||
== Example ==
|
||||
|
||||
Imagine raw.img has 0xcd repeated throughout its first sector:
|
||||
|
||||
$ ./qemu-io -c 'read -v 0 512' raw.img
|
||||
00000000: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................
|
||||
00000010: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................
|
||||
[...]
|
||||
000001e0: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................
|
||||
000001f0: cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd cd ................
|
||||
read 512/512 bytes at offset 0
|
||||
512.000000 bytes, 1 ops; 0.0000 sec (97.656 MiB/sec and 200000.0000 ops/sec)
|
||||
|
||||
And test.img is corrupt, its first sector is zeroed when it shouldn't be:
|
||||
|
||||
$ ./qemu-io -c 'read -v 0 512' test.img
|
||||
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
[...]
|
||||
000001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
000001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
|
||||
read 512/512 bytes at offset 0
|
||||
512.000000 bytes, 1 ops; 0.0000 sec (81.380 MiB/sec and 166666.6667 ops/sec)
|
||||
|
||||
This error is caught by blkverify:
|
||||
|
||||
$ ./qemu-io -c 'read 0 512' blkverify:a.img:b.img
|
||||
blkverify: read sector_num=0 nb_sectors=4 contents mismatch in sector 0
|
||||
|
||||
A more realistic scenario is verifying the installation of a guest OS:
|
||||
|
||||
$ ./qemu-img create raw.img 16G
|
||||
$ ./qemu-img create -f qcow2 test.qcow2 16G
|
||||
$ x86_64-softmmu/qemu-system-x86_64 -cdrom debian.iso \
|
||||
-drive file=blkverify:raw.img:test.qcow2
|
||||
|
||||
If the installation is aborted when blkverify detects corruption, use qemu-io
|
||||
to explore the contents of the disk image at the sector in question.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue