mirror of
https://github.com/cemu-project/idapython.git
synced 2024-12-28 18:51:53 +01:00
336 lines
9.4 KiB
Python
336 lines
9.4 KiB
Python
|
import types
|
||
|
|
||
|
C_TO_PY_CAST = {
|
||
|
'b' : 'char',
|
||
|
'i' : 'int',
|
||
|
'H' : 'uint16',
|
||
|
'h' : 'int16',
|
||
|
'B' : 'uchar',
|
||
|
}
|
||
|
# --------------------------------------------------------------------------------------------
|
||
|
class gen_fmt(object):
|
||
|
def __init__(self, fields, tp = None, bv = None, cast=None, cmt = None):
|
||
|
self.fields = fields
|
||
|
self.tp = tp
|
||
|
# Format to be passed to Py_BuildValue
|
||
|
if not bv:
|
||
|
self.bv = "XXX"
|
||
|
else:
|
||
|
if bv == "K":
|
||
|
self.bv = "PY_FMT64"
|
||
|
else:
|
||
|
self.bv = '"%s"' % bv
|
||
|
|
||
|
if not cast:
|
||
|
if bv == "K":
|
||
|
cast = "pyul_t"
|
||
|
elif bv in C_TO_PY_CAST:
|
||
|
cast = C_TO_PY_CAST[bv]
|
||
|
|
||
|
self.cast = "" if not cast else "(%s)" % cast
|
||
|
self.cmt = cmt
|
||
|
if bv == "K":
|
||
|
self.setcvt = "uint64 v(0); PyGetNumber(value, &v);"
|
||
|
elif bv == 'i':
|
||
|
self.setcvt = "int v = PyInt_AsLong(value);"
|
||
|
else:
|
||
|
self.setcvt = "uint64 v = %sPyInt_AsLong(value);" % self.cast
|
||
|
|
||
|
|
||
|
# --------------------------------------------------------------------------------------------
|
||
|
switch_info_ex_t_gen = [
|
||
|
gen_fmt('regdtyp', bv = 'b', cmt = 'size of the switch expression register as dtyp'),
|
||
|
gen_fmt('flags2', bv = 'i'),
|
||
|
gen_fmt('jcases', bv = 'i', cmt = 'number of entries in the jump table (SWI2_INDIRECT)'),
|
||
|
gen_fmt('regnum', bv = 'i', cmt = 'the switch expression as a register number'),
|
||
|
gen_fmt('flags', bv = 'H', cmt = 'the switch expression as a register number'),
|
||
|
gen_fmt('ncases', bv = 'H', cmt = 'number of cases (excluding default)'),
|
||
|
gen_fmt('defjump', bv = 'K', cmt = 'default jump address'),
|
||
|
gen_fmt('jumps', bv = 'K', cmt = 'jump table address'),
|
||
|
gen_fmt('elbase', bv = 'K', cmt = 'element base'),
|
||
|
gen_fmt('startea', bv = 'K', cmt = 'start of switch idiom'),
|
||
|
gen_fmt('custom', bv = 'K', cmt = 'information for custom tables (filled and used by modules)'),
|
||
|
gen_fmt('ind_lowcase', bv = 'K'),
|
||
|
gen_fmt(['values', 'lowcase'], bv = 'K'),
|
||
|
]
|
||
|
|
||
|
op_t_gen = [
|
||
|
gen_fmt('n', bv = 'b'),
|
||
|
gen_fmt('type', bv = 'B'),
|
||
|
gen_fmt('offb', bv = 'b'),
|
||
|
gen_fmt('offo', bv = 'b'),
|
||
|
gen_fmt('flags', bv = 'B'),
|
||
|
gen_fmt('dtyp', bv = 'b'),
|
||
|
gen_fmt(['reg', 'phrase'], bv = 'H'),
|
||
|
gen_fmt('value', bv = 'K'),
|
||
|
gen_fmt('addr', bv = 'K'),
|
||
|
gen_fmt('specval', bv = 'K'),
|
||
|
gen_fmt('specflag1', bv = 'b'),
|
||
|
gen_fmt('specflag2', bv = 'b'),
|
||
|
gen_fmt('specflag3', bv = 'b'),
|
||
|
gen_fmt('specflag4', bv = 'b')
|
||
|
]
|
||
|
|
||
|
insn_t_gen = [
|
||
|
gen_fmt('cs', bv = 'K'),
|
||
|
gen_fmt('ip', bv = 'K'),
|
||
|
gen_fmt('ea', bv = 'K'),
|
||
|
gen_fmt('itype', bv = 'H'),
|
||
|
gen_fmt('size', bv = 'H'),
|
||
|
gen_fmt('auxpref', bv = 'H'),
|
||
|
gen_fmt('segpref', bv = 'b'),
|
||
|
gen_fmt('insnpref', bv = 'b'),
|
||
|
gen_fmt('Op1', tp = 'op_t'),
|
||
|
gen_fmt('Op2', tp = 'op_t'),
|
||
|
gen_fmt('Op3', tp = 'op_t'),
|
||
|
gen_fmt('Op4', tp = 'op_t'),
|
||
|
gen_fmt('Op5', tp = 'op_t'),
|
||
|
gen_fmt('Op6', tp = 'op_t'),
|
||
|
gen_fmt('flags', bv = 'b')
|
||
|
]
|
||
|
|
||
|
regval_t_gen = [
|
||
|
gen_fmt('rvtype', bv = 'i'),
|
||
|
gen_fmt('ival', bv = 'K'),
|
||
|
gen_fmt('fval', bv = 'd'),
|
||
|
gen_fmt('bytes', bv = 's'),
|
||
|
]
|
||
|
|
||
|
# --------------------------------------------------------------------------------------------
|
||
|
S_LINK_ATTR = 'S_CLINK_NAME' # If the name is a literal, make sure you specify double quotations
|
||
|
S_CMOD_NAME = '_idaapi'
|
||
|
|
||
|
# --------------------------------------------------------------------------------------------
|
||
|
def gen_stub(gen, name, cname = None, tabs=4, gen_py_file = False, gen_c_file = False):
|
||
|
# Assume C type name same as python type name
|
||
|
if not cname:
|
||
|
cname = name
|
||
|
|
||
|
# Python property lines
|
||
|
prop_body = []
|
||
|
|
||
|
# Python get/set bodies
|
||
|
getset_body = []
|
||
|
|
||
|
# C get/set bodies
|
||
|
cgetset_body = []
|
||
|
|
||
|
# some spacing constants
|
||
|
spc = ' ' * tabs
|
||
|
spc2 = spc * 2
|
||
|
nspc = '\n' + spc
|
||
|
nspc2 = '\n' + spc2
|
||
|
|
||
|
cget_link = '%s_get_clink' % cname
|
||
|
|
||
|
#
|
||
|
# Process fields
|
||
|
#
|
||
|
for g in gen:
|
||
|
# a union will be represented by a list
|
||
|
if type(g.fields) != types.ListType:
|
||
|
fields = [g.fields]
|
||
|
else:
|
||
|
fields = g.fields
|
||
|
|
||
|
# join all field names (in case of a union)
|
||
|
flds_name = '_'.join(fields)
|
||
|
|
||
|
# form the method and variable names
|
||
|
set_method = '__set_%s__' % flds_name
|
||
|
get_method = '__get_%s__' % flds_name
|
||
|
cset_method = '%s_set_%s' % (name, flds_name)
|
||
|
cget_method = '%s_get_%s' % (name, flds_name)
|
||
|
fld_name = '__%s__' % flds_name
|
||
|
|
||
|
basic_type = not g.tp
|
||
|
|
||
|
vars = {
|
||
|
'get': get_method,
|
||
|
'set': set_method,
|
||
|
'l': S_LINK_ATTR,
|
||
|
'fld' : fld_name,
|
||
|
'cmod' : S_CMOD_NAME,
|
||
|
'cget': cget_method,
|
||
|
'cset': cset_method,
|
||
|
'csetcvt': g.setcvt,
|
||
|
'cname': cname,
|
||
|
'cgetlink': cget_link,
|
||
|
'cfield1': fields[0],
|
||
|
'bv': g.bv,
|
||
|
'bvcast': g.cast
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Python code
|
||
|
#
|
||
|
|
||
|
# basic type?
|
||
|
# For basic types we need to create property and get/set methods
|
||
|
if basic_type:
|
||
|
for fld in fields:
|
||
|
prop_body.append('%s = property(%s, %s)' % (fld, get_method, set_method))
|
||
|
if g.cmt:
|
||
|
prop_body.append('"""%s"""' % g.cmt)
|
||
|
|
||
|
#
|
||
|
code = '\n'.join([
|
||
|
# get method
|
||
|
'def %(get)s(self):',
|
||
|
spc2 + 'return %(cmod)s.%(cget)s(self)',
|
||
|
# set method
|
||
|
spc + 'def %(set)s(self, v):',
|
||
|
spc2 + '%(cmod)s.%(cset)s(self, v)',
|
||
|
]) % vars
|
||
|
|
||
|
getset_body.append(code)
|
||
|
|
||
|
#
|
||
|
# C code
|
||
|
#
|
||
|
if basic_type:
|
||
|
code = '\n'.join([
|
||
|
"""static PyObject *%(cget)s(PyObject *self)
|
||
|
{
|
||
|
%(cname)s *link = %(cgetlink)s(self);
|
||
|
if ( link == NULL )
|
||
|
Py_RETURN_NONE;
|
||
|
return Py_BuildValue(%(bv)s, %(bvcast)slink->%(cfield1)s);
|
||
|
}
|
||
|
static void %(cset)s(PyObject *self, PyObject *value)
|
||
|
{
|
||
|
%(cname)s *link = %(cgetlink)s(self);
|
||
|
if ( link == NULL )
|
||
|
return;
|
||
|
%(csetcvt)s
|
||
|
link->%(cfield1)s = %(bvcast)sv;
|
||
|
}
|
||
|
|
||
|
"""
|
||
|
]) % vars
|
||
|
|
||
|
cgetset_body.append(code)
|
||
|
|
||
|
# print 'prop_body->\n\t', '\n\t'.join(prop_body), '\n<'
|
||
|
# print 'getset_body->\n', '\n'.join(getset_body), '\n<'
|
||
|
# print 'cgetset_body->\n', '\n'.join(cgetset_body), '\n<'
|
||
|
|
||
|
vars = {
|
||
|
'name': name,
|
||
|
'cname': cname,
|
||
|
'getlink': cget_link,
|
||
|
'l': S_LINK_ATTR,
|
||
|
'cmod' : S_CMOD_NAME
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# Form the complete Python code
|
||
|
#
|
||
|
py = '\n'.join([
|
||
|
'class %(name)s(py_clinked_object_t):',
|
||
|
|
||
|
# init() code
|
||
|
spc + 'def __init__(self, lnk = None):',
|
||
|
spc2 + 'py_clinked_object_t.__init__(self, lnk)',
|
||
|
'',
|
||
|
spc + 'def _create_clink(self):',
|
||
|
spc2 + 'return _idaapi.%(name)s_create()',
|
||
|
'',
|
||
|
spc + 'def _del_clink(self, lnk):',
|
||
|
spc2 + 'return _idaapi.%(name)s_destroy(lnk)',
|
||
|
'',
|
||
|
spc + 'def assign(self, other):',
|
||
|
spc2 + 'return _idaapi.%(name)s_assign(self, other)',
|
||
|
'',
|
||
|
'',
|
||
|
spc + '#',
|
||
|
spc + '# Autogenerated',
|
||
|
spc + '#',
|
||
|
# get/set code
|
||
|
spc + nspc.join(getset_body),
|
||
|
# props code
|
||
|
spc + nspc.join(prop_body),
|
||
|
]) % vars
|
||
|
|
||
|
#
|
||
|
# Form the Python to C conversion function
|
||
|
#
|
||
|
|
||
|
#
|
||
|
# Form the complete C code
|
||
|
#
|
||
|
ccode = '\n'.join([
|
||
|
# Form the C get link code
|
||
|
"""%(cname)s *%(getlink)s(PyObject *self)
|
||
|
{
|
||
|
if ( !PyObject_HasAttrString(self, %(l)s) )
|
||
|
return NULL;
|
||
|
%(cname)s *r;
|
||
|
PyObject *attr = PyObject_GetAttrString(self, %(l)s);
|
||
|
if ( PyCObject_Check(attr) )
|
||
|
r = (%(cname)s *) PyCObject_AsVoidPtr(attr);
|
||
|
else
|
||
|
r = NULL;
|
||
|
Py_DECREF(attr);
|
||
|
return r;
|
||
|
}
|
||
|
|
||
|
static PyObject *%(cname)s_create()
|
||
|
{
|
||
|
%(cname)s *inst = new %(cname)s();
|
||
|
return PyCObject_FromVoidPtr(inst, NULL);
|
||
|
}
|
||
|
|
||
|
static bool %(cname)s_destroy(PyObject *py_obj)
|
||
|
{
|
||
|
if ( !PyCObject_Check(py_obj) )
|
||
|
return false;
|
||
|
%(cname)s *inst = (%(cname)s *) PyCObject_AsVoidPtr(py_obj);
|
||
|
delete inst;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static bool %(cname)s_assign(PyObject *self, PyObject *other)
|
||
|
{
|
||
|
%(cname)s *lhs = %(cname)s_get_clink(self);
|
||
|
%(cname)s *rhs = %(cname)s_get_clink(other);
|
||
|
if (lhs == NULL || rhs == NULL)
|
||
|
return false;
|
||
|
|
||
|
*lhs = *rhs;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-------------------------------------------------------------------------
|
||
|
// Auto generated - begin
|
||
|
//
|
||
|
""",
|
||
|
# Form C get/set functions
|
||
|
''.join(cgetset_body),
|
||
|
"""//
|
||
|
// Auto generated - end
|
||
|
//
|
||
|
//-------------------------------------------------------------------------"""
|
||
|
]) % vars
|
||
|
|
||
|
# write the Python file
|
||
|
if gen_py_file:
|
||
|
f = open(name + '.py', 'w')
|
||
|
f.write(py)
|
||
|
f.close()
|
||
|
|
||
|
# write C file
|
||
|
if gen_c_file:
|
||
|
f = open(name + '.cpp', 'w')
|
||
|
f.write(ccode)
|
||
|
f.close()
|
||
|
|
||
|
# --------------------------------------------------------------------------------------------
|
||
|
def main():
|
||
|
files = [
|
||
|
('switch_info_ex_t', switch_info_ex_t_gen),
|
||
|
]
|
||
|
for (n, g) in files:
|
||
|
gen_stub(g, n, gen_py_file = True, gen_c_file = True)
|
||
|
|
||
|
main()
|