mirror of
https://github.com/capstone-engine/capstone
synced 2026-08-11 16:26:07 -04:00
Remove deprecated packaging and cython (#2400)
* Remove deprecated packaging and cython * Fix some issues after cherry-picking * Fix CI issues * Remove test files added for v6 * Also remove test_alpha.py
This commit is contained in:
parent
e90ef3928f
commit
1bd2a32f2a
38 changed files with 81 additions and 718 deletions
41
.github/workflows/CITest.yml
vendored
41
.github/workflows/CITest.yml
vendored
|
|
@ -1,10 +1,10 @@
|
|||
name: Run Test
|
||||
on:
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- ".gitignore"
|
||||
- "docs/**"
|
||||
- "ChangeLog"
|
||||
- "ChangeLog"
|
||||
- "CREDITS.TXT"
|
||||
- "COMPILE.TXT"
|
||||
- "COMPILE_MSVC.TXT"
|
||||
|
|
@ -30,46 +30,29 @@ jobs:
|
|||
matrix:
|
||||
config:
|
||||
- {
|
||||
name: 'ubuntu-20.04 x64 python3.6 cmake',
|
||||
os: ubuntu-20.04,
|
||||
name: 'ubuntu-22.04 x64 make',
|
||||
os: ubuntu-22.04,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-version: '3.6',
|
||||
build-system: 'cmake',
|
||||
build-system: 'make',
|
||||
}
|
||||
- {
|
||||
name: 'ubuntu-22.04 x64 python3.9 make',
|
||||
name: 'ubuntu-22.04 x64 cmake',
|
||||
os: ubuntu-22.04,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-version: '3.9',
|
||||
build-system: 'make',
|
||||
}
|
||||
- {
|
||||
name: 'ubuntu-22.04 x64 python3.9 cmake',
|
||||
os: ubuntu-22.04,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-version: '3.9',
|
||||
build-system: 'cmake',
|
||||
}
|
||||
enable-asan: 'OFF'
|
||||
}
|
||||
- {
|
||||
name: 'ubuntu-22.04 x64 python3.11 cmake',
|
||||
os: ubuntu-22.04,
|
||||
name: 'ubuntu-22.04 x64 ASAN',
|
||||
os: ubuntu-latest,
|
||||
arch: x64,
|
||||
python-arch: x64,
|
||||
python-version: '3.11',
|
||||
build-system: 'cmake',
|
||||
enable-asan: 'ON'
|
||||
}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.config.python-version }}
|
||||
|
||||
- name: prepare
|
||||
shell: 'script -q -e -c "bash {0}"'
|
||||
run: |
|
||||
|
|
@ -135,7 +118,7 @@ jobs:
|
|||
|
||||
- name: '🛠️ Win MSVC 64 setup'
|
||||
if: contains(matrix.config.name, 'MSVC 64')
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
arch: 'x64'
|
||||
|
||||
|
|
|
|||
2
.github/workflows/fuzz.yml
vendored
2
.github/workflows/fuzz.yml
vendored
|
|
@ -21,3 +21,5 @@ jobs:
|
|||
with:
|
||||
name: artifacts
|
||||
path: ./out/artifacts
|
||||
- name: Install Python Dependencies
|
||||
run: python -m pip install --upgrade setuptools build wheel
|
||||
|
|
|
|||
32
.github/workflows/python-tests.yml
vendored
Normal file
32
.github/workflows/python-tests.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: Python Package CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-2022, macOS-14]
|
||||
python-version: ["3.8", "3.12"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Setup MSVC
|
||||
if: runner.os == 'Windows'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: Build and install capstone
|
||||
run: pip install ./bindings/python
|
||||
|
||||
- name: Run tests
|
||||
run: python ./bindings/python/tests/test_all.py
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -25,6 +25,7 @@
|
|||
# python
|
||||
bindings/python/build/
|
||||
bindings/python/capstone.egg-info/
|
||||
bindings/cython/capstone.egg-info/
|
||||
*.pyc
|
||||
|
||||
# java
|
||||
|
|
|
|||
|
|
@ -13,45 +13,7 @@
|
|||
|
||||
To control the install destination, set the DESTDIR environment variable.
|
||||
|
||||
2. For better Python performance, install cython-based binding with:
|
||||
|
||||
$ sudo make install_cython
|
||||
|
||||
Note that this requires Cython installed first. To install Cython, see
|
||||
below.
|
||||
|
||||
3. To install Cython, you have to ensure that the header files
|
||||
and the static library for Python are installed beforehand.
|
||||
|
||||
E.g. on Ubuntu, do:
|
||||
|
||||
$ sudo apt-get install python-dev
|
||||
|
||||
Depending on if you already have pip or easy_install installed, install
|
||||
Cython with either:
|
||||
|
||||
$ sudo pip install cython
|
||||
or:
|
||||
$ sudo easy_install cython
|
||||
|
||||
NOTE: Depending on your distribution you might also be able to
|
||||
install the required Cython version using your repository.
|
||||
|
||||
E.g. on Ubuntu, do:
|
||||
|
||||
$ sudo apt-get install cython
|
||||
|
||||
However, our cython-based binding requires Cython version 0.19 or newer,
|
||||
but sometimes distributions only provide older version. Make sure to
|
||||
verify the current installed version before going into section 2 above.
|
||||
|
||||
E.g, on Ubuntu, you can verify the current Cython version with:
|
||||
|
||||
$ apt-cache policy cython
|
||||
|
||||
Which should at least print version 0.19
|
||||
|
||||
4. This directory contains some test code to show how to use the Capstone API.
|
||||
2. The tests directory contains some test code to show how to use the Capstone API.
|
||||
|
||||
- test_basic.py
|
||||
This code shows the most simple form of API where we only want to get basic
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
PYTHON2 ?= python2
|
||||
PYTHON3 ?= python3
|
||||
|
||||
.PHONY: gen_const install install3 install_cython sdist sdist3 bdist bdist3 clean check
|
||||
.PHONY: gen_const install sdist bdist clean check
|
||||
|
||||
gen_const:
|
||||
cd .. && $(PYTHON2) const_generator.py python
|
||||
|
|
@ -22,23 +22,6 @@ install3:
|
|||
$(PYTHON3) setup.py build install; \
|
||||
fi
|
||||
|
||||
# NOTE: Newer cython can be installed by: sudo pip install --upgrade cython
|
||||
install_cython:
|
||||
rm -rf src/
|
||||
if test -n "${DESTDIR}"; then \
|
||||
$(PYTHON2) setup_cython.py build install --root="${DESTDIR}"; \
|
||||
else \
|
||||
$(PYTHON2) setup_cython.py build install; \
|
||||
fi
|
||||
|
||||
install3_cython:
|
||||
rm -rf src/
|
||||
if test -n "${DESTDIR}"; then \
|
||||
$(PYTHON3) setup_cython.py build install --root="${DESTDIR}"; \
|
||||
else \
|
||||
$(PYTHON3) setup_cython.py build install; \
|
||||
fi
|
||||
|
||||
# build & upload PyPi package with source code of the core
|
||||
sdist:
|
||||
rm -rf src/ dist/
|
||||
|
|
|
|||
|
|
@ -348,10 +348,16 @@ CS_OPT = {v:k for k,v in locals().items() if k.startswith('CS_OPT_')}
|
|||
|
||||
import ctypes, ctypes.util
|
||||
from os.path import split, join, dirname
|
||||
import distutils.sysconfig
|
||||
import pkg_resources
|
||||
import sysconfig
|
||||
from pathlib import PurePath
|
||||
|
||||
import inspect
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
import importlib.resources as resources
|
||||
else:
|
||||
import importlib_resources as resources
|
||||
|
||||
if not hasattr(sys.modules[__name__], '__file__'):
|
||||
__file__ = inspect.getfile(inspect.currentframe())
|
||||
|
||||
|
|
@ -379,17 +385,17 @@ _cs = None
|
|||
|
||||
# Loading attempts, in order
|
||||
# - user-provided environment variable
|
||||
# - pkg_resources can get us the path to the local libraries
|
||||
# - importlib.resources can get us the path to the local libraries
|
||||
# - we can get the path to the local libraries by parsing our filename
|
||||
# - global load
|
||||
# - python's lib directory
|
||||
# - last-gasp attempt at some hardcoded paths on darwin and linux
|
||||
|
||||
_path_list = [os.getenv('LIBCAPSTONE_PATH', None),
|
||||
pkg_resources.resource_filename(__name__, 'lib'),
|
||||
str(resources.files(__name__) / "lib"),
|
||||
join(split(__file__)[0], 'lib'),
|
||||
'',
|
||||
distutils.sysconfig.get_python_lib(),
|
||||
sysconfig.get_path('platlib'),
|
||||
"/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64']
|
||||
|
||||
for _path in _path_list:
|
||||
|
|
|
|||
3
bindings/python/pyproject.toml
Normal file
3
bindings/python/pyproject.toml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
|
@ -1 +0,0 @@
|
|||
This directory contains Cython files.
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
# By Dang Hoang Vu <danghvu@gmail.com>, 2014
|
||||
|
||||
from libcpp cimport bool
|
||||
from libc.stdint cimport uint8_t, uint64_t, uint16_t
|
||||
|
||||
cdef extern from "<capstone/capstone.h>":
|
||||
|
||||
ctypedef size_t csh
|
||||
|
||||
ctypedef enum cs_mode:
|
||||
pass
|
||||
|
||||
ctypedef enum cs_arch:
|
||||
pass
|
||||
|
||||
ctypedef struct cs_detail:
|
||||
pass
|
||||
|
||||
ctypedef struct cs_insn:
|
||||
unsigned int id
|
||||
uint64_t address
|
||||
uint16_t size
|
||||
uint8_t bytes[24]
|
||||
char mnemonic[32]
|
||||
char op_str[160]
|
||||
cs_detail *detail
|
||||
|
||||
ctypedef enum cs_err:
|
||||
pass
|
||||
|
||||
ctypedef enum cs_opt_type:
|
||||
pass
|
||||
|
||||
unsigned int cs_version(int *major, int *minor)
|
||||
|
||||
bool cs_support(int arch)
|
||||
|
||||
cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
|
||||
|
||||
cs_err cs_close(csh *handle)
|
||||
|
||||
cs_err cs_errno(csh handle)
|
||||
|
||||
size_t cs_disasm(csh handle,
|
||||
const uint8_t *code, size_t code_size,
|
||||
uint64_t address,
|
||||
size_t count,
|
||||
cs_insn **insn)
|
||||
|
||||
cs_err cs_option(csh handle, cs_opt_type type, size_t value)
|
||||
|
||||
void cs_free(cs_insn *insn, size_t count)
|
||||
|
||||
const char *cs_reg_name(csh handle, unsigned int reg_id)
|
||||
|
||||
const char *cs_insn_name(csh handle, unsigned int insn_id)
|
||||
|
||||
const char *cs_group_name(csh handle, unsigned int group_id)
|
||||
|
||||
bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
|
||||
|
||||
bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
|
||||
|
||||
bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
|
||||
|
||||
int cs_op_count(csh handle, cs_insn *insn, unsigned int op_type)
|
||||
|
||||
cs_err cs_regs_access(csh handle, cs_insn *insn, uint16_t *regs_read, uint8_t *read_count, uint16_t *regs_write, uint8_t *write_count)
|
||||
|
||||
int cs_op_index(csh handle, cs_insn *insn, unsigned int op_type,
|
||||
unsigned int position)
|
||||
|
||||
|
|
@ -1,386 +0,0 @@
|
|||
# By Dang Hoang Vu <danghvu@gmail.com>, 2014
|
||||
|
||||
cimport pyx.ccapstone as cc
|
||||
import capstone, ctypes
|
||||
from . import arm, x86, mips, ppc, arm64, sparc, systemz, xcore, tms320c64x, m68k, m680x, evm, mos65xx, wasm, bpf, riscv, sh, tricore, CsError
|
||||
|
||||
_diet = cc.cs_support(capstone.CS_SUPPORT_DIET)
|
||||
|
||||
|
||||
class CsDetail(object):
|
||||
|
||||
def __init__(self, arch, raw_detail = None):
|
||||
if not raw_detail:
|
||||
return
|
||||
detail = ctypes.cast(raw_detail, ctypes.POINTER(capstone._cs_detail)).contents
|
||||
|
||||
self.regs_read = detail.regs_read
|
||||
self.regs_read_count = detail.regs_read_count
|
||||
self.regs_write = detail.regs_write
|
||||
self.regs_write_count = detail.regs_write_count
|
||||
self.groups = detail.groups
|
||||
self.groups_count = detail.groups_count
|
||||
self.writeback = detail.writeback
|
||||
|
||||
if arch == capstone.CS_ARCH_ARM:
|
||||
(self.usermode, self.vector_size, self.vector_data, self.cps_mode, self.cps_flag, \
|
||||
self.cc, self.update_flags, self.writeback, self.post_index, self.mem_barrier, self.operands) = \
|
||||
arm.get_arch_info(detail.arch.arm)
|
||||
elif arch == capstone.CS_ARCH_ARM64:
|
||||
(self.cc, self.update_flags, self.writeback, self.post_index, self.operands) = \
|
||||
arm64.get_arch_info(detail.arch.arm64)
|
||||
elif arch == capstone.CS_ARCH_X86:
|
||||
(self.prefix, self.opcode, self.rex, self.addr_size, \
|
||||
self.modrm, self.sib, self.disp, \
|
||||
self.sib_index, self.sib_scale, self.sib_base, \
|
||||
self.xop_cc, self.sse_cc, self.avx_cc, self.avx_sae, self.avx_rm, \
|
||||
self.eflags, self.fpu_flags, self.encoding, self.modrm_offset, self.disp_offset, \
|
||||
self.disp_size, self.imm_offset, self.imm_size, self.operands) = x86.get_arch_info(detail.arch.x86)
|
||||
elif arch == capstone.CS_ARCH_M68K:
|
||||
(self.operands, self.op_size) = m68k.get_arch_info(detail.arch.m68k)
|
||||
elif arch == capstone.CS_ARCH_MIPS:
|
||||
self.operands = mips.get_arch_info(detail.arch.mips)
|
||||
elif arch == capstone.CS_ARCH_PPC:
|
||||
(self.bc, self.bh, self.update_cr0, self.operands) = \
|
||||
ppc.get_arch_info(detail.arch.ppc)
|
||||
elif arch == capstone.CS_ARCH_SPARC:
|
||||
(self.cc, self.hint, self.operands) = sparc.get_arch_info(detail.arch.sparc)
|
||||
elif arch == capstone.CS_ARCH_SYSZ:
|
||||
(self.cc, self.operands) = systemz.get_arch_info(detail.arch.sysz)
|
||||
elif arch == capstone.CS_ARCH_XCORE:
|
||||
self.operands = xcore.get_arch_info(detail.arch.xcore)
|
||||
elif arch == capstone.CS_ARCH_TMS320C64X:
|
||||
(self.condition, self.funit, self.parallel, self.operands) = tms320c64x.get_arch_info(self._detail.arch.tms320c64x)
|
||||
elif arch == capstone.CS_ARCH_M680X:
|
||||
(self.flags, self.operands) = m680x.get_arch_info(detail.arch.m680x)
|
||||
elif arch == capstone.CS_ARCH_EVM:
|
||||
(self.pop, self.push, self.fee) = evm.get_arch_info(detail.arch.evm)
|
||||
elif arch == capstone.CS_ARCH_MOS65XX:
|
||||
(self.am, self.modifies_flags, self.operands) = mos65xx.get_arch_info(detail.arch.mos65xx)
|
||||
elif arch == capstone.CS_ARCH_WASM:
|
||||
(self.operands) = wasm.get_arch_info(detail.arch.wasm)
|
||||
elif arch == capstone.CS_ARCH_BPF:
|
||||
(self.operands) = bpf.get_arch_info(detail.arch.bpf)
|
||||
elif arch == capstone.CS_ARCH_RISCV:
|
||||
(self.need_effective_addr, self.operands) = riscv.get_arch_info(detail.arch.riscv)
|
||||
elif arch == capstone.CS_ARCH_SH:
|
||||
(self.sh_insn, self.sh_size, self.operands) = sh.get_arch_info(detail.arch.sh)
|
||||
elif arch == capstone.CS_ARCH_TRICORE:
|
||||
(self.update_flags, self.operands) = tricore.get_arch_info(detail.arch.tricore)
|
||||
|
||||
|
||||
cdef class CsInsn(object):
|
||||
|
||||
cdef cc.cs_insn _raw
|
||||
cdef cc.csh _csh
|
||||
cdef object _detail
|
||||
|
||||
def __cinit__(self, _detail):
|
||||
self._detail = _detail
|
||||
|
||||
# defer to CsDetail structure for everything else.
|
||||
def __getattr__(self, name):
|
||||
_detail = self._detail
|
||||
if not _detail:
|
||||
raise CsError(capstone.CS_ERR_DETAIL)
|
||||
return getattr(_detail, name)
|
||||
|
||||
# return instruction's operands.
|
||||
@property
|
||||
def operands(self):
|
||||
return self._detail.operands
|
||||
|
||||
# return instruction's ID.
|
||||
@property
|
||||
def id(self):
|
||||
return self._raw.id
|
||||
|
||||
# return instruction's address.
|
||||
@property
|
||||
def address(self):
|
||||
return self._raw.address
|
||||
|
||||
# return instruction's size.
|
||||
@property
|
||||
def size(self):
|
||||
return self._raw.size
|
||||
|
||||
# return instruction's machine bytes (which should have @size bytes).
|
||||
@property
|
||||
def bytes(self):
|
||||
return bytearray(self._raw.bytes[:self._raw.size])
|
||||
|
||||
# return instruction's mnemonic.
|
||||
@property
|
||||
def mnemonic(self):
|
||||
if _diet:
|
||||
# Diet engine cannot provide @mnemonic & @op_str
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return self._raw.mnemonic
|
||||
|
||||
# return instruction's operands (in string).
|
||||
@property
|
||||
def op_str(self):
|
||||
if _diet:
|
||||
# Diet engine cannot provide @mnemonic & @op_str
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return self._raw.op_str
|
||||
|
||||
# return list of all implicit registers being read.
|
||||
@property
|
||||
def regs_read(self):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @regs_read
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
if self._detail:
|
||||
detail = self._detail
|
||||
return detail.regs_read[:detail.regs_read_count]
|
||||
|
||||
raise CsError(capstone.CS_ERR_DETAIL)
|
||||
|
||||
# return list of all implicit registers being modified
|
||||
@property
|
||||
def regs_write(self):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @regs_write
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
if self._detail:
|
||||
detail = self._detail
|
||||
return detail.regs_write[:detail.regs_write_count]
|
||||
|
||||
raise CsError(capstone.CS_ERR_DETAIL)
|
||||
|
||||
# return list of semantic groups this instruction belongs to.
|
||||
@property
|
||||
def groups(self):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @groups
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
if self._detail:
|
||||
detail = self._detail
|
||||
return detail.groups[:detail.groups_count]
|
||||
|
||||
raise CsError(capstone.CS_ERR_DETAIL)
|
||||
|
||||
# get the last error code
|
||||
def errno(self):
|
||||
return cc.cs_errno(self._csh)
|
||||
|
||||
# get the register name, given the register ID
|
||||
def reg_name(self, reg_id):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide register's name
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return cc.cs_reg_name(self._csh, reg_id)
|
||||
|
||||
# get the instruction string
|
||||
def insn_name(self):
|
||||
if _diet:
|
||||
# Diet engine cannot provide instruction's name
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return cc.cs_insn_name(self._csh, self.id)
|
||||
|
||||
# get the group string
|
||||
def group_name(self, group_id):
|
||||
if _diet:
|
||||
# Diet engine cannot provide group's name
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return cc.cs_group_name(self._csh, group_id)
|
||||
|
||||
# verify if this insn belong to group with id as @group_id
|
||||
def group(self, group_id):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @groups
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return group_id in self.groups
|
||||
|
||||
# verify if this instruction implicitly read register @reg_id
|
||||
def reg_read(self, reg_id):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @regs_read
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return reg_id in self.regs_read
|
||||
|
||||
# verify if this instruction implicitly modified register @reg_id
|
||||
def reg_write(self, reg_id):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @regs_write
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
return reg_id in self.regs_write
|
||||
|
||||
# return number of operands having same operand type @op_type
|
||||
def op_count(self, op_type):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
c = 0
|
||||
for op in self._detail.operands:
|
||||
if op.type == op_type:
|
||||
c += 1
|
||||
return c
|
||||
|
||||
# get the operand at position @position of all operands having the same type @op_type
|
||||
def op_find(self, op_type, position):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
c = 0
|
||||
for op in self._detail.operands:
|
||||
if op.type == op_type:
|
||||
c += 1
|
||||
if c == position:
|
||||
return op
|
||||
|
||||
# Return (list-of-registers-read, list-of-registers-modified) by this instructions.
|
||||
# This includes all the implicit & explicit registers.
|
||||
def regs_access(self):
|
||||
if self._raw.id == 0:
|
||||
raise CsError(capstone.CS_ERR_SKIPDATA)
|
||||
|
||||
cdef cc.uint16_t regs_read[64]
|
||||
cdef cc.uint16_t regs_write[64]
|
||||
cdef cc.uint8_t read_count, write_count
|
||||
|
||||
status = cc.cs_regs_access(self._cs.csh, &self._raw, regs_read, &read_count, regs_write, &write_count)
|
||||
if status != capstone.CS_ERR_OK:
|
||||
raise CsError(status)
|
||||
|
||||
r1 = []
|
||||
for i from 0 <= i < read_count: r1.append(regs_read[i])
|
||||
|
||||
w1 = []
|
||||
for i from 0 <= i < write_count: w1.append(regs_write[i])
|
||||
|
||||
return (r1, w1)
|
||||
|
||||
|
||||
cdef class Cs(object):
|
||||
|
||||
cdef cc.csh _csh
|
||||
cdef object _cs
|
||||
|
||||
def __cinit__(self, _cs):
|
||||
cdef version = cc.cs_version(NULL, NULL)
|
||||
if (version != (capstone.CS_API_MAJOR << 8) + capstone.CS_API_MINOR):
|
||||
# our binding version is different from the core's API version
|
||||
raise CsError(capstone.CS_ERR_VERSION)
|
||||
|
||||
self._csh = <cc.csh> _cs.csh.value
|
||||
self._cs = _cs
|
||||
|
||||
|
||||
# destructor to be called automatically when object is destroyed.
|
||||
def __dealloc__(self):
|
||||
if self._csh:
|
||||
status = cc.cs_close(&self._csh)
|
||||
if status != capstone.CS_ERR_OK:
|
||||
raise CsError(status)
|
||||
|
||||
|
||||
# Disassemble binary & return disassembled instructions in CsInsn objects
|
||||
def disasm(self, code, addr, count=0):
|
||||
cdef cc.cs_insn *allinsn
|
||||
|
||||
cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn)
|
||||
detail = self._cs.detail
|
||||
arch = self._cs.arch
|
||||
|
||||
try:
|
||||
for i from 0 <= i < res:
|
||||
if detail:
|
||||
dummy = CsInsn(CsDetail(arch, <size_t>allinsn[i].detail))
|
||||
else:
|
||||
dummy = CsInsn(None)
|
||||
|
||||
dummy._raw = allinsn[i]
|
||||
dummy._csh = self._csh
|
||||
yield dummy
|
||||
finally:
|
||||
cc.cs_free(allinsn, res)
|
||||
|
||||
|
||||
# Light function to disassemble binary. This is about 20% faster than disasm() because
|
||||
# unlike disasm(), disasm_lite() only return tuples of (address, size, mnemonic, op_str),
|
||||
# rather than CsInsn objects.
|
||||
def disasm_lite(self, code, addr, count=0):
|
||||
# TODO: dont need detail, so we might turn off detail, then turn on again when done
|
||||
cdef cc.cs_insn *allinsn
|
||||
|
||||
if _diet:
|
||||
# Diet engine cannot provide @mnemonic & @op_str
|
||||
raise CsError(capstone.CS_ERR_DIET)
|
||||
|
||||
cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn)
|
||||
|
||||
try:
|
||||
for i from 0 <= i < res:
|
||||
insn = allinsn[i]
|
||||
yield (insn.address, insn.size, insn.mnemonic, insn.op_str)
|
||||
finally:
|
||||
cc.cs_free(allinsn, res)
|
||||
|
||||
|
||||
# print out debugging info
|
||||
def debug():
|
||||
if cc.cs_support(capstone.CS_SUPPORT_DIET):
|
||||
diet = "diet"
|
||||
else:
|
||||
diet = "standard"
|
||||
|
||||
archs = { "arm": capstone.CS_ARCH_ARM, "arm64": capstone.CS_ARCH_ARM64, \
|
||||
"m68k": capstone.CS_ARCH_M68K, "mips": capstone.CS_ARCH_MIPS, \
|
||||
"ppc": capstone.CS_ARCH_PPC, "sparc": capstone.CS_ARCH_SPARC, \
|
||||
"sysz": capstone.CS_ARCH_SYSZ, "xcore": capstone.CS_ARCH_XCORE, \
|
||||
"tms320c64x": capstone.CS_ARCH_TMS320C64X, "m680x": capstone.CS_ARCH_M680X, \
|
||||
"evm": capstone.CS_ARCH_EVM, "mos65xx": capstone.CS_ARCH_MOS65XX, \
|
||||
"wasm": capstone.CS_ARCH_WASM, \
|
||||
"bpf": capstone.CS_ARCH_BPF, "riscv": capstone.CS_ARCH_RISCV, \
|
||||
"sh": capstone.CS_ARCH_SH, "tricore": capstone.CS_ARCH_TRICORE }
|
||||
|
||||
all_archs = ""
|
||||
keys = list(archs.keys())
|
||||
keys.sort()
|
||||
for k in keys:
|
||||
if cc.cs_support(archs[k]):
|
||||
all_archs += "-%s" %k
|
||||
|
||||
if cc.cs_support(capstone.CS_ARCH_X86):
|
||||
all_archs += "-x86"
|
||||
if cc.cs_support(capstone.CS_SUPPORT_X86_REDUCE):
|
||||
all_archs += "_reduce"
|
||||
|
||||
(major, minor, _combined) = capstone.cs_version()
|
||||
|
||||
return "Cython-%s%s-c%u.%u-b%u.%u" %(diet, all_archs, major, minor, capstone.CS_API_MAJOR, capstone.CS_API_MINOR)
|
||||
|
|
@ -6,16 +6,15 @@ import shutil
|
|||
import sys
|
||||
import platform
|
||||
|
||||
from distutils import log
|
||||
import logging
|
||||
from setuptools import setup
|
||||
from distutils.util import get_platform
|
||||
from distutils.command.build import build
|
||||
from distutils.command.sdist import sdist
|
||||
from sysconfig import get_platform
|
||||
from setuptools.command.build import build
|
||||
from setuptools.command.sdist import sdist
|
||||
from setuptools.command.bdist_egg import bdist_egg
|
||||
|
||||
PYTHON2 = sys.version_info[0] == 2
|
||||
if PYTHON2:
|
||||
import io
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
SYSTEM = sys.platform
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ def copy_sources():
|
|||
|
||||
for filename in src:
|
||||
outpath = os.path.join(SRC_DIR, os.path.basename(filename))
|
||||
log.info("%s -> %s" % (filename, outpath))
|
||||
logger.info("%s -> %s" % (filename, outpath))
|
||||
shutil.copy(filename, outpath)
|
||||
|
||||
def build_libraries():
|
||||
|
|
@ -127,6 +126,7 @@ def build_libraries():
|
|||
# if prebuilt libraries are available, use those and cancel build
|
||||
if os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE)) and \
|
||||
(not STATIC_LIBRARY_FILE or os.path.exists(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE))):
|
||||
logger.info('Using prebuilt libraries')
|
||||
shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', LIBRARY_FILE), LIBS_DIR)
|
||||
if STATIC_LIBRARY_FILE is not None:
|
||||
shutil.copy(os.path.join(ROOT_DIR, 'prebuilt', STATIC_LIBRARY_FILE), LIBS_DIR)
|
||||
|
|
@ -165,9 +165,9 @@ class custom_sdist(sdist):
|
|||
class custom_build(build):
|
||||
def run(self):
|
||||
if 'LIBCAPSTONE_PATH' in os.environ:
|
||||
log.info('Skipping building C extensions since LIBCAPSTONE_PATH is set')
|
||||
logger.info('Skipping building C extensions since LIBCAPSTONE_PATH is set')
|
||||
else:
|
||||
log.info('Building C extensions')
|
||||
logger.info('Building C extensions')
|
||||
build_libraries()
|
||||
return build.run(self)
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ try:
|
|||
from setuptools.command.develop import develop
|
||||
class custom_develop(develop):
|
||||
def run(self):
|
||||
log.info("Building C extensions")
|
||||
logger.info("Building C extensions")
|
||||
build_libraries()
|
||||
return develop.run(self)
|
||||
|
||||
|
|
@ -220,19 +220,20 @@ setup(
|
|||
author_email='aquynh@gmail.com',
|
||||
description='Capstone disassembly engine',
|
||||
url='https://www.capstone-engine.org',
|
||||
long_description=io.open('README.txt', encoding="utf8").read() if PYTHON2 else open('README.txt', encoding="utf8").read(),
|
||||
long_description=open('README.txt', encoding="utf8").read(),
|
||||
long_description_content_type='text/markdown',
|
||||
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
|
||||
python_requires='>=3.8',
|
||||
classifiers=[
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
],
|
||||
cmdclass=cmdclass,
|
||||
zip_safe=True,
|
||||
zip_safe=False,
|
||||
include_package_data=True,
|
||||
package_data={
|
||||
"capstone": ["lib/*", "include/capstone/*"],
|
||||
}
|
||||
},
|
||||
install_requires=[
|
||||
"importlib_resources;python_version<'3.9'",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,151 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
from distutils import log
|
||||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
from distutils.command.build import build
|
||||
from Cython.Distutils import build_ext
|
||||
|
||||
SYSTEM = sys.platform
|
||||
VERSION = '5.0.0'
|
||||
VERSION_PARTS = VERSION.split(".")
|
||||
|
||||
# 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
|
||||
|
||||
# are we building from the repository or from a source distribution?
|
||||
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
LIBS_DIR = os.path.join(ROOT_DIR, 'pyx', 'lib')
|
||||
HEADERS_DIR = os.path.join(ROOT_DIR, 'pyx', 'include')
|
||||
SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||
BUILD_DIR = SRC_DIR if os.path.exists(SRC_DIR) else os.path.join(ROOT_DIR, '../..')
|
||||
PYPACKAGE_DIR = os.path.join(ROOT_DIR, 'capstone')
|
||||
CYPACKAGE_DIR = os.path.join(ROOT_DIR, 'pyx')
|
||||
|
||||
if SYSTEM == 'darwin':
|
||||
VERSIONED_LIBRARY_FILE = "libcapstone.{}.dylib".format(VERSION_PARTS[0])
|
||||
LIBRARY_FILE = "libcapstone.dylib"
|
||||
STATIC_LIBRARY_FILE = 'libcapstone.a'
|
||||
elif SYSTEM in ('win32', 'cygwin'):
|
||||
VERSIONED_LIBRARY_FILE = "capstone.dll"
|
||||
LIBRARY_FILE = "capstone.dll"
|
||||
STATIC_LIBRARY_FILE = None
|
||||
else:
|
||||
VERSIONED_LIBRARY_FILE = "libcapstone.so.{}".format(VERSION_PARTS[0])
|
||||
LIBRARY_FILE = "libcapstone.so"
|
||||
STATIC_LIBRARY_FILE = 'libcapstone.a'
|
||||
|
||||
compile_args = ['-O3', '-fomit-frame-pointer', '-I' + HEADERS_DIR]
|
||||
link_args = ['-L' + LIBS_DIR]
|
||||
|
||||
ext_module_names = ['arm', 'arm_const', 'arm64', 'arm64_const', 'm68k', 'm68k_const', 'm680x', 'm680x_const', 'mips', 'mips_const', 'ppc', 'ppc_const', 'x86', 'x86_const', 'sparc', 'sparc_const', 'systemz', 'sysz_const', 'xcore', 'xcore_const', 'tms320c64x', 'tms320c64x_const', 'evm', 'evm_const', 'mos65xx', 'mos65xx_const', 'wasm', 'wasm_const', 'bpf', 'bpf_const', 'riscv', 'riscv_const', 'sh', 'sh_const', 'tricore', 'tricore_const' ]
|
||||
|
||||
ext_modules = [Extension("capstone.ccapstone",
|
||||
["pyx/ccapstone.pyx"],
|
||||
libraries=["capstone"],
|
||||
extra_compile_args=compile_args,
|
||||
extra_link_args=link_args)]
|
||||
ext_modules += [Extension("capstone.%s" % name,
|
||||
["pyx/%s.pyx" % name],
|
||||
extra_compile_args=compile_args,
|
||||
extra_link_args=link_args)
|
||||
for name in ext_module_names]
|
||||
|
||||
for e in ext_modules:
|
||||
e.cython_directives = {"language_level": str(sys.version_info[0])}
|
||||
|
||||
|
||||
def clean_bins():
|
||||
shutil.rmtree(LIBS_DIR, ignore_errors=True)
|
||||
shutil.rmtree(HEADERS_DIR, ignore_errors=True)
|
||||
|
||||
def copy_pysources():
|
||||
for fname in os.listdir(PYPACKAGE_DIR):
|
||||
if not fname.endswith('.py'):
|
||||
continue
|
||||
|
||||
if fname == '__init__.py':
|
||||
shutil.copy(os.path.join(PYPACKAGE_DIR, fname), os.path.join(CYPACKAGE_DIR, fname))
|
||||
else:
|
||||
shutil.copy(os.path.join(PYPACKAGE_DIR, fname), os.path.join(CYPACKAGE_DIR, fname + 'x'))
|
||||
|
||||
def build_libraries():
|
||||
"""
|
||||
Prepare the capstone directory for a binary distribution or installation.
|
||||
Builds shared libraries and copies header files.
|
||||
|
||||
Will use a src/ dir if one exists in the current directory, otherwise assumes it's in the repo
|
||||
"""
|
||||
cwd = os.getcwd()
|
||||
clean_bins()
|
||||
os.mkdir(HEADERS_DIR)
|
||||
os.mkdir(LIBS_DIR)
|
||||
|
||||
# copy public headers
|
||||
shutil.copytree(os.path.join(BUILD_DIR, 'include', 'capstone'), os.path.join(HEADERS_DIR, 'capstone'))
|
||||
|
||||
os.chdir(BUILD_DIR)
|
||||
|
||||
# platform description refers at https://docs.python.org/2/library/sys.html#sys.platform
|
||||
if SYSTEM == "win32":
|
||||
# Windows build: this process requires few things:
|
||||
# - CMake + MSVC installed
|
||||
# - Run this command in an environment setup for MSVC
|
||||
if not os.path.exists("build"): os.mkdir("build")
|
||||
os.chdir("build")
|
||||
# Only build capstone.dll
|
||||
os.system('cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_SHARED=ON -DCAPSTONE_BUILD_TESTS=OFF -DCAPSTONE_BUILD_CSTOOL=OFF -G "NMake Makefiles" ..')
|
||||
os.system("cmake --build .")
|
||||
else: # Unix incl. cygwin
|
||||
os.system("CAPSTONE_BUILD_CORE_ONLY=yes bash ./make.sh")
|
||||
|
||||
shutil.copy(VERSIONED_LIBRARY_FILE, os.path.join(LIBS_DIR, LIBRARY_FILE))
|
||||
if STATIC_LIBRARY_FILE: shutil.copy(STATIC_LIBRARY_FILE, LIBS_DIR)
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
class custom_build(build):
|
||||
def run(self):
|
||||
log.info('Copying python sources')
|
||||
copy_pysources()
|
||||
log.info('Building C extensions')
|
||||
build_libraries()
|
||||
return build.run(self)
|
||||
|
||||
# clean package directory first
|
||||
#import os.path, shutil, sys
|
||||
#for f in sys.path:
|
||||
# if f.endswith('packages'):
|
||||
# pkgdir = os.path.join(f, 'capstone')
|
||||
# #print(pkgdir)
|
||||
# try:
|
||||
# shutil.rmtree(pkgdir)
|
||||
# except:
|
||||
# pass
|
||||
|
||||
setup(
|
||||
provides = ['capstone'],
|
||||
package_dir = {'capstone' : 'pyx'},
|
||||
packages = ['capstone'],
|
||||
name = 'capstone',
|
||||
version = VERSION,
|
||||
cmdclass = {'build_ext': build_ext, 'build': custom_build},
|
||||
ext_modules = ext_modules,
|
||||
author = 'Nguyen Anh Quynh',
|
||||
author_email = 'aquynh@gmail.com',
|
||||
description = 'Capstone disassembly engine',
|
||||
url = 'http://www.capstone-engine.org',
|
||||
classifiers = [
|
||||
'License :: OSI Approved :: BSD License',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
],
|
||||
include_package_data=True,
|
||||
package_data={
|
||||
"capstone": ["lib/*", "include/capstone/*"],
|
||||
}
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue