Skip to content

Commit cb5d37b

Browse files
committed
Undelete ccapstone.pyx
1 parent 24e2615 commit cb5d37b

File tree

2 files changed

+387
-0
lines changed

2 files changed

+387
-0
lines changed

bindings/cython/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ pyx/lib
77
pyx/include
88
pyx/*.c
99
pyx/*.pyx
10+
!pyx/ccapstone.pyx

bindings/cython/pyx/ccapstone.pyx

Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
# By Dang Hoang Vu <[email protected]>, 2014
2+
3+
cimport pyx.ccapstone as cc
4+
import capstone, ctypes
5+
from . import arm, x86, mips, ppc, aarch64, sparc, systemz, xcore, tms320c64x, m68k, m680x, evm, mos65xx, wasm, bpf, riscv, sh, tricore, CsError
6+
7+
_diet = cc.cs_support(capstone.CS_SUPPORT_DIET)
8+
9+
10+
class CsDetail(object):
11+
12+
def __init__(self, arch, raw_detail = None):
13+
if not raw_detail:
14+
return
15+
detail = ctypes.cast(raw_detail, ctypes.POINTER(capstone._cs_detail)).contents
16+
17+
self.regs_read = detail.regs_read
18+
self.regs_read_count = detail.regs_read_count
19+
self.regs_write = detail.regs_write
20+
self.regs_write_count = detail.regs_write_count
21+
self.groups = detail.groups
22+
self.groups_count = detail.groups_count
23+
self.writeback = detail.writeback
24+
25+
if arch == capstone.CS_ARCH_ARM:
26+
(self.usermode, self.vector_size, self.vector_data, self.cps_mode, self.cps_flag, \
27+
self.cc, self.vcc, self.update_flags, self.post_index, self.mem_barrier, self.pred_mask, self.operands) = \
28+
arm.get_arch_info(detail.arch.arm)
29+
elif arch == capstone.CS_ARCH_AARCH64:
30+
(self.cc, self.update_flags, self.post_index, self.operands) = \
31+
aarch64.get_arch_info(detail.arch.aarch64)
32+
elif arch == capstone.CS_ARCH_X86:
33+
(self.prefix, self.opcode, self.rex, self.addr_size, \
34+
self.modrm, self.sib, self.disp, \
35+
self.sib_index, self.sib_scale, self.sib_base, \
36+
self.xop_cc, self.sse_cc, self.avx_cc, self.avx_sae, self.avx_rm, \
37+
self.eflags, self.fpu_flags, self.encoding, self.modrm_offset, self.disp_offset, \
38+
self.disp_size, self.imm_offset, self.imm_size, self.operands) = x86.get_arch_info(detail.arch.x86)
39+
elif arch == capstone.CS_ARCH_M68K:
40+
(self.operands, self.op_size) = m68k.get_arch_info(detail.arch.m68k)
41+
elif arch == capstone.CS_ARCH_MIPS:
42+
self.operands = mips.get_arch_info(detail.arch.mips)
43+
elif arch == capstone.CS_ARCH_PPC:
44+
(self.bc, self.update_cr0, self.operands) = \
45+
ppc.get_arch_info(detail.arch.ppc)
46+
elif arch == capstone.CS_ARCH_SPARC:
47+
(self.cc, self.hint, self.operands) = sparc.get_arch_info(detail.arch.sparc)
48+
elif arch == capstone.CS_ARCH_SYSZ:
49+
(self.cc, self.operands) = systemz.get_arch_info(detail.arch.sysz)
50+
elif arch == capstone.CS_ARCH_XCORE:
51+
self.operands = xcore.get_arch_info(detail.arch.xcore)
52+
elif arch == capstone.CS_ARCH_TMS320C64X:
53+
(self.condition, self.funit, self.parallel, self.operands) = tms320c64x.get_arch_info(self._detail.arch.tms320c64x)
54+
elif arch == capstone.CS_ARCH_M680X:
55+
(self.flags, self.operands) = m680x.get_arch_info(detail.arch.m680x)
56+
elif arch == capstone.CS_ARCH_EVM:
57+
(self.pop, self.push, self.fee) = evm.get_arch_info(detail.arch.evm)
58+
elif arch == capstone.CS_ARCH_MOS65XX:
59+
(self.am, self.modifies_flags, self.operands) = mos65xx.get_arch_info(detail.arch.mos65xx)
60+
elif arch == capstone.CS_ARCH_WASM:
61+
(self.operands) = wasm.get_arch_info(detail.arch.wasm)
62+
elif arch == capstone.CS_ARCH_BPF:
63+
(self.operands) = bpf.get_arch_info(detail.arch.bpf)
64+
elif arch == capstone.CS_ARCH_RISCV:
65+
(self.need_effective_addr, self.operands) = riscv.get_arch_info(detail.arch.riscv)
66+
elif arch == capstone.CS_ARCH_SH:
67+
(self.sh_insn, self.sh_size, self.operands) = sh.get_arch_info(detail.arch.sh)
68+
elif arch == capstone.CS_ARCH_TRICORE:
69+
(self.update_flags, self.operands) = tricore.get_arch_info(detail.arch.tricore)
70+
71+
72+
cdef class CsInsn(object):
73+
74+
cdef cc.cs_insn _raw
75+
cdef cc.csh _csh
76+
cdef object _detail
77+
78+
def __cinit__(self, _detail):
79+
self._detail = _detail
80+
81+
# defer to CsDetail structure for everything else.
82+
def __getattr__(self, name):
83+
_detail = self._detail
84+
if not _detail:
85+
raise CsError(capstone.CS_ERR_DETAIL)
86+
return getattr(_detail, name)
87+
88+
# return instruction's operands.
89+
@property
90+
def operands(self):
91+
return self._detail.operands
92+
93+
# return instruction's ID.
94+
@property
95+
def id(self):
96+
return self._raw.id
97+
98+
# return instruction's address.
99+
@property
100+
def address(self):
101+
return self._raw.address
102+
103+
# return instruction's size.
104+
@property
105+
def size(self):
106+
return self._raw.size
107+
108+
# return instruction's machine bytes (which should have @size bytes).
109+
@property
110+
def bytes(self):
111+
return bytearray(self._raw.bytes[:self._raw.size])
112+
113+
# return instruction's mnemonic.
114+
@property
115+
def mnemonic(self):
116+
if _diet:
117+
# Diet engine cannot provide @mnemonic & @op_str
118+
raise CsError(capstone.CS_ERR_DIET)
119+
120+
return self._raw.mnemonic
121+
122+
# return instruction's operands (in string).
123+
@property
124+
def op_str(self):
125+
if _diet:
126+
# Diet engine cannot provide @mnemonic & @op_str
127+
raise CsError(capstone.CS_ERR_DIET)
128+
129+
return self._raw.op_str
130+
131+
# return list of all implicit registers being read.
132+
@property
133+
def regs_read(self):
134+
if self._raw.id == 0:
135+
raise CsError(capstone.CS_ERR_SKIPDATA)
136+
137+
if _diet:
138+
# Diet engine cannot provide @regs_read
139+
raise CsError(capstone.CS_ERR_DIET)
140+
141+
if self._detail:
142+
detail = self._detail
143+
return detail.regs_read[:detail.regs_read_count]
144+
145+
raise CsError(capstone.CS_ERR_DETAIL)
146+
147+
# return list of all implicit registers being modified
148+
@property
149+
def regs_write(self):
150+
if self._raw.id == 0:
151+
raise CsError(capstone.CS_ERR_SKIPDATA)
152+
153+
if _diet:
154+
# Diet engine cannot provide @regs_write
155+
raise CsError(capstone.CS_ERR_DIET)
156+
157+
if self._detail:
158+
detail = self._detail
159+
return detail.regs_write[:detail.regs_write_count]
160+
161+
raise CsError(capstone.CS_ERR_DETAIL)
162+
163+
# return list of semantic groups this instruction belongs to.
164+
@property
165+
def groups(self):
166+
if self._raw.id == 0:
167+
raise CsError(capstone.CS_ERR_SKIPDATA)
168+
169+
if _diet:
170+
# Diet engine cannot provide @groups
171+
raise CsError(capstone.CS_ERR_DIET)
172+
173+
if self._detail:
174+
detail = self._detail
175+
return detail.groups[:detail.groups_count]
176+
177+
raise CsError(capstone.CS_ERR_DETAIL)
178+
179+
# get the last error code
180+
def errno(self):
181+
return cc.cs_errno(self._csh)
182+
183+
# get the register name, given the register ID
184+
def reg_name(self, reg_id):
185+
if self._raw.id == 0:
186+
raise CsError(capstone.CS_ERR_SKIPDATA)
187+
188+
if _diet:
189+
# Diet engine cannot provide register's name
190+
raise CsError(capstone.CS_ERR_DIET)
191+
192+
return cc.cs_reg_name(self._csh, reg_id)
193+
194+
# get the instruction string
195+
def insn_name(self):
196+
if _diet:
197+
# Diet engine cannot provide instruction's name
198+
raise CsError(capstone.CS_ERR_DIET)
199+
200+
return cc.cs_insn_name(self._csh, self.id)
201+
202+
# get the group string
203+
def group_name(self, group_id):
204+
if _diet:
205+
# Diet engine cannot provide group's name
206+
raise CsError(capstone.CS_ERR_DIET)
207+
208+
return cc.cs_group_name(self._csh, group_id)
209+
210+
# verify if this insn belong to group with id as @group_id
211+
def group(self, group_id):
212+
if self._raw.id == 0:
213+
raise CsError(capstone.CS_ERR_SKIPDATA)
214+
215+
if _diet:
216+
# Diet engine cannot provide @groups
217+
raise CsError(capstone.CS_ERR_DIET)
218+
219+
return group_id in self.groups
220+
221+
# verify if this instruction implicitly read register @reg_id
222+
def reg_read(self, reg_id):
223+
if self._raw.id == 0:
224+
raise CsError(capstone.CS_ERR_SKIPDATA)
225+
226+
if _diet:
227+
# Diet engine cannot provide @regs_read
228+
raise CsError(capstone.CS_ERR_DIET)
229+
230+
return reg_id in self.regs_read
231+
232+
# verify if this instruction implicitly modified register @reg_id
233+
def reg_write(self, reg_id):
234+
if self._raw.id == 0:
235+
raise CsError(capstone.CS_ERR_SKIPDATA)
236+
237+
if _diet:
238+
# Diet engine cannot provide @regs_write
239+
raise CsError(capstone.CS_ERR_DIET)
240+
241+
return reg_id in self.regs_write
242+
243+
# return number of operands having same operand type @op_type
244+
def op_count(self, op_type):
245+
if self._raw.id == 0:
246+
raise CsError(capstone.CS_ERR_SKIPDATA)
247+
248+
c = 0
249+
for op in self._detail.operands:
250+
if op.type == op_type:
251+
c += 1
252+
return c
253+
254+
# get the operand at position @position of all operands having the same type @op_type
255+
def op_find(self, op_type, position):
256+
if self._raw.id == 0:
257+
raise CsError(capstone.CS_ERR_SKIPDATA)
258+
259+
c = 0
260+
for op in self._detail.operands:
261+
if op.type == op_type:
262+
c += 1
263+
if c == position:
264+
return op
265+
266+
# Return (list-of-registers-read, list-of-registers-modified) by this instructions.
267+
# This includes all the implicit & explicit registers.
268+
def regs_access(self):
269+
if self._raw.id == 0:
270+
raise CsError(capstone.CS_ERR_SKIPDATA)
271+
272+
cdef cc.uint16_t regs_read[64]
273+
cdef cc.uint16_t regs_write[64]
274+
cdef cc.uint8_t read_count, write_count
275+
276+
status = cc.cs_regs_access(self._cs.csh, &self._raw, regs_read, &read_count, regs_write, &write_count)
277+
if status != capstone.CS_ERR_OK:
278+
raise CsError(status)
279+
280+
r1 = []
281+
for i from 0 <= i < read_count: r1.append(regs_read[i])
282+
283+
w1 = []
284+
for i from 0 <= i < write_count: w1.append(regs_write[i])
285+
286+
return (r1, w1)
287+
288+
289+
cdef class Cs(object):
290+
291+
cdef cc.csh _csh
292+
cdef object _cs
293+
294+
def __cinit__(self, _cs):
295+
cdef version = cc.cs_version(NULL, NULL)
296+
if (version != (capstone.CS_API_MAJOR << 8) + capstone.CS_API_MINOR):
297+
# our binding version is different from the core's API version
298+
raise CsError(capstone.CS_ERR_VERSION)
299+
300+
self._csh = <cc.csh> _cs.csh.value
301+
self._cs = _cs
302+
303+
304+
# destructor to be called automatically when object is destroyed.
305+
def __dealloc__(self):
306+
if self._csh:
307+
status = cc.cs_close(&self._csh)
308+
if status != capstone.CS_ERR_OK:
309+
raise CsError(status)
310+
311+
312+
# Disassemble binary & return disassembled instructions in CsInsn objects
313+
def disasm(self, code, addr, count=0):
314+
cdef cc.cs_insn *allinsn
315+
316+
cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn)
317+
detail = self._cs.detail
318+
arch = self._cs.arch
319+
320+
try:
321+
for i from 0 <= i < res:
322+
if detail:
323+
dummy = CsInsn(CsDetail(arch, <size_t>allinsn[i].detail))
324+
else:
325+
dummy = CsInsn(None)
326+
327+
dummy._raw = allinsn[i]
328+
dummy._csh = self._csh
329+
yield dummy
330+
finally:
331+
cc.cs_free(allinsn, res)
332+
333+
334+
# Light function to disassemble binary. This is about 20% faster than disasm() because
335+
# unlike disasm(), disasm_lite() only return tuples of (address, size, mnemonic, op_str),
336+
# rather than CsInsn objects.
337+
def disasm_lite(self, code, addr, count=0):
338+
# TODO: don't need detail, so we might turn off detail, then turn on again when done
339+
cdef cc.cs_insn *allinsn
340+
341+
if _diet:
342+
# Diet engine cannot provide @mnemonic & @op_str
343+
raise CsError(capstone.CS_ERR_DIET)
344+
345+
cdef res = cc.cs_disasm(self._csh, code, len(code), addr, count, &allinsn)
346+
347+
try:
348+
for i from 0 <= i < res:
349+
insn = allinsn[i]
350+
yield (insn.address, insn.size, insn.mnemonic, insn.op_str)
351+
finally:
352+
cc.cs_free(allinsn, res)
353+
354+
355+
# print out debugging info
356+
def debug():
357+
if cc.cs_support(capstone.CS_SUPPORT_DIET):
358+
diet = "diet"
359+
else:
360+
diet = "standard"
361+
362+
archs = { "arm": capstone.CS_ARCH_ARM, "aarch64": capstone.CS_ARCH_AARCH64, \
363+
"m68k": capstone.CS_ARCH_M68K, "mips": capstone.CS_ARCH_MIPS, \
364+
"ppc": capstone.CS_ARCH_PPC, "sparc": capstone.CS_ARCH_SPARC, \
365+
"sysz": capstone.CS_ARCH_SYSZ, "xcore": capstone.CS_ARCH_XCORE, \
366+
"tms320c64x": capstone.CS_ARCH_TMS320C64X, "m680x": capstone.CS_ARCH_M680X, \
367+
"evm": capstone.CS_ARCH_EVM, "mos65xx": capstone.CS_ARCH_MOS65XX, \
368+
"wasm": capstone.CS_ARCH_WASM, \
369+
"bpf": capstone.CS_ARCH_BPF, "riscv": capstone.CS_ARCH_RISCV, \
370+
"sh": capstone.CS_ARCH_SH, "tricore": capstone.CS_ARCH_TRICORE }
371+
372+
all_archs = ""
373+
keys = list(archs.keys())
374+
keys.sort()
375+
for k in keys:
376+
if cc.cs_support(archs[k]):
377+
all_archs += "-%s" %k
378+
379+
if cc.cs_support(capstone.CS_ARCH_X86):
380+
all_archs += "-x86"
381+
if cc.cs_support(capstone.CS_SUPPORT_X86_REDUCE):
382+
all_archs += "_reduce"
383+
384+
(major, minor, _combined) = capstone.cs_version()
385+
386+
return "Cython-%s%s-c%u.%u-b%u.%u" %(diet, all_archs, major, minor, capstone.CS_API_MAJOR, capstone.CS_API_MINOR)

0 commit comments

Comments
 (0)