Files
unicorn/bindings/python/tests/test_ctl.py
@Antelox 6fbbf3089a Python binding setup refactoring + cibuildwheel workflow (#2026)
* Python bindings: Make the test scripts handy for pytest

* Python bindings: Update MANIFEST.in with new paths

* Update .gitignore to exclude PyCharm-related files/folders

* Python bindings: Update CMakeLists.txt in order to set CMAKE_OSX_ARCHITECTURES var

* Python bindings:
- Moved project package settings to the new TOML format
- Refactored setup.py to cleanup/improve the code and make it ready for cibuildwheel
- Updated README.md with the package long description part
- Removed setup.cfg since universal wheel building will be deprecated soon

* Python bindings:
- Replaced old PyPI-publishing.yml workflow with brand-new one based on cibuildwheel
- Removed old building scripts

* Replaced macos-12 runner with macos-13 since it will be removed soon

* Python bindings: Specify SYSTEM_VERSION_COMPAT=0 env var for macos-13 x86_64 runner as per cibuildwheel warning message

* Python bindings: Enable i686 for debugging

* Python bindings: Enable DEBUG flag according to the presence of tag release

* Python bindings: Added matrix to cover i686 manylinux/musllinux builds

* Python bindings:
- Replaced macos-14 runner with macos-latest
- Bumped cibuildwheel GitHub action to 2.21.3 version

* Python bindings:
- Adapt test_uc_ctl_tb_cache test to the recent changes
- Fixed typos
- PEP8 fixes

* GitHub Action Workflow: Introduce BUILD_TYPE env var to select build type according to the presence of tag release

---------

Co-authored-by: mio <mio@lazym.io>
2024-10-17 19:35:42 +08:00

130 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python
# Sample code for Unicorn.
# By Lazymio(@wtdcode), 2021
from unicorn import *
from unicorn.x86_const import *
from datetime import datetime
def test_uc_ctl_read():
uc = Uc(UC_ARCH_X86, UC_MODE_32)
print("Reading some properties by uc_ctl.")
arch = uc.ctl_get_arch()
mode = uc.ctl_get_mode()
page_size = uc.ctl_get_page_size()
timeout = uc.ctl_get_timeout()
print(f">>> arch={arch} mode={mode} page size={page_size} timeout={timeout}")
def time_emulation(uc, start, end):
n = datetime.now()
uc.emu_start(start, end)
return (datetime.now() - n).total_seconds() * 1e6
def test_uc_ctl_tb_cache():
# Initialize emulator in X86-32bit mode
uc = Uc(UC_ARCH_X86, UC_MODE_32)
addr = 0x10000
# Fill the code buffer with NOP.
code = b"\x90" * 8 * 512
print("Controlling the TB cache in a finer granularity by uc_ctl.")
uc.mem_map(addr, 0x10000)
# Write our code to the memory.
uc.mem_write(addr, code)
# Do emulation without any cache.
standard = time_emulation(uc, addr, addr + len(code))
# Now we request cache for all TBs.
for i in range(8):
tb = uc.ctl_request_cache(addr + i * 512)
print(f">>> TB is cached at {hex(tb[0])} which has {tb[1]} instructions with {tb[2]} bytes")
# Do emulation with all TB cached.
cached = time_emulation(uc, addr, addr + len(code))
# Now we clear cache for all TBs.
for i in range(8):
uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1)
evicted = time_emulation(uc, addr, addr + len(code))
print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}")
def trace_new_edge(uc, cur, prev, data):
print(f">>> Getting a new edge from {hex(prev.pc + prev.size - 1)} to {hex(cur.pc)}")
def trace_tcg_sub(uc, address, arg1, arg2, size, data):
print(f">>> Get a tcg sub opcode at {hex(address)} with args: {arg1} and {arg2}")
def test_uc_ctl_exits():
uc = Uc(UC_ARCH_X86, UC_MODE_32)
addr = 0x1000
# cmp eax, 0;
# jg lb;
# inc eax;
# nop;
# lb:
# inc ebx;
# nop;
code = b"\x83\xf8\x00\x7f\x02\x40\x90\x43\x90"
exits = [addr + 6, addr + 8]
print("Using multiple exits by uc_ctl")
uc.mem_map(addr, 0x1000)
# Write our code to the memory.
uc.mem_write(addr, code)
# We trace if any new edge is generated.
uc.hook_add(UC_HOOK_EDGE_GENERATED, trace_new_edge)
# Trace cmp instruction.
uc.hook_add(UC_HOOK_TCG_OPCODE, trace_tcg_sub, aux1=UC_TCG_OP_SUB, aux2=UC_TCG_OP_FLAG_CMP)
uc.ctl_exits_enabled(True)
uc.ctl_set_exits(exits)
# This should stop at ADDRESS + 6 and increase eax, even though we don't provide an exit.
uc.emu_start(addr, 0)
eax = uc.reg_read(UC_X86_REG_EAX)
ebx = uc.reg_read(UC_X86_REG_EBX)
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
# This should stop at ADDRESS + 8, even though we don't provide an exit.
uc.emu_start(addr, 0)
eax = uc.reg_read(UC_X86_REG_EAX)
ebx = uc.reg_read(UC_X86_REG_EBX)
print(f">>> eax = {hex(eax)} and ebx = {hex(ebx)} after the first emulation")
if __name__ == "__main__":
test_uc_ctl_read()
print("=" * 32)
test_uc_ctl_tb_cache()
print("=" * 32)
test_uc_ctl_exits()