Top

miasm2.core.objc module

C helper for Miasm: raw C to Miasm expression Miasm expression to raw C * Miasm expression to C type

"""
C helper for Miasm:
* raw C to Miasm expression
* Miasm expression to raw C
* Miasm expression to C type
"""


import warnings
from pycparser import c_parser, c_ast

from miasm2.expression.expression_reduce import ExprReducer
from miasm2.expression.expression import ExprInt, ExprId, ExprOp, ExprMem

from miasm2.core.ctypesmngr import CTypeUnion, CTypeStruct, CTypeId, CTypePtr,\
    CTypeArray, CTypeOp, CTypeSizeof, CTypeEnum, CTypeFunc, CTypeEllipsis


PADDING_TYPE_NAME = "___padding___"

def missing_definition(objtype):
    warnings.warn("Null size type: Missing definition? %r" % objtype)

"""
Display C type
source: "The C Programming Language - 2nd Edition - Ritchie Kernighan.pdf"
p. 124
"""

def objc_to_str(objc, result=None):
    if result is None:
        result = ""
    while True:
        if isinstance(objc, ObjCArray):
            result += "[%d]" % objc.elems
            objc = objc.objtype
        elif isinstance(objc, ObjCPtr):
            if not result and isinstance(objc.objtype, ObjCFunc):
                result = objc.objtype.name
            if isinstance(objc.objtype, (ObjCPtr, ObjCDecl, ObjCStruct, ObjCUnion)):
                result = "*%s" % result
            else:
                result = "(*%s)" % result

            objc = objc.objtype
        elif isinstance(objc, (ObjCDecl, ObjCStruct, ObjCUnion)):
            if result:
                result = "%s %s" % (objc, result)
            else:
                result = str(objc)
            break
        elif isinstance(objc, ObjCFunc):
            args_str = []
            for name, arg in objc.args:
                args_str.append(objc_to_str(arg, name))
            args = ", ".join(args_str)
            result += "(%s)" % args
            objc = objc.type_ret
        elif isinstance(objc, ObjCInt):
            return "int"
        elif isinstance(objc, ObjCEllipsis):
            return "..."
        else:
            raise TypeError("Unknown c type")
    return result


class ObjC(object):
    """Generic ObjC"""

    def __init__(self, align, size):
        self._align = align
        self._size = size

    @property
    def align(self):
        """Alignment (in bytes) of the C object"""
        return self._align

    @property
    def size(self):
        """Size (in bytes) of the C object"""
        return self._size

    def cmp_base(self, other):
        assert self.__class__ in OBJC_PRIO
        assert other.__class__ in OBJC_PRIO

        if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
            return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
        if self.align != other.align:
            return cmp(self.align, other.align)
        return cmp(self.size, other.size)

    def __hash__(self):
        return hash((self.__class__, self._align, self._size))

    def __str__(self):
        return objc_to_str(self)


class ObjCDecl(ObjC):
    """C Declaration identified"""

    def __init__(self, name, align, size):
        super(ObjCDecl, self).__init__(align, size)
        self._name = name

    name = property(lambda self: self._name)

    def __hash__(self):
        return hash((super(ObjCDecl, self).__hash__(), self._name))

    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.name)

    def __str__(self):
        return str(self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)


class ObjCInt(ObjC):
    """C integer"""

    def __init__(self):
        super(ObjCInt, self).__init__(None, None)

    def __str__(self):
        return 'int'

    def __cmp__(self, other):
        return self.cmp_base(other)


class ObjCPtr(ObjC):
    """C Pointer"""

    def __init__(self, objtype, void_p_align, void_p_size):
        """Init ObjCPtr

        @objtype: pointer target ObjC
        @void_p_align: pointer alignment (in bytes)
        @void_p_size: pointer size (in bytes)
        """

        super(ObjCPtr, self).__init__(void_p_align, void_p_size)
        self._lock = False

        self.objtype = objtype
        if objtype is None:
            self._lock = False

    def get_objtype(self):
        assert self._lock is True
        return self._objtype

    def set_objtype(self, objtype):
        assert self._lock is False
        self._lock = True
        self._objtype = objtype

    objtype = property(get_objtype, set_objtype)

    def __hash__(self):
        # Don't try to hash on an unlocked Ptr (still mutable)
        assert self._lock
        return hash((super(ObjCPtr, self).__hash__(), hash(self._objtype)))

    def __repr__(self):
        return '<%s %r>' % (self.__class__.__name__,
                            self.objtype.__class__)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.objtype, other.objtype)


class ObjCArray(ObjC):
    """C array (test[XX])"""

    def __init__(self, objtype, elems):
        """Init ObjCArray

        @objtype: pointer target ObjC
        @elems: number of elements in the array
        """

        super(ObjCArray, self).__init__(objtype.align, elems * objtype.size)
        self._elems = elems
        self._objtype = objtype

    objtype = property(lambda self: self._objtype)
    elems = property(lambda self: self._elems)

    def __hash__(self):
        return hash((super(ObjCArray, self).__hash__(), self._elems, hash(self._objtype)))

    def __repr__(self):
        return '<%r[%d]>' % (self.objtype, self.elems)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        ret = cmp(self.elems, other.elems)
        if ret:
            return ret
        return cmp(self.objtype, other.objtype)


class ObjCStruct(ObjC):
    """C object for structures"""

    def __init__(self, name, align, size, fields):
        super(ObjCStruct, self).__init__(align, size)
        self._name = name
        self._fields = tuple(fields)

    name = property(lambda self: self._name)
    fields = property(lambda self: self._fields)

    def __hash__(self):
        return hash((super(ObjCStruct, self).__hash__(), self._name))

    def __repr__(self):
        out = []
        out.append("Struct %s: (align: %d)" % (self.name, self.align))
        out.append("  off sz  name")
        for name, objtype, offset, size in self.fields:
            out.append("  0x%-3x %-3d %-10s %r" %
                       (offset, size, name, objtype.__class__.__name__))
        return '\n'.join(out)

    def __str__(self):
        return 'struct %s' % (self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

class ObjCUnion(ObjC):
    """C object for unions"""

    def __init__(self, name, align, size, fields):
        super(ObjCUnion, self).__init__(align, size)
        self._name = name
        self._fields = tuple(fields)

    name = property(lambda self: self._name)
    fields = property(lambda self: self._fields)

    def __hash__(self):
        return hash((super(ObjCUnion, self).__hash__(), self._name))

    def __repr__(self):
        out = []
        out.append("Union %s: (align: %d)" % (self.name, self.align))
        out.append("  off sz  name")
        for name, objtype, offset, size in self.fields:
            out.append("  0x%-3x %-3d %-10s %r" %
                       (offset, size, name, objtype))
        return '\n'.join(out)

    def __str__(self):
        return 'union %s' % (self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

class ObjCEllipsis(ObjC):
    """C integer"""

    def __init__(self):
        super(ObjCEllipsis, self).__init__(None, None)

    align = property(lambda self: self._align)
    size = property(lambda self: self._size)

    def __cmp__(self, other):
        return self.cmp_base(other)


class ObjCFunc(ObjC):
    """C object for Functions"""

    def __init__(self, name, abi, type_ret, args, void_p_align, void_p_size):
        super(ObjCFunc, self).__init__(void_p_align, void_p_size)
        self._name = name
        self._abi = abi
        self._type_ret = type_ret
        self._args = tuple(args)

    args = property(lambda self: self._args)
    type_ret = property(lambda self: self._type_ret)
    abi = property(lambda self: self._abi)
    name = property(lambda self: self._name)

    def __hash__(self):
        return hash((super(ObjCFunc, self).__hash__(), hash(self._args), self._name))

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.name)

    def __str__(self):
        out = []
        out.append("Function (%s)  %s: (align: %d)" % (self.abi, self.name, self.align))
        out.append("  ret: %s" % (str(self.type_ret)))
        out.append("  Args:")
        for name, arg in self.args:
            out.append("  %s %s" % (name, arg))
        return '\n'.join(out)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

OBJC_PRIO = {
    ObjC: 0,
    ObjCDecl:1,
    ObjCInt:2,
    ObjCPtr:3,
    ObjCArray:4,
    ObjCStruct:5,
    ObjCUnion:6,
    ObjCEllipsis:7,
    ObjCFunc:8,
}


def access_simplifier(expr):
    """Expression visitor to simplify a C access represented in Miasm

    @expr: Miasm expression representing the C access

    Example:

    IN: (In c: ['*(&((&((*(ptr_Test)).a))[0]))'])
    [ExprOp('deref', ExprOp('addr', ExprOp('[]', ExprOp('addr',
    ExprOp('field', ExprOp('deref', ExprId('ptr_Test', 64)),
    ExprId('a', 64))), ExprInt(0x0, 64))))]

    OUT: (In c: ['(ptr_Test)->a'])
    [ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))]
    """

    if (expr.is_op("addr") and
            expr.args[0].is_op("[]") and
            expr.args[0].args[1] == ExprInt(0, 64)):
        return expr.args[0].args[0]
    elif (expr.is_op("[]") and
          expr.args[0].is_op("addr") and
          expr.args[1] == ExprInt(0, 64)):
        return expr.args[0].args[0]
    elif (expr.is_op("addr") and
          expr.args[0].is_op("deref")):
        return expr.args[0].args[0]
    elif (expr.is_op("deref") and
          expr.args[0].is_op("addr")):
        return expr.args[0].args[0]
    elif (expr.is_op("field") and
          expr.args[0].is_op("deref")):
        return ExprOp("->", expr.args[0].args[0], expr.args[1])
    return expr


def access_str(expr):
    """Return the C string of a C access represented in Miasm

    @expr: Miasm expression representing the C access

    In:
    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
    OUT:
    '(ptr_Test)->a'
    """

    if isinstance(expr, ExprId):
        out = str(expr)
    elif isinstance(expr, ExprInt):
        out = str(int(expr))
    elif expr.is_op("addr"):
        out = "&(%s)" % access_str(expr.args[0])
    elif expr.is_op("deref"):
        out = "*(%s)" % access_str(expr.args[0])
    elif expr.is_op("field"):
        out = "(%s).%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
    elif expr.is_op("->"):
        out = "(%s)->%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
    elif expr.is_op("[]"):
        out = "(%s)[%s]" % (access_str(expr.args[0]), access_str(expr.args[1]))
    else:
        raise RuntimeError("unknown op")

    return out


class CGen(object):
    """Generic object to represent a C expression"""

    default_size = 64


    def __init__(self, ctype):
        self._ctype = ctype

    @property
    def ctype(self):
        """Type (ObjC instance) of the current object"""
        return self._ctype

    def __hash__(self):
        return hash(self.__class__)

    def __eq__(self, other):
        return (self.__class__ == other.__class__ and
                self._ctype == other.ctype)

    def __ne__(self, other):
        return not self.__eq__(other)

    def to_c(self):
        """Generate corresponding C"""

        raise NotImplementedError("Virtual")

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        raise NotImplementedError("Virtual")


class CGenInt(CGen):
    """Int C object"""

    def __init__(self, integer):
        assert isinstance(integer, (int, long))
        self._integer = integer
        super(CGenInt, self).__init__(ObjCInt())

    @property
    def integer(self):
        """Value of the object"""
        return self._integer

    def __hash__(self):
        return hash((super(CGenInt, self).__hash__(), self._integer))

    def __eq__(self, other):
        return (super(CGenInt, self).__eq__(other) and
                self._integer == other.integer)

    def to_c(self):
        """Generate corresponding C"""

        return "0x%X" % self.integer

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.integer)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        return ExprInt(self.integer, self.default_size)


class CGenId(CGen):
    """ID of a C object"""

    def __init__(self, ctype, name):
        self._name = name
        assert isinstance(name, str)
        super(CGenId, self).__init__(ctype)

    @property
    def name(self):
        """Name of the Id"""
        return self._name

    def __hash__(self):
        return hash((super(CGenId, self).__hash__(), self._name))

    def __eq__(self, other):
        return (super(CGenId, self).__eq__(other) and
                self._name == other.name)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.name)

    def to_c(self):
        """Generate corresponding C"""

        return "%s" % (self.name)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        return ExprId(self.name, self.default_size)


class CGenField(CGen):
    """
    Field of a C struct/union

    IN:
    - struct (not ptr struct)
    - field name
    OUT:
    - input type of the field => output type
    - X[] => X[]
    - X => X*
    """

    def __init__(self, struct, field, fieldtype, void_p_align, void_p_size):
        self._struct = struct
        self._field = field
        assert isinstance(field, str)
        if isinstance(fieldtype, ObjCArray):
            ctype = fieldtype
        else:
            ctype = ObjCPtr(fieldtype, void_p_align, void_p_size)
        super(CGenField, self).__init__(ctype)

    @property
    def struct(self):
        """Structure containing the field"""
        return self._struct

    @property
    def field(self):
        """Field name"""
        return self._field

    def __hash__(self):
        return hash((super(CGenField, self).__hash__(), self._struct, self._field))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._struct == other.struct and
                self._field == other.field)

    def to_c(self):
        """Generate corresponding C"""

        if isinstance(self.ctype, ObjCArray):
            return "(%s).%s" % (self.struct.to_c(), self.field)
        elif isinstance(self.ctype, ObjCPtr):
            return "&((%s).%s)" % (self.struct.to_c(), self.field)
        else:
            raise RuntimeError("Strange case")

    def __repr__(self):
        return "<%s %s %s>" % (self.__class__.__name__,
                               self.struct,
                               self.field)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if isinstance(self.ctype, ObjCArray):
            return ExprOp("field",
                          self.struct.to_expr(),
                          ExprId(self.field, self.default_size))
        elif isinstance(self.ctype, ObjCPtr):
            return ExprOp("addr",
                          ExprOp("field",
                                 self.struct.to_expr(),
                                 ExprId(self.field, self.default_size)))
        else:
            raise RuntimeError("Strange case")


class CGenArray(CGen):
    """
    C Array

    This object does *not* deref the source, it only do object casting.

    IN:
    - obj
    OUT:
    - X* => X*
    - ..[][] => ..[]
    - X[] => X*
    """

    def __init__(self, base, elems, void_p_align, void_p_size):
        ctype = base.ctype
        if isinstance(ctype, ObjCPtr):
            pass
        elif isinstance(ctype, ObjCArray) and isinstance(ctype.objtype, ObjCArray):
            ctype = ctype.objtype
        elif isinstance(ctype, ObjCArray):
            ctype = ObjCPtr(ctype.objtype, void_p_align, void_p_size)
        else:
            raise TypeError("Strange case")
        self._base = base
        self._elems = elems
        super(CGenArray, self).__init__(ctype)

    @property
    def base(self):
        """Base object supporting the array"""
        return self._base

    @property
    def elems(self):
        """Number of elements in the array"""
        return self._elems

    def __hash__(self):
        return hash((super(CGenArray, self).__hash__(), self._base, self._elems))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._base == other.base and
                self._elems == other.elems)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.base)

    def to_c(self):
        """Generate corresponding C"""

        if isinstance(self.ctype, ObjCPtr):
            out_str = "&((%s)[%d])" % (self.base.to_c(), self.elems)
        elif isinstance(self.ctype, ObjCArray):
            out_str = "(%s)[%d]" % (self.base.to_c(), self.elems)
        else:
            raise RuntimeError("Strange case")
        return out_str

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if isinstance(self.ctype, ObjCPtr):
            return ExprOp("addr",
                          ExprOp("[]",
                                 self.base.to_expr(),
                                 ExprInt(self.elems, self.default_size)))
        elif isinstance(self.ctype, ObjCArray):
            return ExprOp("[]",
                          self.base.to_expr(),
                          ExprInt(self.elems, self.default_size))
        else:
            raise RuntimeError("Strange case")


class CGenDeref(CGen):
    """
    C dereference

    IN:
    - ptr
    OUT:
    - X* => X
    """

    def __init__(self, ptr):
        assert isinstance(ptr.ctype, ObjCPtr)
        self._ptr = ptr
        super(CGenDeref, self).__init__(ptr.ctype.objtype)

    @property
    def ptr(self):
        """Pointer object"""
        return self._ptr

    def __hash__(self):
        return hash((super(CGenDeref, self).__hash__(), self._ptr))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._ptr == other.ptr)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.ptr)

    def to_c(self):
        """Generate corresponding C"""

        if not isinstance(self.ptr.ctype, ObjCPtr):
            raise RuntimeError()
        return "*(%s)" % (self.ptr.to_c())

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if not isinstance(self.ptr.ctype, ObjCPtr):
            raise RuntimeError()
        return ExprOp("deref", self.ptr.to_expr())


def ast_get_c_access_expr(ast, expr_types, lvl=0):
    """Transform C ast object into a C Miasm expression

    @ast: parsed pycparser.c_ast object
    @expr_types: a dictionnary linking ID names to their types
    @lvl: actual recursion level

    Example:

    IN:
    StructRef: ->
      ID: ptr_Test
      ID: a

    OUT:
    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
    """

    if isinstance(ast, c_ast.Constant):
        obj = ExprInt(int(ast.value), 64)
    elif isinstance(ast, c_ast.StructRef):
        name, field = ast.name, ast.field.name
        name = ast_get_c_access_expr(name, expr_types)
        if ast.type == "->":
            s_name = name
            s_field = ExprId(field, 64)
            obj = ExprOp('->', s_name, s_field)
        elif ast.type == ".":
            s_name = name
            s_field = ExprId(field, 64)
            obj = ExprOp("field", s_name, s_field)
        else:
            raise RuntimeError("Unknown struct access")
    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "&":
        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
        obj = ExprOp("addr", tmp)
    elif isinstance(ast, c_ast.ArrayRef):
        tmp = ast_get_c_access_expr(ast.name, expr_types, lvl + 1)
        index = ast_get_c_access_expr(ast.subscript, expr_types, lvl + 1)
        obj = ExprOp("[]", tmp, index)
    elif isinstance(ast, c_ast.ID):
        assert ast.name in expr_types
        obj = ExprId(ast.name, 64)
    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "*":
        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
        obj = ExprOp("deref", tmp)
    else:
        raise NotImplementedError("Unknown type")
    return obj


def parse_access(c_access):
    """Parse C access

    @c_access: C access string
    """

    main = '''
    int main() {
    %s;
    }
    ''' % c_access

    parser = c_parser.CParser()
    node = parser.parse(main, filename='<stdin>')
    access = node.ext[-1].body.block_items[0]
    return access


class ExprToAccessC(ExprReducer):
    """
    Generate the C access object(s) for a given native Miasm expression
    Example:
    IN:
    @32[ptr_Test]
    OUT:
    [<CGenDeref <CGenArray <CGenField <CGenDeref <CGenId ptr_Test>> a>>>]

    An expression may be represented by multiple accessor (due to unions).
    """

    def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
        """Init GenCAccess

        @expr_types: a dictionnary linking ID names to their types
        @types_mngr: types manager
        @enforce_strict_access: If false, generate access even on expression
        pointing to a middle of an object. If true, raise exception if such a
        pointer is encountered
        """

        self.expr_types = expr_types
        self.types_mngr = types_mngr
        self.enforce_strict_access = enforce_strict_access

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types

    def cgen_access(self, cgenobj, base_type, offset, deref, lvl=0):
        """Return the access(es) which lead to the element at @offset of an
        object of type @base_type

        In case of no @deref, stops recursion as soon as we reached the base of
        an object.
        In other cases, we need to go down to the final dereferenced object

        @cgenobj: current object access
        @base_type: type of main object
        @offset: offset (in bytes) of the target sub object
        @deref: get type for a pointer or a deref
        @lvl: actual recursion level


        IN:
        - base_type: struct Toto{
            int a
            int b
          }
        - base_name: var
        - 4
        OUT:
        - CGenField(var, b)



        IN:
        - base_type: int a
        - 0
        OUT:
        - CGenAddr(a)

        IN:
        - base_type: X = int* a
        - 0
        OUT:
        - CGenAddr(X)

        IN:
        - X = int* a
        - 8
        OUT:
        - ASSERT


        IN:
        - struct toto{
            int a
            int b[10]
          }
        - 8
        OUT:
        - CGenArray(CGenField(toto, b), 1)
        """
        if base_type.size == 0:
            missing_definition(base_type)
            return set()


        void_type = self.types_mngr.void_ptr
        if isinstance(base_type, ObjCStruct):
            if not 0 <= offset < base_type.size:
                return set()

            if offset == 0 and not deref:
                # In this case, return the struct*
                return set([cgenobj])

            for fieldname, subtype, field_offset, size in base_type.fields:
                if not field_offset <= offset < field_offset + size:
                    continue
                fieldptr = CGenField(CGenDeref(cgenobj), fieldname, subtype,
                                     void_type.align, void_type.size)
                new_type = self.cgen_access(fieldptr, subtype,
                                            offset - field_offset,
                                            deref, lvl + 1)
                break
            else:
                return set()
        elif isinstance(base_type, ObjCArray):
            if base_type.objtype.size == 0:
                missing_definition(base_type.objtype)
                return set()
            element_num = offset / (base_type.objtype.size)
            field_offset = offset % base_type.objtype.size
            if element_num >= base_type.elems:
                return set()
            if offset == 0 and not deref:
                # In this case, return the array
                return set([cgenobj])

            curobj = CGenArray(cgenobj, element_num,
                               void_type.align,
                               void_type.size)
            if field_offset == 0:
                # We point to the start of the sub object,
                # return it directly
                return set([curobj])
            new_type = self.cgen_access(curobj, base_type.objtype,
                                        field_offset, deref, lvl + 1)

        elif isinstance(base_type, ObjCDecl):
            if self.enforce_strict_access and offset % base_type.size != 0:
                return set()
            elem_num = offset / base_type.size

            nobj = CGenArray(cgenobj, elem_num,
                             void_type.align, void_type.size)
            new_type = set([nobj])

        elif isinstance(base_type, ObjCUnion):
            if offset == 0 and not deref:
                # In this case, return the struct*
                return set([cgenobj])

            out = set()
            for fieldname, objtype, field_offset, size in base_type.fields:
                if not field_offset <= offset < field_offset + size:
                    continue
                field = CGenField(CGenDeref(cgenobj), fieldname, objtype,
                                  void_type.align, void_type.size)
                out.update(self.cgen_access(field, objtype,
                                            offset - field_offset,
                                            deref, lvl + 1))
            new_type = out

        elif isinstance(base_type, ObjCPtr):
            elem_num = offset / base_type.size
            if self.enforce_strict_access and offset % base_type.size != 0:
                return set()
            nobj = CGenArray(cgenobj, elem_num,
                             void_type.align, void_type.size)
            new_type = set([nobj])

        else:
            raise NotImplementedError("deref type %r" % base_type)
        return new_type

    def reduce_known_expr(self, node, ctxt, **kwargs):
        """Generate access for known expr"""
        if node.expr in ctxt:
            objcs = ctxt[node.expr]
            return set(CGenId(objc, str(node.expr)) for objc in objcs)
        return None

    def reduce_int(self, node, **kwargs):
        """Generate access for ExprInt"""

        if not isinstance(node.expr, ExprInt):
            return None
        return set([CGenInt(int(node.expr))])

    def get_solo_type(self, node):
        """Return the type of the @node if it has only one possible type,
        different from not None. In othe cases, return None.
        """
        if node.info is None or len(node.info) != 1:
            return None
        return type(list(node.info)[0].ctype)

    def reduce_op(self, node, lvl=0, **kwargs):
        """Generate access for ExprOp"""
        if not node.expr.is_op("+") or len(node.args) != 2:
            return None
        type_arg1 = self.get_solo_type(node.args[1])
        if type_arg1 != ObjCInt:
            return None
        arg0, arg1 = node.args
        if arg0.info is None:
            return None
        void_type = self.types_mngr.void_ptr
        out = set()
        if not arg1.expr.is_int():
            return None
        ptr_offset = int(arg1.expr)
        for info in arg0.info:
            if isinstance(info.ctype, ObjCArray):
                field_type = info.ctype
            elif isinstance(info.ctype, ObjCPtr):
                field_type = info.ctype.objtype
            else:
                continue
            target_type = info.ctype.objtype

            # Array-like: int* ptr; ptr[1] = X
            out.update(self.cgen_access(info, field_type, ptr_offset, False, lvl))
        return out

    def reduce_mem(self, node, lvl=0, **kwargs):
        """Generate access for ExprMem:
        * @NN[ptr<elem>] -> elem  (type)
        * @64[ptr<ptr<elem>>] -> ptr<elem>
        * @32[ptr<struct>] -> struct.00
        """

        if not isinstance(node.expr, ExprMem):
            return None
        if node.arg.info is None:
            return None
        assert isinstance(node.arg.info, set)
        void_type = self.types_mngr.void_ptr
        found = set()
        for subcgenobj in node.arg.info:
            if isinstance(subcgenobj.ctype, ObjCArray):
                nobj = CGenArray(subcgenobj, 0,
                                 void_type.align,
                                 void_type.size)
                target = nobj.ctype.objtype
                for finalcgenobj in self.cgen_access(nobj, target, 0, True, lvl):
                    assert isinstance(finalcgenobj.ctype, ObjCPtr)
                    if self.enforce_strict_access and finalcgenobj.ctype.objtype.size != node.expr.size / 8:
                        continue
                    found.add(CGenDeref(finalcgenobj))

            elif isinstance(subcgenobj.ctype, ObjCPtr):
                target = subcgenobj.ctype.objtype
                # target : type(elem)
                if isinstance(target, (ObjCStruct, ObjCUnion)):
                    for finalcgenobj in self.cgen_access(subcgenobj, target, 0, True, lvl):
                        target = finalcgenobj.ctype.objtype
                        if self.enforce_strict_access and target.size != node.expr.size / 8:
                            continue
                        found.add(CGenDeref(finalcgenobj))
                elif isinstance(target, ObjCArray):
                    if self.enforce_strict_access and subcgenobj.ctype.size != node.expr.size / 8:
                        continue
                    found.update(self.cgen_access(CGenDeref(subcgenobj), target,
                                                  0, False, lvl))
                else:
                    if self.enforce_strict_access and target.size != node.expr.size / 8:
                        continue
                    found.add(CGenDeref(subcgenobj))
        if not found:
            return None
        return found

    reduction_rules = [reduce_known_expr,
                       reduce_int,
                       reduce_op,
                       reduce_mem,
                      ]

    def get_accesses(self, expr, expr_context=None):
        """Generate C access(es) for the native Miasm expression @expr
        @expr: native Miasm expression
        @expr_context: a dictionnary linking known expressions to their
        types. An expression is linked to a tuple of types.
        """
        if expr_context is None:
            expr_context = self.expr_types
        ret = self.reduce(expr, ctxt=expr_context)
        if ret.info is None:
            return set()
        return ret.info


class ExprCToExpr(ExprReducer):
    """Translate a Miasm expression (representing a C access) into a native
    Miasm expression and its C type:

    Example:

    IN: ((ptr_struct -> f_mini) field x)
    OUT: @32[ptr_struct + 0x80], int


    Tricky cases:
    Struct S0 {
        int x;
        int y[0x10];
    }

    Struct S1 {
        int a;
        S0 toto;
    }

    S1* ptr;

    Case 1:
    ptr->toto => ptr + 0x4
    &(ptr->toto) => ptr + 0x4

    Case 2:
    (ptr->toto).x => @32[ptr + 0x4]
    &((ptr->toto).x) => ptr + 0x4

    Case 3:
    (ptr->toto).y => ptr + 0x8
    &((ptr->toto).y) => ptr + 0x8

    Case 4:
    (ptr->toto).y[1] => @32[ptr + 0x8 + 0x4]
    &((ptr->toto).y[1]) => ptr + 0x8 + 0x4

    """

    def __init__(self, expr_types, types_mngr):
        """Init ExprCAccess

        @expr_types: a dictionnary linking ID names to their types
        @types_mngr: types manager
        """

        self.expr_types = expr_types
        self.types_mngr = types_mngr

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types

    CST = "CST"

    def reduce_known_expr(self, node, ctxt, **kwargs):
        """Reduce known expressions"""
        if str(node.expr) in ctxt:
            objc = ctxt[str(node.expr)]
            out = (node.expr, objc)
        elif node.expr.is_id():
            out = (node.expr, None)
        else:
            out = None
        return out

    def reduce_int(self, node, **kwargs):
        """Reduce ExprInt"""

        if not isinstance(node.expr, ExprInt):
            return None
        return self.CST

    def reduce_op_memberof(self, node, **kwargs):
        """Reduce -> operator"""

        if not node.expr.is_op('->'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprId)
        field = node.args[1].expr.name
        src, src_type = node.args[0].info
        if src_type is None:
            return None
        assert isinstance(src_type, (ObjCPtr, ObjCArray))
        struct_dst = src_type.objtype
        assert isinstance(struct_dst, ObjCStruct)

        found = False
        for name, objtype, offset, _ in struct_dst.fields:
            if name != field:
                continue
            expr = src + ExprInt(offset, src.size)
            if isinstance(objtype, (ObjCArray, ObjCStruct, ObjCUnion)):
                pass
            else:
                expr = ExprMem(expr, objtype.size * 8)
            assert not found
            found = True
            out = (expr, objtype)
        assert found
        return out

    def reduce_op_field(self, node, **kwargs):
        """Reduce field operator (Struct or Union)"""

        if not node.expr.is_op('field'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprId)
        field = node.args[1].expr.name
        src, src_type = node.args[0].info
        struct_dst = src_type

        if isinstance(struct_dst, ObjCStruct):
            found = False
            for name, objtype, offset, _ in struct_dst.fields:
                if name != field:
                    continue
                expr = src + ExprInt(offset, src.size)
                if isinstance(objtype, ObjCArray):
                    # Case 4
                    pass
                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                    # Case 1
                    pass
                else:
                    # Case 2
                    expr = ExprMem(expr, objtype.size * 8)
                assert not found
                found = True
                out = (expr, objtype)
        elif isinstance(struct_dst, ObjCUnion):
            found = False
            for name, objtype, offset, _ in struct_dst.fields:
                if name != field:
                    continue
                expr = src + ExprInt(offset, src.size)
                if isinstance(objtype, ObjCArray):
                    # Case 4
                    pass
                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                    # Case 1
                    pass
                else:
                    # Case 2
                    expr = ExprMem(expr, objtype.size * 8)
                assert not found
                found = True
                out = (expr, objtype)
        else:
            raise NotImplementedError("unknown ObjC")
        assert found
        return out

    def reduce_op_array(self, node, **kwargs):
        """Reduce array operator"""

        if not node.expr.is_op('[]'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprInt)
        cst = node.args[1].expr
        src, src_type = node.args[0].info
        objtype = src_type.objtype
        expr = src + cst * ExprInt(objtype.size, cst.size)
        if isinstance(src_type, ObjCPtr):
            if isinstance(objtype, ObjCArray):
                final = objtype.objtype
                expr = src + cst * ExprInt(final.size, cst.size)
                objtype = final
                expr = ExprMem(expr, final.size * 8)
                found = True
            else:
                expr = ExprMem(expr, objtype.size * 8)
                found = True
        elif isinstance(src_type, ObjCArray):
            if isinstance(objtype, ObjCArray):
                final = objtype
                found = True
            elif isinstance(objtype, ObjCStruct):
                found = True
            else:
                expr = ExprMem(expr, objtype.size * 8)
                found = True
        else:
            raise NotImplementedError("Unknown access" % node.expr)
        assert found
        out = (expr, objtype)
        return out

    def reduce_op_addr(self, node, **kwargs):
        """Reduce addr operator"""

        if not node.expr.is_op('addr'):
            return None
        assert len(node.args) == 1
        out = []
        src, src_type = node.args[0].info

        void_type = self.types_mngr.void_ptr

        if isinstance(src_type, ObjCArray):
            out = (src.arg, ObjCPtr(src_type.objtype,
                                    void_type.align, void_type.size))
        elif isinstance(src, ExprMem):
            out = (src.arg, ObjCPtr(src_type,
                                    void_type.align, void_type.size))
        elif isinstance(src_type, ObjCStruct):
            out = (src, ObjCPtr(src_type,
                                void_type.align, void_type.size))
        elif isinstance(src_type, ObjCUnion):
            out = (src, ObjCPtr(src_type,
                                void_type.align, void_type.size))
        else:
            raise NotImplementedError("unk type")
        return out

    def reduce_op_deref(self, node, **kwargs):
        """Reduce deref operator"""

        if not node.expr.is_op('deref'):
            return None
        out = []
        src, src_type = node.args[0].info
        assert isinstance(src_type, (ObjCPtr, ObjCArray))
        void_type = self.types_mngr.void_ptr
        if isinstance(src_type, ObjCPtr):
            if isinstance(src_type.objtype, ObjCArray):
                size = void_type.size*8
            else:
                size = src_type.objtype.size * 8
            out = (ExprMem(src, size), (src_type.objtype))
        else:
            size = src_type.objtype.size * 8
            out = (ExprMem(src, size), (src_type.objtype))
        return out

    reduction_rules = [reduce_known_expr,
                       reduce_int,
                       reduce_op_memberof,
                       reduce_op_field,
                       reduce_op_array,
                       reduce_op_addr,
                       reduce_op_deref,
                      ]

    def get_expr(self, expr, c_context):
        """Translate a Miasm expression @expr (representing a C access) into a
        tuple composed of a native Miasm expression and its C type.
        @expr: Miasm expression (representing a C access)
        @c_context: a dictionnary linking known tokens (strings) to their
        types. A token is linked to only one type.
        """
        ret = self.reduce(expr, ctxt=c_context)
        if ret.info is None:
            return (None, None)
        return ret.info


class CTypesManager(object):
    """Represent a C object, without any layout information"""

    def __init__(self, types_ast, leaf_types):
        self.types_ast = types_ast
        self.leaf_types = leaf_types

    @property
    def void_ptr(self):
        """Retrieve a void* objc"""
        return self.leaf_types.types.get(CTypePtr(CTypeId('void')))

    @property
    def padding(self):
        """Retrieve a padding ctype"""
        return CTypeId(PADDING_TYPE_NAME)

    def _get_objc(self, type_id, resolved=None, to_fix=None, lvl=0):
        if resolved is None:
            resolved = {}
        if to_fix is None:
            to_fix = []
        if type_id in resolved:
            return resolved[type_id]
        type_id = self.types_ast.get_type(type_id)
        fixed = True
        if isinstance(type_id, CTypeId):
            out = self.leaf_types.types.get(type_id, None)
            assert out is not None
        elif isinstance(type_id, CTypeUnion):
            args = []
            align_max, size_max = 0, 0
            for name, field in type_id.fields:
                objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                resolved[field] = objc
                align_max = max(align_max, objc.align)
                size_max = max(size_max, objc.size)
                args.append((name, objc, 0, objc.size))

            align, size = self.union_compute_align_size(align_max, size_max)
            out = ObjCUnion(type_id.name, align, size, args)

        elif isinstance(type_id, CTypeStruct):
            align_max, size_max = 0, 0

            args = []
            offset, align_max = 0, 1
            pad_index = 0
            for name, field in type_id.fields:
                objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                resolved[field] = objc
                align_max = max(align_max, objc.align)
                new_offset = self.struct_compute_field_offset(objc, offset)
                if new_offset - offset:
                    pad_name = "__PAD__%d__" % pad_index
                    pad_index += 1
                    size = new_offset - offset
                    pad_objc = self._get_objc(CTypeArray(self.padding, size), resolved, to_fix, lvl + 1)
                    args.append((pad_name, pad_objc, offset, pad_objc.size))
                offset = new_offset
                args.append((name, objc, offset, objc.size))
                offset += objc.size

            align, size = self.struct_compute_align_size(align_max, offset)
            out = ObjCStruct(type_id.name, align, size, args)

        elif isinstance(type_id, CTypePtr):
            target = type_id.target
            out = ObjCPtr(None, self.void_ptr.align, self.void_ptr.size)
            fixed = False

        elif isinstance(type_id, CTypeArray):
            target = type_id.target
            objc = self._get_objc(target, resolved, to_fix, lvl + 1)
            resolved[target] = objc
            if type_id.size is None:
                # case: toto[]
                # return ObjCPtr
                out = ObjCPtr(objc, self.void_ptr.align, self.void_ptr.size)
            else:
                size = self.size_to_int(type_id.size)
                if size is None:
                    raise RuntimeError('Enable to compute objc size')
                else:
                    out = ObjCArray(objc, size)
            assert out.size is not None and out.align is not None
        elif isinstance(type_id, CTypeEnum):
            # Enum are integer
            return self.leaf_types.types.get(CTypeId('int'))
        elif isinstance(type_id, CTypeFunc):
            type_ret = self._get_objc(
                type_id.type_ret, resolved, to_fix, lvl + 1)
            resolved[type_id.type_ret] = type_ret
            args = []
            for name, arg in type_id.args:
                objc = self._get_objc(arg, resolved, to_fix, lvl + 1)
                resolved[arg] = objc
                args.append((name, objc))
            out = ObjCFunc(type_id.name, type_id.abi, type_ret, args,
                           self.void_ptr.align, self.void_ptr.size)
        elif isinstance(type_id, CTypeEllipsis):
            out = ObjCEllipsis()
        else:
            raise TypeError("Unknown type %r" % type_id.__class__)
        if not isinstance(out, ObjCEllipsis):
            assert out.align is not None and out.size is not None

        if fixed:
            resolved[type_id] = out
        else:
            to_fix.append((type_id, out))
        return out

    def get_objc(self, type_id):
        """Get the ObjC corresponding to the CType @type_id
        @type_id: CTypeBase instance"""
        resolved = {}
        to_fix = []
        out = self._get_objc(type_id, resolved, to_fix)
        # Fix sub objects
        while to_fix:
            type_id, objc_to_fix = to_fix.pop()
            objc = self._get_objc(type_id.target, resolved, to_fix)
            objc_to_fix.objtype = objc
        self.check_objc(out)
        return out

    def check_objc(self, objc, done=None):
        """Ensure each sub ObjC is resolved
        @objc: ObjC instance"""
        if done is None:
            done = set()
        if objc in done:
            return True
        done.add(objc)
        if isinstance(objc, (ObjCDecl, ObjCInt, ObjCEllipsis)):
            return True
        elif isinstance(objc, (ObjCPtr, ObjCArray)):
            assert self.check_objc(objc.objtype, done)
            return True
        elif isinstance(objc, (ObjCStruct, ObjCUnion)):
            for _, field, _, _ in objc.fields:
                assert self.check_objc(field, done)
            return True
        elif isinstance(objc, ObjCFunc):
            assert self.check_objc(objc.type_ret, done)
            for name, arg in objc.args:
                assert self.check_objc(arg, done)
            return True
        else:
            assert False

    def size_to_int(self, size):
        """Resolve an array size
        @size: CTypeOp or integer"""
        if isinstance(size, CTypeOp):
            assert len(size.args) == 2
            arg0, arg1 = [self.size_to_int(arg) for arg in size.args]
            if size.operator == "+":
                return arg0 + arg1
            elif size.operator == "-":
                return arg0 - arg1
            elif size.operator == "*":
                return arg0 * arg1
            elif size.operator == "/":
                return arg0 / arg1
            elif size.operator == "<<":
                return arg0 << arg1
            elif size.operator == ">>":
                return arg0 >> arg1
            else:
                raise ValueError("Unknown operator %s" % size.operator)
        elif isinstance(size, (int, long)):
            return size
        elif isinstance(size, CTypeSizeof):
            obj = self._get_objc(size.target)
            return obj.size
        else:
            raise TypeError("Unknown size type")

    def struct_compute_field_offset(self, obj, offset):
        """Compute the offset of the field @obj in the current structure"""
        raise NotImplementedError("Abstract method")

    def struct_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current structure"""
        raise NotImplementedError("Abstract method")

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union"""
        raise NotImplementedError("Abstract method")


class CTypesManagerNotPacked(CTypesManager):
    """Store defined C types (not packed)"""

    def struct_compute_field_offset(self, obj, offset):
        """Compute the offset of the field @obj in the current structure
        (not packed)"""

        if obj.align > 1:
            offset = (offset + obj.align - 1) & ~(obj.align - 1)
        return offset

    def struct_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current structure
        (not packed)"""
        if align_max > 1:
            size = (size + align_max - 1) & ~(align_max - 1)
        return align_max, size

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union
        (not packed)"""
        return align_max, size


class CTypesManagerPacked(CTypesManager):
    """Store defined C types (packed form)"""

    def struct_compute_field_offset(self, _, offset):
        """Compute the offset of the field @obj in the current structure
        (packed form)"""
        return offset

    def struct_compute_align_size(self, _, size):
        """Compute the alignment and size of the current structure
        (packed form)"""
        return 1, size

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union
        (packed form)"""
        return 1, size


class CHandler(object):
    """
    C manipulator for Miasm
    Miasm expr <-> C
    """

    exprCToExpr_cls = ExprCToExpr
    exprToAccessC_cls = ExprToAccessC

    def __init__(self, types_mngr, expr_types,
                 simplify_c=access_simplifier,
                 enforce_strict_access=True):
        self.exprc2expr = self.exprCToExpr_cls(expr_types, types_mngr)
        self.access_c_gen = self.exprToAccessC_cls(expr_types,
                                                   types_mngr,
                                                   enforce_strict_access)
        self.types_mngr = types_mngr
        self.simplify_c = simplify_c
        self.expr_types = expr_types

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types
        self.exprc2expr.updt_expr_types(expr_types)
        self.access_c_gen.updt_expr_types(expr_types)

    def expr_to_c_access(self, expr, expr_context=None):
        """Generate the C access object(s) for a given native Miasm expression.
        @expr: Miasm expression
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        if expr_context is None:
            expr_context = self.expr_types
        return self.access_c_gen.get_accesses(expr, expr_context)


    def expr_to_c_and_types(self, expr, expr_context=None):
        """Generate the C access string and corresponding type for a given
        native Miasm expression.
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        accesses = set()
        for access in self.expr_to_c_access(expr, expr_context):
            c_str = access_str(access.to_expr().visit(self.simplify_c))
            accesses.add((c_str, access.ctype))
        return accesses

    def expr_to_c(self, expr, expr_context=None):
        """Convert a Miasm @expr into it's C equivalent string
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        return set(access[0]
                   for access in self.expr_to_c_and_types(expr, expr_context))

    def expr_to_types(self, expr, expr_context=None):
        """Get the possible types of the Miasm @expr
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        return set(access.ctype
                   for access in self.expr_to_c_access(expr, expr_context))

    def c_to_expr_and_type(self, c_str, c_context):
        """Convert a C string expression to a Miasm expression and it's
        corresponding c type
        @c_str: C string
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        ast = parse_access(c_str)
        access_c = ast_get_c_access_expr(ast, c_context)
        return self.exprc2expr.get_expr(access_c, c_context)

    def c_to_expr(self, c_str, c_context):
        """Convert a C string expression to a Miasm expression
        @c_str: C string
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        expr, _ = self.c_to_expr_and_type(c_str, c_context)
        return expr

    def c_to_type(self, c_str, c_context):
        """Get the type of a C string expression
        @expr: Miasm expression
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        _, ctype = self.c_to_expr_and_type(c_str, c_context)
        return ctype


class CLeafTypes(object):
    """Define C types sizes/alignement for a given architecture"""
    pass

Module variables

var OBJC_PRIO

var PADDING_TYPE_NAME

Functions

def access_simplifier(

expr)

Expression visitor to simplify a C access represented in Miasm

@expr: Miasm expression representing the C access

Example:

IN: (In c: ['(&((&(((ptr_Test)).a))[0]))']) [ExprOp('deref', ExprOp('addr', ExprOp('[]', ExprOp('addr', ExprOp('field', ExprOp('deref', ExprId('ptr_Test', 64)), ExprId('a', 64))), ExprInt(0x0, 64))))]

OUT: (In c: ['(ptr_Test)->a']) [ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))]

def access_simplifier(expr):
    """Expression visitor to simplify a C access represented in Miasm

    @expr: Miasm expression representing the C access

    Example:

    IN: (In c: ['*(&((&((*(ptr_Test)).a))[0]))'])
    [ExprOp('deref', ExprOp('addr', ExprOp('[]', ExprOp('addr',
    ExprOp('field', ExprOp('deref', ExprId('ptr_Test', 64)),
    ExprId('a', 64))), ExprInt(0x0, 64))))]

    OUT: (In c: ['(ptr_Test)->a'])
    [ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))]
    """

    if (expr.is_op("addr") and
            expr.args[0].is_op("[]") and
            expr.args[0].args[1] == ExprInt(0, 64)):
        return expr.args[0].args[0]
    elif (expr.is_op("[]") and
          expr.args[0].is_op("addr") and
          expr.args[1] == ExprInt(0, 64)):
        return expr.args[0].args[0]
    elif (expr.is_op("addr") and
          expr.args[0].is_op("deref")):
        return expr.args[0].args[0]
    elif (expr.is_op("deref") and
          expr.args[0].is_op("addr")):
        return expr.args[0].args[0]
    elif (expr.is_op("field") and
          expr.args[0].is_op("deref")):
        return ExprOp("->", expr.args[0].args[0], expr.args[1])
    return expr

def access_str(

expr)

Return the C string of a C access represented in Miasm

@expr: Miasm expression representing the C access

In: ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64)) OUT: '(ptr_Test)->a'

def access_str(expr):
    """Return the C string of a C access represented in Miasm

    @expr: Miasm expression representing the C access

    In:
    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
    OUT:
    '(ptr_Test)->a'
    """

    if isinstance(expr, ExprId):
        out = str(expr)
    elif isinstance(expr, ExprInt):
        out = str(int(expr))
    elif expr.is_op("addr"):
        out = "&(%s)" % access_str(expr.args[0])
    elif expr.is_op("deref"):
        out = "*(%s)" % access_str(expr.args[0])
    elif expr.is_op("field"):
        out = "(%s).%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
    elif expr.is_op("->"):
        out = "(%s)->%s" % (access_str(expr.args[0]), access_str(expr.args[1]))
    elif expr.is_op("[]"):
        out = "(%s)[%s]" % (access_str(expr.args[0]), access_str(expr.args[1]))
    else:
        raise RuntimeError("unknown op")

    return out

def ast_get_c_access_expr(

ast, expr_types, lvl=0)

Transform C ast object into a C Miasm expression

@ast: parsed pycparser.c_ast object @expr_types: a dictionnary linking ID names to their types @lvl: actual recursion level

Example:

IN: StructRef: -> ID: ptr_Test ID: a

OUT: ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))

def ast_get_c_access_expr(ast, expr_types, lvl=0):
    """Transform C ast object into a C Miasm expression

    @ast: parsed pycparser.c_ast object
    @expr_types: a dictionnary linking ID names to their types
    @lvl: actual recursion level

    Example:

    IN:
    StructRef: ->
      ID: ptr_Test
      ID: a

    OUT:
    ExprOp('->', ExprId('ptr_Test', 64), ExprId('a', 64))
    """

    if isinstance(ast, c_ast.Constant):
        obj = ExprInt(int(ast.value), 64)
    elif isinstance(ast, c_ast.StructRef):
        name, field = ast.name, ast.field.name
        name = ast_get_c_access_expr(name, expr_types)
        if ast.type == "->":
            s_name = name
            s_field = ExprId(field, 64)
            obj = ExprOp('->', s_name, s_field)
        elif ast.type == ".":
            s_name = name
            s_field = ExprId(field, 64)
            obj = ExprOp("field", s_name, s_field)
        else:
            raise RuntimeError("Unknown struct access")
    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "&":
        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
        obj = ExprOp("addr", tmp)
    elif isinstance(ast, c_ast.ArrayRef):
        tmp = ast_get_c_access_expr(ast.name, expr_types, lvl + 1)
        index = ast_get_c_access_expr(ast.subscript, expr_types, lvl + 1)
        obj = ExprOp("[]", tmp, index)
    elif isinstance(ast, c_ast.ID):
        assert ast.name in expr_types
        obj = ExprId(ast.name, 64)
    elif isinstance(ast, c_ast.UnaryOp) and ast.op == "*":
        tmp = ast_get_c_access_expr(ast.expr, expr_types, lvl + 1)
        obj = ExprOp("deref", tmp)
    else:
        raise NotImplementedError("Unknown type")
    return obj

def missing_definition(

objtype)

def missing_definition(objtype):
    warnings.warn("Null size type: Missing definition? %r" % objtype)

def objc_to_str(

objc, result=None)

def objc_to_str(objc, result=None):
    if result is None:
        result = ""
    while True:
        if isinstance(objc, ObjCArray):
            result += "[%d]" % objc.elems
            objc = objc.objtype
        elif isinstance(objc, ObjCPtr):
            if not result and isinstance(objc.objtype, ObjCFunc):
                result = objc.objtype.name
            if isinstance(objc.objtype, (ObjCPtr, ObjCDecl, ObjCStruct, ObjCUnion)):
                result = "*%s" % result
            else:
                result = "(*%s)" % result

            objc = objc.objtype
        elif isinstance(objc, (ObjCDecl, ObjCStruct, ObjCUnion)):
            if result:
                result = "%s %s" % (objc, result)
            else:
                result = str(objc)
            break
        elif isinstance(objc, ObjCFunc):
            args_str = []
            for name, arg in objc.args:
                args_str.append(objc_to_str(arg, name))
            args = ", ".join(args_str)
            result += "(%s)" % args
            objc = objc.type_ret
        elif isinstance(objc, ObjCInt):
            return "int"
        elif isinstance(objc, ObjCEllipsis):
            return "..."
        else:
            raise TypeError("Unknown c type")
    return result

def parse_access(

c_access)

Parse C access

@c_access: C access string

def parse_access(c_access):
    """Parse C access

    @c_access: C access string
    """

    main = '''
    int main() {
    %s;
    }
    ''' % c_access

    parser = c_parser.CParser()
    node = parser.parse(main, filename='<stdin>')
    access = node.ext[-1].body.block_items[0]
    return access

Classes

class CGen

Generic object to represent a C expression

class CGen(object):
    """Generic object to represent a C expression"""

    default_size = 64


    def __init__(self, ctype):
        self._ctype = ctype

    @property
    def ctype(self):
        """Type (ObjC instance) of the current object"""
        return self._ctype

    def __hash__(self):
        return hash(self.__class__)

    def __eq__(self, other):
        return (self.__class__ == other.__class__ and
                self._ctype == other.ctype)

    def __ne__(self, other):
        return not self.__eq__(other)

    def to_c(self):
        """Generate corresponding C"""

        raise NotImplementedError("Virtual")

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        raise NotImplementedError("Virtual")

Ancestors (in MRO)

  • CGen
  • __builtin__.object

Class variables

var default_size

Instance variables

var ctype

Type (ObjC instance) of the current object

Methods

def __init__(

self, ctype)

def __init__(self, ctype):
    self._ctype = ctype

def to_c(

self)

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    raise NotImplementedError("Virtual")

def to_expr(

self)

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    raise NotImplementedError("Virtual")

class CGenArray

C Array

This object does not deref the source, it only do object casting.

IN: - obj OUT: - X => X - ..[][] => ..[] - X[] => X*

class CGenArray(CGen):
    """
    C Array

    This object does *not* deref the source, it only do object casting.

    IN:
    - obj
    OUT:
    - X* => X*
    - ..[][] => ..[]
    - X[] => X*
    """

    def __init__(self, base, elems, void_p_align, void_p_size):
        ctype = base.ctype
        if isinstance(ctype, ObjCPtr):
            pass
        elif isinstance(ctype, ObjCArray) and isinstance(ctype.objtype, ObjCArray):
            ctype = ctype.objtype
        elif isinstance(ctype, ObjCArray):
            ctype = ObjCPtr(ctype.objtype, void_p_align, void_p_size)
        else:
            raise TypeError("Strange case")
        self._base = base
        self._elems = elems
        super(CGenArray, self).__init__(ctype)

    @property
    def base(self):
        """Base object supporting the array"""
        return self._base

    @property
    def elems(self):
        """Number of elements in the array"""
        return self._elems

    def __hash__(self):
        return hash((super(CGenArray, self).__hash__(), self._base, self._elems))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._base == other.base and
                self._elems == other.elems)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.base)

    def to_c(self):
        """Generate corresponding C"""

        if isinstance(self.ctype, ObjCPtr):
            out_str = "&((%s)[%d])" % (self.base.to_c(), self.elems)
        elif isinstance(self.ctype, ObjCArray):
            out_str = "(%s)[%d]" % (self.base.to_c(), self.elems)
        else:
            raise RuntimeError("Strange case")
        return out_str

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if isinstance(self.ctype, ObjCPtr):
            return ExprOp("addr",
                          ExprOp("[]",
                                 self.base.to_expr(),
                                 ExprInt(self.elems, self.default_size)))
        elif isinstance(self.ctype, ObjCArray):
            return ExprOp("[]",
                          self.base.to_expr(),
                          ExprInt(self.elems, self.default_size))
        else:
            raise RuntimeError("Strange case")

Ancestors (in MRO)

Class variables

var default_size

Inheritance: CGen.default_size

Instance variables

var base

Base object supporting the array

var ctype

Inheritance: CGen.ctype

Type (ObjC instance) of the current object

var elems

Number of elements in the array

Methods

def __init__(

self, base, elems, void_p_align, void_p_size)

Inheritance: CGen.__init__

def __init__(self, base, elems, void_p_align, void_p_size):
    ctype = base.ctype
    if isinstance(ctype, ObjCPtr):
        pass
    elif isinstance(ctype, ObjCArray) and isinstance(ctype.objtype, ObjCArray):
        ctype = ctype.objtype
    elif isinstance(ctype, ObjCArray):
        ctype = ObjCPtr(ctype.objtype, void_p_align, void_p_size)
    else:
        raise TypeError("Strange case")
    self._base = base
    self._elems = elems
    super(CGenArray, self).__init__(ctype)

def to_c(

self)

Inheritance: CGen.to_c

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    if isinstance(self.ctype, ObjCPtr):
        out_str = "&((%s)[%d])" % (self.base.to_c(), self.elems)
    elif isinstance(self.ctype, ObjCArray):
        out_str = "(%s)[%d]" % (self.base.to_c(), self.elems)
    else:
        raise RuntimeError("Strange case")
    return out_str

def to_expr(

self)

Inheritance: CGen.to_expr

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    if isinstance(self.ctype, ObjCPtr):
        return ExprOp("addr",
                      ExprOp("[]",
                             self.base.to_expr(),
                             ExprInt(self.elems, self.default_size)))
    elif isinstance(self.ctype, ObjCArray):
        return ExprOp("[]",
                      self.base.to_expr(),
                      ExprInt(self.elems, self.default_size))
    else:
        raise RuntimeError("Strange case")

class CGenDeref

C dereference

IN: - ptr OUT: - X* => X

class CGenDeref(CGen):
    """
    C dereference

    IN:
    - ptr
    OUT:
    - X* => X
    """

    def __init__(self, ptr):
        assert isinstance(ptr.ctype, ObjCPtr)
        self._ptr = ptr
        super(CGenDeref, self).__init__(ptr.ctype.objtype)

    @property
    def ptr(self):
        """Pointer object"""
        return self._ptr

    def __hash__(self):
        return hash((super(CGenDeref, self).__hash__(), self._ptr))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._ptr == other.ptr)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.ptr)

    def to_c(self):
        """Generate corresponding C"""

        if not isinstance(self.ptr.ctype, ObjCPtr):
            raise RuntimeError()
        return "*(%s)" % (self.ptr.to_c())

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if not isinstance(self.ptr.ctype, ObjCPtr):
            raise RuntimeError()
        return ExprOp("deref", self.ptr.to_expr())

Ancestors (in MRO)

Class variables

var default_size

Inheritance: CGen.default_size

Instance variables

var ctype

Inheritance: CGen.ctype

Type (ObjC instance) of the current object

var ptr

Pointer object

Methods

def __init__(

self, ptr)

Inheritance: CGen.__init__

def __init__(self, ptr):
    assert isinstance(ptr.ctype, ObjCPtr)
    self._ptr = ptr
    super(CGenDeref, self).__init__(ptr.ctype.objtype)

def to_c(

self)

Inheritance: CGen.to_c

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    if not isinstance(self.ptr.ctype, ObjCPtr):
        raise RuntimeError()
    return "*(%s)" % (self.ptr.to_c())

def to_expr(

self)

Inheritance: CGen.to_expr

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    if not isinstance(self.ptr.ctype, ObjCPtr):
        raise RuntimeError()
    return ExprOp("deref", self.ptr.to_expr())

class CGenField

Field of a C struct/union

IN: - struct (not ptr struct) - field name OUT: - input type of the field => output type - X[] => X[] - X => X*

class CGenField(CGen):
    """
    Field of a C struct/union

    IN:
    - struct (not ptr struct)
    - field name
    OUT:
    - input type of the field => output type
    - X[] => X[]
    - X => X*
    """

    def __init__(self, struct, field, fieldtype, void_p_align, void_p_size):
        self._struct = struct
        self._field = field
        assert isinstance(field, str)
        if isinstance(fieldtype, ObjCArray):
            ctype = fieldtype
        else:
            ctype = ObjCPtr(fieldtype, void_p_align, void_p_size)
        super(CGenField, self).__init__(ctype)

    @property
    def struct(self):
        """Structure containing the field"""
        return self._struct

    @property
    def field(self):
        """Field name"""
        return self._field

    def __hash__(self):
        return hash((super(CGenField, self).__hash__(), self._struct, self._field))

    def __eq__(self, other):
        return (super(CGenField, self).__eq__(other) and
                self._struct == other.struct and
                self._field == other.field)

    def to_c(self):
        """Generate corresponding C"""

        if isinstance(self.ctype, ObjCArray):
            return "(%s).%s" % (self.struct.to_c(), self.field)
        elif isinstance(self.ctype, ObjCPtr):
            return "&((%s).%s)" % (self.struct.to_c(), self.field)
        else:
            raise RuntimeError("Strange case")

    def __repr__(self):
        return "<%s %s %s>" % (self.__class__.__name__,
                               self.struct,
                               self.field)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        if isinstance(self.ctype, ObjCArray):
            return ExprOp("field",
                          self.struct.to_expr(),
                          ExprId(self.field, self.default_size))
        elif isinstance(self.ctype, ObjCPtr):
            return ExprOp("addr",
                          ExprOp("field",
                                 self.struct.to_expr(),
                                 ExprId(self.field, self.default_size)))
        else:
            raise RuntimeError("Strange case")

Ancestors (in MRO)

Class variables

var default_size

Inheritance: CGen.default_size

Instance variables

var ctype

Inheritance: CGen.ctype

Type (ObjC instance) of the current object

var field

Field name

var struct

Structure containing the field

Methods

def __init__(

self, struct, field, fieldtype, void_p_align, void_p_size)

Inheritance: CGen.__init__

def __init__(self, struct, field, fieldtype, void_p_align, void_p_size):
    self._struct = struct
    self._field = field
    assert isinstance(field, str)
    if isinstance(fieldtype, ObjCArray):
        ctype = fieldtype
    else:
        ctype = ObjCPtr(fieldtype, void_p_align, void_p_size)
    super(CGenField, self).__init__(ctype)

def to_c(

self)

Inheritance: CGen.to_c

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    if isinstance(self.ctype, ObjCArray):
        return "(%s).%s" % (self.struct.to_c(), self.field)
    elif isinstance(self.ctype, ObjCPtr):
        return "&((%s).%s)" % (self.struct.to_c(), self.field)
    else:
        raise RuntimeError("Strange case")

def to_expr(

self)

Inheritance: CGen.to_expr

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    if isinstance(self.ctype, ObjCArray):
        return ExprOp("field",
                      self.struct.to_expr(),
                      ExprId(self.field, self.default_size))
    elif isinstance(self.ctype, ObjCPtr):
        return ExprOp("addr",
                      ExprOp("field",
                             self.struct.to_expr(),
                             ExprId(self.field, self.default_size)))
    else:
        raise RuntimeError("Strange case")

class CGenId

ID of a C object

class CGenId(CGen):
    """ID of a C object"""

    def __init__(self, ctype, name):
        self._name = name
        assert isinstance(name, str)
        super(CGenId, self).__init__(ctype)

    @property
    def name(self):
        """Name of the Id"""
        return self._name

    def __hash__(self):
        return hash((super(CGenId, self).__hash__(), self._name))

    def __eq__(self, other):
        return (super(CGenId, self).__eq__(other) and
                self._name == other.name)

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.name)

    def to_c(self):
        """Generate corresponding C"""

        return "%s" % (self.name)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        return ExprId(self.name, self.default_size)

Ancestors (in MRO)

Class variables

var default_size

Inheritance: CGen.default_size

Instance variables

var ctype

Inheritance: CGen.ctype

Type (ObjC instance) of the current object

var name

Name of the Id

Methods

def __init__(

self, ctype, name)

Inheritance: CGen.__init__

def __init__(self, ctype, name):
    self._name = name
    assert isinstance(name, str)
    super(CGenId, self).__init__(ctype)

def to_c(

self)

Inheritance: CGen.to_c

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    return "%s" % (self.name)

def to_expr(

self)

Inheritance: CGen.to_expr

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    return ExprId(self.name, self.default_size)

class CGenInt

Int C object

class CGenInt(CGen):
    """Int C object"""

    def __init__(self, integer):
        assert isinstance(integer, (int, long))
        self._integer = integer
        super(CGenInt, self).__init__(ObjCInt())

    @property
    def integer(self):
        """Value of the object"""
        return self._integer

    def __hash__(self):
        return hash((super(CGenInt, self).__hash__(), self._integer))

    def __eq__(self, other):
        return (super(CGenInt, self).__eq__(other) and
                self._integer == other.integer)

    def to_c(self):
        """Generate corresponding C"""

        return "0x%X" % self.integer

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.integer)

    def to_expr(self):
        """Generate Miasm expression representing the C access"""

        return ExprInt(self.integer, self.default_size)

Ancestors (in MRO)

Class variables

var default_size

Inheritance: CGen.default_size

Instance variables

var ctype

Inheritance: CGen.ctype

Type (ObjC instance) of the current object

var integer

Value of the object

Methods

def __init__(

self, integer)

Inheritance: CGen.__init__

def __init__(self, integer):
    assert isinstance(integer, (int, long))
    self._integer = integer
    super(CGenInt, self).__init__(ObjCInt())

def to_c(

self)

Inheritance: CGen.to_c

Generate corresponding C

def to_c(self):
    """Generate corresponding C"""
    return "0x%X" % self.integer

def to_expr(

self)

Inheritance: CGen.to_expr

Generate Miasm expression representing the C access

def to_expr(self):
    """Generate Miasm expression representing the C access"""
    return ExprInt(self.integer, self.default_size)

class CHandler

C manipulator for Miasm Miasm expr <-> C

class CHandler(object):
    """
    C manipulator for Miasm
    Miasm expr <-> C
    """

    exprCToExpr_cls = ExprCToExpr
    exprToAccessC_cls = ExprToAccessC

    def __init__(self, types_mngr, expr_types,
                 simplify_c=access_simplifier,
                 enforce_strict_access=True):
        self.exprc2expr = self.exprCToExpr_cls(expr_types, types_mngr)
        self.access_c_gen = self.exprToAccessC_cls(expr_types,
                                                   types_mngr,
                                                   enforce_strict_access)
        self.types_mngr = types_mngr
        self.simplify_c = simplify_c
        self.expr_types = expr_types

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types
        self.exprc2expr.updt_expr_types(expr_types)
        self.access_c_gen.updt_expr_types(expr_types)

    def expr_to_c_access(self, expr, expr_context=None):
        """Generate the C access object(s) for a given native Miasm expression.
        @expr: Miasm expression
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        if expr_context is None:
            expr_context = self.expr_types
        return self.access_c_gen.get_accesses(expr, expr_context)


    def expr_to_c_and_types(self, expr, expr_context=None):
        """Generate the C access string and corresponding type for a given
        native Miasm expression.
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        accesses = set()
        for access in self.expr_to_c_access(expr, expr_context):
            c_str = access_str(access.to_expr().visit(self.simplify_c))
            accesses.add((c_str, access.ctype))
        return accesses

    def expr_to_c(self, expr, expr_context=None):
        """Convert a Miasm @expr into it's C equivalent string
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        return set(access[0]
                   for access in self.expr_to_c_and_types(expr, expr_context))

    def expr_to_types(self, expr, expr_context=None):
        """Get the possible types of the Miasm @expr
        @expr_context: a dictionnary linking known expressions to a set of types
        """

        return set(access.ctype
                   for access in self.expr_to_c_access(expr, expr_context))

    def c_to_expr_and_type(self, c_str, c_context):
        """Convert a C string expression to a Miasm expression and it's
        corresponding c type
        @c_str: C string
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        ast = parse_access(c_str)
        access_c = ast_get_c_access_expr(ast, c_context)
        return self.exprc2expr.get_expr(access_c, c_context)

    def c_to_expr(self, c_str, c_context):
        """Convert a C string expression to a Miasm expression
        @c_str: C string
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        expr, _ = self.c_to_expr_and_type(c_str, c_context)
        return expr

    def c_to_type(self, c_str, c_context):
        """Get the type of a C string expression
        @expr: Miasm expression
        @c_context: a dictionnary linking known tokens (strings) to its type.
        """

        _, ctype = self.c_to_expr_and_type(c_str, c_context)
        return ctype

Ancestors (in MRO)

Class variables

var exprCToExpr_cls

var exprToAccessC_cls

Instance variables

var access_c_gen

var expr_types

var exprc2expr

var simplify_c

var types_mngr

Methods

def __init__(

self, types_mngr, expr_types, simplify_c=<function access_simplifier at 0x7f19adeeb938>, enforce_strict_access=True)

def __init__(self, types_mngr, expr_types,
             simplify_c=access_simplifier,
             enforce_strict_access=True):
    self.exprc2expr = self.exprCToExpr_cls(expr_types, types_mngr)
    self.access_c_gen = self.exprToAccessC_cls(expr_types,
                                               types_mngr,
                                               enforce_strict_access)
    self.types_mngr = types_mngr
    self.simplify_c = simplify_c
    self.expr_types = expr_types

def c_to_expr(

self, c_str, c_context)

Convert a C string expression to a Miasm expression @c_str: C string @c_context: a dictionnary linking known tokens (strings) to its type.

def c_to_expr(self, c_str, c_context):
    """Convert a C string expression to a Miasm expression
    @c_str: C string
    @c_context: a dictionnary linking known tokens (strings) to its type.
    """
    expr, _ = self.c_to_expr_and_type(c_str, c_context)
    return expr

def c_to_expr_and_type(

self, c_str, c_context)

Convert a C string expression to a Miasm expression and it's corresponding c type @c_str: C string @c_context: a dictionnary linking known tokens (strings) to its type.

def c_to_expr_and_type(self, c_str, c_context):
    """Convert a C string expression to a Miasm expression and it's
    corresponding c type
    @c_str: C string
    @c_context: a dictionnary linking known tokens (strings) to its type.
    """
    ast = parse_access(c_str)
    access_c = ast_get_c_access_expr(ast, c_context)
    return self.exprc2expr.get_expr(access_c, c_context)

def c_to_type(

self, c_str, c_context)

Get the type of a C string expression @expr: Miasm expression @c_context: a dictionnary linking known tokens (strings) to its type.

def c_to_type(self, c_str, c_context):
    """Get the type of a C string expression
    @expr: Miasm expression
    @c_context: a dictionnary linking known tokens (strings) to its type.
    """
    _, ctype = self.c_to_expr_and_type(c_str, c_context)
    return ctype

def expr_to_c(

self, expr, expr_context=None)

Convert a Miasm @expr into it's C equivalent string @expr_context: a dictionnary linking known expressions to a set of types

def expr_to_c(self, expr, expr_context=None):
    """Convert a Miasm @expr into it's C equivalent string
    @expr_context: a dictionnary linking known expressions to a set of types
    """
    return set(access[0]
               for access in self.expr_to_c_and_types(expr, expr_context))

def expr_to_c_access(

self, expr, expr_context=None)

Generate the C access object(s) for a given native Miasm expression. @expr: Miasm expression @expr_context: a dictionnary linking known expressions to a set of types

def expr_to_c_access(self, expr, expr_context=None):
    """Generate the C access object(s) for a given native Miasm expression.
    @expr: Miasm expression
    @expr_context: a dictionnary linking known expressions to a set of types
    """
    if expr_context is None:
        expr_context = self.expr_types
    return self.access_c_gen.get_accesses(expr, expr_context)

def expr_to_c_and_types(

self, expr, expr_context=None)

Generate the C access string and corresponding type for a given native Miasm expression. @expr_context: a dictionnary linking known expressions to a set of types

def expr_to_c_and_types(self, expr, expr_context=None):
    """Generate the C access string and corresponding type for a given
    native Miasm expression.
    @expr_context: a dictionnary linking known expressions to a set of types
    """
    accesses = set()
    for access in self.expr_to_c_access(expr, expr_context):
        c_str = access_str(access.to_expr().visit(self.simplify_c))
        accesses.add((c_str, access.ctype))
    return accesses

def expr_to_types(

self, expr, expr_context=None)

Get the possible types of the Miasm @expr @expr_context: a dictionnary linking known expressions to a set of types

def expr_to_types(self, expr, expr_context=None):
    """Get the possible types of the Miasm @expr
    @expr_context: a dictionnary linking known expressions to a set of types
    """
    return set(access.ctype
               for access in self.expr_to_c_access(expr, expr_context))

def updt_expr_types(

self, expr_types)

Update expr_types @expr_types: Dictionnary associating name to type

def updt_expr_types(self, expr_types):
    """Update expr_types
    @expr_types: Dictionnary associating name to type
    """
    self.expr_types = expr_types
    self.exprc2expr.updt_expr_types(expr_types)
    self.access_c_gen.updt_expr_types(expr_types)

class CLeafTypes

Define C types sizes/alignement for a given architecture

class CLeafTypes(object):
    """Define C types sizes/alignement for a given architecture"""
    pass

Ancestors (in MRO)

class CTypesManager

Represent a C object, without any layout information

class CTypesManager(object):
    """Represent a C object, without any layout information"""

    def __init__(self, types_ast, leaf_types):
        self.types_ast = types_ast
        self.leaf_types = leaf_types

    @property
    def void_ptr(self):
        """Retrieve a void* objc"""
        return self.leaf_types.types.get(CTypePtr(CTypeId('void')))

    @property
    def padding(self):
        """Retrieve a padding ctype"""
        return CTypeId(PADDING_TYPE_NAME)

    def _get_objc(self, type_id, resolved=None, to_fix=None, lvl=0):
        if resolved is None:
            resolved = {}
        if to_fix is None:
            to_fix = []
        if type_id in resolved:
            return resolved[type_id]
        type_id = self.types_ast.get_type(type_id)
        fixed = True
        if isinstance(type_id, CTypeId):
            out = self.leaf_types.types.get(type_id, None)
            assert out is not None
        elif isinstance(type_id, CTypeUnion):
            args = []
            align_max, size_max = 0, 0
            for name, field in type_id.fields:
                objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                resolved[field] = objc
                align_max = max(align_max, objc.align)
                size_max = max(size_max, objc.size)
                args.append((name, objc, 0, objc.size))

            align, size = self.union_compute_align_size(align_max, size_max)
            out = ObjCUnion(type_id.name, align, size, args)

        elif isinstance(type_id, CTypeStruct):
            align_max, size_max = 0, 0

            args = []
            offset, align_max = 0, 1
            pad_index = 0
            for name, field in type_id.fields:
                objc = self._get_objc(field, resolved, to_fix, lvl + 1)
                resolved[field] = objc
                align_max = max(align_max, objc.align)
                new_offset = self.struct_compute_field_offset(objc, offset)
                if new_offset - offset:
                    pad_name = "__PAD__%d__" % pad_index
                    pad_index += 1
                    size = new_offset - offset
                    pad_objc = self._get_objc(CTypeArray(self.padding, size), resolved, to_fix, lvl + 1)
                    args.append((pad_name, pad_objc, offset, pad_objc.size))
                offset = new_offset
                args.append((name, objc, offset, objc.size))
                offset += objc.size

            align, size = self.struct_compute_align_size(align_max, offset)
            out = ObjCStruct(type_id.name, align, size, args)

        elif isinstance(type_id, CTypePtr):
            target = type_id.target
            out = ObjCPtr(None, self.void_ptr.align, self.void_ptr.size)
            fixed = False

        elif isinstance(type_id, CTypeArray):
            target = type_id.target
            objc = self._get_objc(target, resolved, to_fix, lvl + 1)
            resolved[target] = objc
            if type_id.size is None:
                # case: toto[]
                # return ObjCPtr
                out = ObjCPtr(objc, self.void_ptr.align, self.void_ptr.size)
            else:
                size = self.size_to_int(type_id.size)
                if size is None:
                    raise RuntimeError('Enable to compute objc size')
                else:
                    out = ObjCArray(objc, size)
            assert out.size is not None and out.align is not None
        elif isinstance(type_id, CTypeEnum):
            # Enum are integer
            return self.leaf_types.types.get(CTypeId('int'))
        elif isinstance(type_id, CTypeFunc):
            type_ret = self._get_objc(
                type_id.type_ret, resolved, to_fix, lvl + 1)
            resolved[type_id.type_ret] = type_ret
            args = []
            for name, arg in type_id.args:
                objc = self._get_objc(arg, resolved, to_fix, lvl + 1)
                resolved[arg] = objc
                args.append((name, objc))
            out = ObjCFunc(type_id.name, type_id.abi, type_ret, args,
                           self.void_ptr.align, self.void_ptr.size)
        elif isinstance(type_id, CTypeEllipsis):
            out = ObjCEllipsis()
        else:
            raise TypeError("Unknown type %r" % type_id.__class__)
        if not isinstance(out, ObjCEllipsis):
            assert out.align is not None and out.size is not None

        if fixed:
            resolved[type_id] = out
        else:
            to_fix.append((type_id, out))
        return out

    def get_objc(self, type_id):
        """Get the ObjC corresponding to the CType @type_id
        @type_id: CTypeBase instance"""
        resolved = {}
        to_fix = []
        out = self._get_objc(type_id, resolved, to_fix)
        # Fix sub objects
        while to_fix:
            type_id, objc_to_fix = to_fix.pop()
            objc = self._get_objc(type_id.target, resolved, to_fix)
            objc_to_fix.objtype = objc
        self.check_objc(out)
        return out

    def check_objc(self, objc, done=None):
        """Ensure each sub ObjC is resolved
        @objc: ObjC instance"""
        if done is None:
            done = set()
        if objc in done:
            return True
        done.add(objc)
        if isinstance(objc, (ObjCDecl, ObjCInt, ObjCEllipsis)):
            return True
        elif isinstance(objc, (ObjCPtr, ObjCArray)):
            assert self.check_objc(objc.objtype, done)
            return True
        elif isinstance(objc, (ObjCStruct, ObjCUnion)):
            for _, field, _, _ in objc.fields:
                assert self.check_objc(field, done)
            return True
        elif isinstance(objc, ObjCFunc):
            assert self.check_objc(objc.type_ret, done)
            for name, arg in objc.args:
                assert self.check_objc(arg, done)
            return True
        else:
            assert False

    def size_to_int(self, size):
        """Resolve an array size
        @size: CTypeOp or integer"""
        if isinstance(size, CTypeOp):
            assert len(size.args) == 2
            arg0, arg1 = [self.size_to_int(arg) for arg in size.args]
            if size.operator == "+":
                return arg0 + arg1
            elif size.operator == "-":
                return arg0 - arg1
            elif size.operator == "*":
                return arg0 * arg1
            elif size.operator == "/":
                return arg0 / arg1
            elif size.operator == "<<":
                return arg0 << arg1
            elif size.operator == ">>":
                return arg0 >> arg1
            else:
                raise ValueError("Unknown operator %s" % size.operator)
        elif isinstance(size, (int, long)):
            return size
        elif isinstance(size, CTypeSizeof):
            obj = self._get_objc(size.target)
            return obj.size
        else:
            raise TypeError("Unknown size type")

    def struct_compute_field_offset(self, obj, offset):
        """Compute the offset of the field @obj in the current structure"""
        raise NotImplementedError("Abstract method")

    def struct_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current structure"""
        raise NotImplementedError("Abstract method")

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union"""
        raise NotImplementedError("Abstract method")

Ancestors (in MRO)

Instance variables

var leaf_types

var padding

Retrieve a padding ctype

var types_ast

var void_ptr

Retrieve a void* objc

Methods

def __init__(

self, types_ast, leaf_types)

def __init__(self, types_ast, leaf_types):
    self.types_ast = types_ast
    self.leaf_types = leaf_types

def check_objc(

self, objc, done=None)

Ensure each sub ObjC is resolved @objc: ObjC instance

def check_objc(self, objc, done=None):
    """Ensure each sub ObjC is resolved
    @objc: ObjC instance"""
    if done is None:
        done = set()
    if objc in done:
        return True
    done.add(objc)
    if isinstance(objc, (ObjCDecl, ObjCInt, ObjCEllipsis)):
        return True
    elif isinstance(objc, (ObjCPtr, ObjCArray)):
        assert self.check_objc(objc.objtype, done)
        return True
    elif isinstance(objc, (ObjCStruct, ObjCUnion)):
        for _, field, _, _ in objc.fields:
            assert self.check_objc(field, done)
        return True
    elif isinstance(objc, ObjCFunc):
        assert self.check_objc(objc.type_ret, done)
        for name, arg in objc.args:
            assert self.check_objc(arg, done)
        return True
    else:
        assert False

def get_objc(

self, type_id)

Get the ObjC corresponding to the CType @type_id @type_id: CTypeBase instance

def get_objc(self, type_id):
    """Get the ObjC corresponding to the CType @type_id
    @type_id: CTypeBase instance"""
    resolved = {}
    to_fix = []
    out = self._get_objc(type_id, resolved, to_fix)
    # Fix sub objects
    while to_fix:
        type_id, objc_to_fix = to_fix.pop()
        objc = self._get_objc(type_id.target, resolved, to_fix)
        objc_to_fix.objtype = objc
    self.check_objc(out)
    return out

def size_to_int(

self, size)

Resolve an array size @size: CTypeOp or integer

def size_to_int(self, size):
    """Resolve an array size
    @size: CTypeOp or integer"""
    if isinstance(size, CTypeOp):
        assert len(size.args) == 2
        arg0, arg1 = [self.size_to_int(arg) for arg in size.args]
        if size.operator == "+":
            return arg0 + arg1
        elif size.operator == "-":
            return arg0 - arg1
        elif size.operator == "*":
            return arg0 * arg1
        elif size.operator == "/":
            return arg0 / arg1
        elif size.operator == "<<":
            return arg0 << arg1
        elif size.operator == ">>":
            return arg0 >> arg1
        else:
            raise ValueError("Unknown operator %s" % size.operator)
    elif isinstance(size, (int, long)):
        return size
    elif isinstance(size, CTypeSizeof):
        obj = self._get_objc(size.target)
        return obj.size
    else:
        raise TypeError("Unknown size type")

def struct_compute_align_size(

self, align_max, size)

Compute the alignment and size of the current structure

def struct_compute_align_size(self, align_max, size):
    """Compute the alignment and size of the current structure"""
    raise NotImplementedError("Abstract method")

def struct_compute_field_offset(

self, obj, offset)

Compute the offset of the field @obj in the current structure

def struct_compute_field_offset(self, obj, offset):
    """Compute the offset of the field @obj in the current structure"""
    raise NotImplementedError("Abstract method")

def union_compute_align_size(

self, align_max, size)

Compute the alignment and size of the current union

def union_compute_align_size(self, align_max, size):
    """Compute the alignment and size of the current union"""
    raise NotImplementedError("Abstract method")

class CTypesManagerNotPacked

Store defined C types (not packed)

class CTypesManagerNotPacked(CTypesManager):
    """Store defined C types (not packed)"""

    def struct_compute_field_offset(self, obj, offset):
        """Compute the offset of the field @obj in the current structure
        (not packed)"""

        if obj.align > 1:
            offset = (offset + obj.align - 1) & ~(obj.align - 1)
        return offset

    def struct_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current structure
        (not packed)"""
        if align_max > 1:
            size = (size + align_max - 1) & ~(align_max - 1)
        return align_max, size

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union
        (not packed)"""
        return align_max, size

Ancestors (in MRO)

Instance variables

var leaf_types

Inheritance: CTypesManager.leaf_types

var padding

Inheritance: CTypesManager.padding

Retrieve a padding ctype

var types_ast

Inheritance: CTypesManager.types_ast

var void_ptr

Inheritance: CTypesManager.void_ptr

Retrieve a void* objc

Methods

def __init__(

self, types_ast, leaf_types)

Inheritance: CTypesManager.__init__

def __init__(self, types_ast, leaf_types):
    self.types_ast = types_ast
    self.leaf_types = leaf_types

def check_objc(

self, objc, done=None)

Inheritance: CTypesManager.check_objc

Ensure each sub ObjC is resolved @objc: ObjC instance

def check_objc(self, objc, done=None):
    """Ensure each sub ObjC is resolved
    @objc: ObjC instance"""
    if done is None:
        done = set()
    if objc in done:
        return True
    done.add(objc)
    if isinstance(objc, (ObjCDecl, ObjCInt, ObjCEllipsis)):
        return True
    elif isinstance(objc, (ObjCPtr, ObjCArray)):
        assert self.check_objc(objc.objtype, done)
        return True
    elif isinstance(objc, (ObjCStruct, ObjCUnion)):
        for _, field, _, _ in objc.fields:
            assert self.check_objc(field, done)
        return True
    elif isinstance(objc, ObjCFunc):
        assert self.check_objc(objc.type_ret, done)
        for name, arg in objc.args:
            assert self.check_objc(arg, done)
        return True
    else:
        assert False

def get_objc(

self, type_id)

Inheritance: CTypesManager.get_objc

Get the ObjC corresponding to the CType @type_id @type_id: CTypeBase instance

def get_objc(self, type_id):
    """Get the ObjC corresponding to the CType @type_id
    @type_id: CTypeBase instance"""
    resolved = {}
    to_fix = []
    out = self._get_objc(type_id, resolved, to_fix)
    # Fix sub objects
    while to_fix:
        type_id, objc_to_fix = to_fix.pop()
        objc = self._get_objc(type_id.target, resolved, to_fix)
        objc_to_fix.objtype = objc
    self.check_objc(out)
    return out

def size_to_int(

self, size)

Inheritance: CTypesManager.size_to_int

Resolve an array size @size: CTypeOp or integer

def size_to_int(self, size):
    """Resolve an array size
    @size: CTypeOp or integer"""
    if isinstance(size, CTypeOp):
        assert len(size.args) == 2
        arg0, arg1 = [self.size_to_int(arg) for arg in size.args]
        if size.operator == "+":
            return arg0 + arg1
        elif size.operator == "-":
            return arg0 - arg1
        elif size.operator == "*":
            return arg0 * arg1
        elif size.operator == "/":
            return arg0 / arg1
        elif size.operator == "<<":
            return arg0 << arg1
        elif size.operator == ">>":
            return arg0 >> arg1
        else:
            raise ValueError("Unknown operator %s" % size.operator)
    elif isinstance(size, (int, long)):
        return size
    elif isinstance(size, CTypeSizeof):
        obj = self._get_objc(size.target)
        return obj.size
    else:
        raise TypeError("Unknown size type")

def struct_compute_align_size(

self, align_max, size)

Inheritance: CTypesManager.struct_compute_align_size

Compute the alignment and size of the current structure (not packed)

def struct_compute_align_size(self, align_max, size):
    """Compute the alignment and size of the current structure
    (not packed)"""
    if align_max > 1:
        size = (size + align_max - 1) & ~(align_max - 1)
    return align_max, size

def struct_compute_field_offset(

self, obj, offset)

Inheritance: CTypesManager.struct_compute_field_offset

Compute the offset of the field @obj in the current structure (not packed)

def struct_compute_field_offset(self, obj, offset):
    """Compute the offset of the field @obj in the current structure
    (not packed)"""
    if obj.align > 1:
        offset = (offset + obj.align - 1) & ~(obj.align - 1)
    return offset

def union_compute_align_size(

self, align_max, size)

Inheritance: CTypesManager.union_compute_align_size

Compute the alignment and size of the current union (not packed)

def union_compute_align_size(self, align_max, size):
    """Compute the alignment and size of the current union
    (not packed)"""
    return align_max, size

class CTypesManagerPacked

Store defined C types (packed form)

class CTypesManagerPacked(CTypesManager):
    """Store defined C types (packed form)"""

    def struct_compute_field_offset(self, _, offset):
        """Compute the offset of the field @obj in the current structure
        (packed form)"""
        return offset

    def struct_compute_align_size(self, _, size):
        """Compute the alignment and size of the current structure
        (packed form)"""
        return 1, size

    def union_compute_align_size(self, align_max, size):
        """Compute the alignment and size of the current union
        (packed form)"""
        return 1, size

Ancestors (in MRO)

Instance variables

var leaf_types

Inheritance: CTypesManager.leaf_types

var padding

Inheritance: CTypesManager.padding

Retrieve a padding ctype

var types_ast

Inheritance: CTypesManager.types_ast

var void_ptr

Inheritance: CTypesManager.void_ptr

Retrieve a void* objc

Methods

def __init__(

self, types_ast, leaf_types)

Inheritance: CTypesManager.__init__

def __init__(self, types_ast, leaf_types):
    self.types_ast = types_ast
    self.leaf_types = leaf_types

def check_objc(

self, objc, done=None)

Inheritance: CTypesManager.check_objc

Ensure each sub ObjC is resolved @objc: ObjC instance

def check_objc(self, objc, done=None):
    """Ensure each sub ObjC is resolved
    @objc: ObjC instance"""
    if done is None:
        done = set()
    if objc in done:
        return True
    done.add(objc)
    if isinstance(objc, (ObjCDecl, ObjCInt, ObjCEllipsis)):
        return True
    elif isinstance(objc, (ObjCPtr, ObjCArray)):
        assert self.check_objc(objc.objtype, done)
        return True
    elif isinstance(objc, (ObjCStruct, ObjCUnion)):
        for _, field, _, _ in objc.fields:
            assert self.check_objc(field, done)
        return True
    elif isinstance(objc, ObjCFunc):
        assert self.check_objc(objc.type_ret, done)
        for name, arg in objc.args:
            assert self.check_objc(arg, done)
        return True
    else:
        assert False

def get_objc(

self, type_id)

Inheritance: CTypesManager.get_objc

Get the ObjC corresponding to the CType @type_id @type_id: CTypeBase instance

def get_objc(self, type_id):
    """Get the ObjC corresponding to the CType @type_id
    @type_id: CTypeBase instance"""
    resolved = {}
    to_fix = []
    out = self._get_objc(type_id, resolved, to_fix)
    # Fix sub objects
    while to_fix:
        type_id, objc_to_fix = to_fix.pop()
        objc = self._get_objc(type_id.target, resolved, to_fix)
        objc_to_fix.objtype = objc
    self.check_objc(out)
    return out

def size_to_int(

self, size)

Inheritance: CTypesManager.size_to_int

Resolve an array size @size: CTypeOp or integer

def size_to_int(self, size):
    """Resolve an array size
    @size: CTypeOp or integer"""
    if isinstance(size, CTypeOp):
        assert len(size.args) == 2
        arg0, arg1 = [self.size_to_int(arg) for arg in size.args]
        if size.operator == "+":
            return arg0 + arg1
        elif size.operator == "-":
            return arg0 - arg1
        elif size.operator == "*":
            return arg0 * arg1
        elif size.operator == "/":
            return arg0 / arg1
        elif size.operator == "<<":
            return arg0 << arg1
        elif size.operator == ">>":
            return arg0 >> arg1
        else:
            raise ValueError("Unknown operator %s" % size.operator)
    elif isinstance(size, (int, long)):
        return size
    elif isinstance(size, CTypeSizeof):
        obj = self._get_objc(size.target)
        return obj.size
    else:
        raise TypeError("Unknown size type")

def struct_compute_align_size(

self, _, size)

Inheritance: CTypesManager.struct_compute_align_size

Compute the alignment and size of the current structure (packed form)

def struct_compute_align_size(self, _, size):
    """Compute the alignment and size of the current structure
    (packed form)"""
    return 1, size

def struct_compute_field_offset(

self, _, offset)

Inheritance: CTypesManager.struct_compute_field_offset

Compute the offset of the field @obj in the current structure (packed form)

def struct_compute_field_offset(self, _, offset):
    """Compute the offset of the field @obj in the current structure
    (packed form)"""
    return offset

def union_compute_align_size(

self, align_max, size)

Inheritance: CTypesManager.union_compute_align_size

Compute the alignment and size of the current union (packed form)

def union_compute_align_size(self, align_max, size):
    """Compute the alignment and size of the current union
    (packed form)"""
    return 1, size

class ExprCToExpr

Translate a Miasm expression (representing a C access) into a native Miasm expression and its C type:

Example:

IN: ((ptr_struct -> f_mini) field x) OUT: @32[ptr_struct + 0x80], int

Tricky cases: Struct S0 { int x; int y[0x10]; }

Struct S1 { int a; S0 toto; }

S1* ptr;

Case 1: ptr->toto => ptr + 0x4 &(ptr->toto) => ptr + 0x4

Case 2: (ptr->toto).x => @32[ptr + 0x4] &((ptr->toto).x) => ptr + 0x4

Case 3: (ptr->toto).y => ptr + 0x8 &((ptr->toto).y) => ptr + 0x8

Case 4: (ptr->toto).y[1] => @32[ptr + 0x8 + 0x4] &((ptr->toto).y[1]) => ptr + 0x8 + 0x4

class ExprCToExpr(ExprReducer):
    """Translate a Miasm expression (representing a C access) into a native
    Miasm expression and its C type:

    Example:

    IN: ((ptr_struct -> f_mini) field x)
    OUT: @32[ptr_struct + 0x80], int


    Tricky cases:
    Struct S0 {
        int x;
        int y[0x10];
    }

    Struct S1 {
        int a;
        S0 toto;
    }

    S1* ptr;

    Case 1:
    ptr->toto => ptr + 0x4
    &(ptr->toto) => ptr + 0x4

    Case 2:
    (ptr->toto).x => @32[ptr + 0x4]
    &((ptr->toto).x) => ptr + 0x4

    Case 3:
    (ptr->toto).y => ptr + 0x8
    &((ptr->toto).y) => ptr + 0x8

    Case 4:
    (ptr->toto).y[1] => @32[ptr + 0x8 + 0x4]
    &((ptr->toto).y[1]) => ptr + 0x8 + 0x4

    """

    def __init__(self, expr_types, types_mngr):
        """Init ExprCAccess

        @expr_types: a dictionnary linking ID names to their types
        @types_mngr: types manager
        """

        self.expr_types = expr_types
        self.types_mngr = types_mngr

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types

    CST = "CST"

    def reduce_known_expr(self, node, ctxt, **kwargs):
        """Reduce known expressions"""
        if str(node.expr) in ctxt:
            objc = ctxt[str(node.expr)]
            out = (node.expr, objc)
        elif node.expr.is_id():
            out = (node.expr, None)
        else:
            out = None
        return out

    def reduce_int(self, node, **kwargs):
        """Reduce ExprInt"""

        if not isinstance(node.expr, ExprInt):
            return None
        return self.CST

    def reduce_op_memberof(self, node, **kwargs):
        """Reduce -> operator"""

        if not node.expr.is_op('->'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprId)
        field = node.args[1].expr.name
        src, src_type = node.args[0].info
        if src_type is None:
            return None
        assert isinstance(src_type, (ObjCPtr, ObjCArray))
        struct_dst = src_type.objtype
        assert isinstance(struct_dst, ObjCStruct)

        found = False
        for name, objtype, offset, _ in struct_dst.fields:
            if name != field:
                continue
            expr = src + ExprInt(offset, src.size)
            if isinstance(objtype, (ObjCArray, ObjCStruct, ObjCUnion)):
                pass
            else:
                expr = ExprMem(expr, objtype.size * 8)
            assert not found
            found = True
            out = (expr, objtype)
        assert found
        return out

    def reduce_op_field(self, node, **kwargs):
        """Reduce field operator (Struct or Union)"""

        if not node.expr.is_op('field'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprId)
        field = node.args[1].expr.name
        src, src_type = node.args[0].info
        struct_dst = src_type

        if isinstance(struct_dst, ObjCStruct):
            found = False
            for name, objtype, offset, _ in struct_dst.fields:
                if name != field:
                    continue
                expr = src + ExprInt(offset, src.size)
                if isinstance(objtype, ObjCArray):
                    # Case 4
                    pass
                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                    # Case 1
                    pass
                else:
                    # Case 2
                    expr = ExprMem(expr, objtype.size * 8)
                assert not found
                found = True
                out = (expr, objtype)
        elif isinstance(struct_dst, ObjCUnion):
            found = False
            for name, objtype, offset, _ in struct_dst.fields:
                if name != field:
                    continue
                expr = src + ExprInt(offset, src.size)
                if isinstance(objtype, ObjCArray):
                    # Case 4
                    pass
                elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                    # Case 1
                    pass
                else:
                    # Case 2
                    expr = ExprMem(expr, objtype.size * 8)
                assert not found
                found = True
                out = (expr, objtype)
        else:
            raise NotImplementedError("unknown ObjC")
        assert found
        return out

    def reduce_op_array(self, node, **kwargs):
        """Reduce array operator"""

        if not node.expr.is_op('[]'):
            return None
        assert len(node.args) == 2
        out = []
        assert isinstance(node.args[1].expr, ExprInt)
        cst = node.args[1].expr
        src, src_type = node.args[0].info
        objtype = src_type.objtype
        expr = src + cst * ExprInt(objtype.size, cst.size)
        if isinstance(src_type, ObjCPtr):
            if isinstance(objtype, ObjCArray):
                final = objtype.objtype
                expr = src + cst * ExprInt(final.size, cst.size)
                objtype = final
                expr = ExprMem(expr, final.size * 8)
                found = True
            else:
                expr = ExprMem(expr, objtype.size * 8)
                found = True
        elif isinstance(src_type, ObjCArray):
            if isinstance(objtype, ObjCArray):
                final = objtype
                found = True
            elif isinstance(objtype, ObjCStruct):
                found = True
            else:
                expr = ExprMem(expr, objtype.size * 8)
                found = True
        else:
            raise NotImplementedError("Unknown access" % node.expr)
        assert found
        out = (expr, objtype)
        return out

    def reduce_op_addr(self, node, **kwargs):
        """Reduce addr operator"""

        if not node.expr.is_op('addr'):
            return None
        assert len(node.args) == 1
        out = []
        src, src_type = node.args[0].info

        void_type = self.types_mngr.void_ptr

        if isinstance(src_type, ObjCArray):
            out = (src.arg, ObjCPtr(src_type.objtype,
                                    void_type.align, void_type.size))
        elif isinstance(src, ExprMem):
            out = (src.arg, ObjCPtr(src_type,
                                    void_type.align, void_type.size))
        elif isinstance(src_type, ObjCStruct):
            out = (src, ObjCPtr(src_type,
                                void_type.align, void_type.size))
        elif isinstance(src_type, ObjCUnion):
            out = (src, ObjCPtr(src_type,
                                void_type.align, void_type.size))
        else:
            raise NotImplementedError("unk type")
        return out

    def reduce_op_deref(self, node, **kwargs):
        """Reduce deref operator"""

        if not node.expr.is_op('deref'):
            return None
        out = []
        src, src_type = node.args[0].info
        assert isinstance(src_type, (ObjCPtr, ObjCArray))
        void_type = self.types_mngr.void_ptr
        if isinstance(src_type, ObjCPtr):
            if isinstance(src_type.objtype, ObjCArray):
                size = void_type.size*8
            else:
                size = src_type.objtype.size * 8
            out = (ExprMem(src, size), (src_type.objtype))
        else:
            size = src_type.objtype.size * 8
            out = (ExprMem(src, size), (src_type.objtype))
        return out

    reduction_rules = [reduce_known_expr,
                       reduce_int,
                       reduce_op_memberof,
                       reduce_op_field,
                       reduce_op_array,
                       reduce_op_addr,
                       reduce_op_deref,
                      ]

    def get_expr(self, expr, c_context):
        """Translate a Miasm expression @expr (representing a C access) into a
        tuple composed of a native Miasm expression and its C type.
        @expr: Miasm expression (representing a C access)
        @c_context: a dictionnary linking known tokens (strings) to their
        types. A token is linked to only one type.
        """
        ret = self.reduce(expr, ctxt=c_context)
        if ret.info is None:
            return (None, None)
        return ret.info

Ancestors (in MRO)

  • ExprCToExpr
  • miasm2.expression.expression_reduce.ExprReducer
  • __builtin__.object

Class variables

var CST

var allow_none_result

var reduction_rules

Instance variables

var expr_types

var types_mngr

Methods

def __init__(

self, expr_types, types_mngr)

Init ExprCAccess

@expr_types: a dictionnary linking ID names to their types @types_mngr: types manager

def __init__(self, expr_types, types_mngr):
    """Init ExprCAccess
    @expr_types: a dictionnary linking ID names to their types
    @types_mngr: types manager
    """
    self.expr_types = expr_types
    self.types_mngr = types_mngr

def apply_rules(

self, node, lvl=0, **kwargs)

Find and apply reduction rules to @node

@node: ExprNode to analyse @lvl: actuel recusion level

def apply_rules(self, node, lvl=0, **kwargs):
    """Find and apply reduction rules to @node
    @node: ExprNode to analyse
    @lvl: actuel recusion level
    """
    for rule in self.reduction_rules:
        ret = rule(self, node, lvl=lvl, **kwargs)
        if ret is not None:
            log_reduce.debug("\t" * lvl + "Rule found: %r", rule)
            return ret
    if not self.allow_none_result:
        raise RuntimeError('Missing reduction rule for %r' % node.expr)

def categorize(

self, node, lvl=0, **kwargs)

Recursively apply rules to @node

@node: ExprNode to analyze @lvl: actual recusion level

def categorize(self, node, lvl=0, **kwargs):
    """Recursively apply rules to @node
    @node: ExprNode to analyze
    @lvl: actual recusion level
    """
    expr = node.expr
    log_reduce.debug("\t" * lvl + "Reduce...: %s", node.expr)
    if isinstance(expr, (ExprId, ExprInt, ExprLoc)):
        pass
    elif isinstance(expr, ExprMem):
        arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprMem(arg.expr, expr.size))
        node.arg = arg
    elif isinstance(expr, ExprSlice):
        arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprSlice(arg.expr, expr.start, expr.stop))
        node.arg = arg
    elif isinstance(expr, ExprOp):
        new_args = []
        for arg in node.args:
            new_a = self.categorize(arg, lvl=lvl + 1, **kwargs)
            assert new_a.expr.size == arg.expr.size
            new_args.append(new_a)
        node = ExprNode(ExprOp(expr.op, *[x.expr for x in new_args]))
        node.args = new_args
        expr = node.expr
    elif isinstance(expr, ExprCompose):
        new_args = []
        new_expr_args = []
        for arg in node.args:
            arg = self.categorize(arg, lvl=lvl + 1, **kwargs)
            new_args.append(arg)
            new_expr_args.append(arg.expr)
        new_expr = ExprCompose(*new_expr_args)
        node = ExprNode(new_expr)
        node.args = new_args
    elif isinstance(expr, ExprCond):
        cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs)
        src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs)
        src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprCond(cond.expr, src1.expr, src2.expr))
        node.cond, node.src1, node.src2 = cond, src1, src2
    else:
        raise TypeError("Unknown Expr Type %r", type(expr))
    node.info = self.apply_rules(node, lvl=lvl, **kwargs)
    log_reduce.debug("\t" * lvl + "Reduce result: %s %r",
                     node.expr, node.info)
    return node

def expr2node(

self, expr)

Build ExprNode mirror of @expr

@expr: Expression to analyze

def expr2node(self, expr):
    """Build ExprNode mirror of @expr
    @expr: Expression to analyze
    """
    if isinstance(expr, (ExprId, ExprLoc, ExprInt)):
        node = ExprNode(expr)
    elif isinstance(expr, (ExprMem, ExprSlice)):
        son = self.expr2node(expr.arg)
        node = ExprNode(expr)
        node.arg = son
    elif isinstance(expr, ExprOp):
        sons = [self.expr2node(arg) for arg in expr.args]
        node = ExprNode(expr)
        node.args = sons
    elif isinstance(expr, ExprCompose):
        sons = [self.expr2node(arg) for arg in expr.args]
        node = ExprNode(expr)
        node.args = sons
    elif isinstance(expr, ExprCond):
        node = ExprNode(expr)
        node.cond = self.expr2node(expr.cond)
        node.src1 = self.expr2node(expr.src1)
        node.src2 = self.expr2node(expr.src2)
    else:
        raise TypeError("Unknown Expr Type %r", type(expr))
    return node

def get_expr(

self, expr, c_context)

Translate a Miasm expression @expr (representing a C access) into a tuple composed of a native Miasm expression and its C type. @expr: Miasm expression (representing a C access) @c_context: a dictionnary linking known tokens (strings) to their types. A token is linked to only one type.

def get_expr(self, expr, c_context):
    """Translate a Miasm expression @expr (representing a C access) into a
    tuple composed of a native Miasm expression and its C type.
    @expr: Miasm expression (representing a C access)
    @c_context: a dictionnary linking known tokens (strings) to their
    types. A token is linked to only one type.
    """
    ret = self.reduce(expr, ctxt=c_context)
    if ret.info is None:
        return (None, None)
    return ret.info

def reduce(

self, expr, **kwargs)

Returns an ExprNode tree mirroring @expr tree. The ExprNode is computed by applying reduction rules to the expression @expr

@expr: an Expression

def reduce(self, expr, **kwargs):
    """Returns an ExprNode tree mirroring @expr tree. The ExprNode is
    computed by applying reduction rules to the expression @expr
    @expr: an Expression
    """
    node = self.expr2node(expr)
    return self.categorize(node, lvl=0, **kwargs)

def reduce_int(

self, node, **kwargs)

Reduce ExprInt

def reduce_int(self, node, **kwargs):
    """Reduce ExprInt"""
    if not isinstance(node.expr, ExprInt):
        return None
    return self.CST

def reduce_known_expr(

self, node, ctxt, **kwargs)

Reduce known expressions

def reduce_known_expr(self, node, ctxt, **kwargs):
    """Reduce known expressions"""
    if str(node.expr) in ctxt:
        objc = ctxt[str(node.expr)]
        out = (node.expr, objc)
    elif node.expr.is_id():
        out = (node.expr, None)
    else:
        out = None
    return out

def reduce_op_addr(

self, node, **kwargs)

Reduce addr operator

def reduce_op_addr(self, node, **kwargs):
    """Reduce addr operator"""
    if not node.expr.is_op('addr'):
        return None
    assert len(node.args) == 1
    out = []
    src, src_type = node.args[0].info
    void_type = self.types_mngr.void_ptr
    if isinstance(src_type, ObjCArray):
        out = (src.arg, ObjCPtr(src_type.objtype,
                                void_type.align, void_type.size))
    elif isinstance(src, ExprMem):
        out = (src.arg, ObjCPtr(src_type,
                                void_type.align, void_type.size))
    elif isinstance(src_type, ObjCStruct):
        out = (src, ObjCPtr(src_type,
                            void_type.align, void_type.size))
    elif isinstance(src_type, ObjCUnion):
        out = (src, ObjCPtr(src_type,
                            void_type.align, void_type.size))
    else:
        raise NotImplementedError("unk type")
    return out

def reduce_op_array(

self, node, **kwargs)

Reduce array operator

def reduce_op_array(self, node, **kwargs):
    """Reduce array operator"""
    if not node.expr.is_op('[]'):
        return None
    assert len(node.args) == 2
    out = []
    assert isinstance(node.args[1].expr, ExprInt)
    cst = node.args[1].expr
    src, src_type = node.args[0].info
    objtype = src_type.objtype
    expr = src + cst * ExprInt(objtype.size, cst.size)
    if isinstance(src_type, ObjCPtr):
        if isinstance(objtype, ObjCArray):
            final = objtype.objtype
            expr = src + cst * ExprInt(final.size, cst.size)
            objtype = final
            expr = ExprMem(expr, final.size * 8)
            found = True
        else:
            expr = ExprMem(expr, objtype.size * 8)
            found = True
    elif isinstance(src_type, ObjCArray):
        if isinstance(objtype, ObjCArray):
            final = objtype
            found = True
        elif isinstance(objtype, ObjCStruct):
            found = True
        else:
            expr = ExprMem(expr, objtype.size * 8)
            found = True
    else:
        raise NotImplementedError("Unknown access" % node.expr)
    assert found
    out = (expr, objtype)
    return out

def reduce_op_deref(

self, node, **kwargs)

Reduce deref operator

def reduce_op_deref(self, node, **kwargs):
    """Reduce deref operator"""
    if not node.expr.is_op('deref'):
        return None
    out = []
    src, src_type = node.args[0].info
    assert isinstance(src_type, (ObjCPtr, ObjCArray))
    void_type = self.types_mngr.void_ptr
    if isinstance(src_type, ObjCPtr):
        if isinstance(src_type.objtype, ObjCArray):
            size = void_type.size*8
        else:
            size = src_type.objtype.size * 8
        out = (ExprMem(src, size), (src_type.objtype))
    else:
        size = src_type.objtype.size * 8
        out = (ExprMem(src, size), (src_type.objtype))
    return out

def reduce_op_field(

self, node, **kwargs)

Reduce field operator (Struct or Union)

def reduce_op_field(self, node, **kwargs):
    """Reduce field operator (Struct or Union)"""
    if not node.expr.is_op('field'):
        return None
    assert len(node.args) == 2
    out = []
    assert isinstance(node.args[1].expr, ExprId)
    field = node.args[1].expr.name
    src, src_type = node.args[0].info
    struct_dst = src_type
    if isinstance(struct_dst, ObjCStruct):
        found = False
        for name, objtype, offset, _ in struct_dst.fields:
            if name != field:
                continue
            expr = src + ExprInt(offset, src.size)
            if isinstance(objtype, ObjCArray):
                # Case 4
                pass
            elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                # Case 1
                pass
            else:
                # Case 2
                expr = ExprMem(expr, objtype.size * 8)
            assert not found
            found = True
            out = (expr, objtype)
    elif isinstance(struct_dst, ObjCUnion):
        found = False
        for name, objtype, offset, _ in struct_dst.fields:
            if name != field:
                continue
            expr = src + ExprInt(offset, src.size)
            if isinstance(objtype, ObjCArray):
                # Case 4
                pass
            elif isinstance(objtype, (ObjCStruct, ObjCUnion)):
                # Case 1
                pass
            else:
                # Case 2
                expr = ExprMem(expr, objtype.size * 8)
            assert not found
            found = True
            out = (expr, objtype)
    else:
        raise NotImplementedError("unknown ObjC")
    assert found
    return out

def reduce_op_memberof(

self, node, **kwargs)

Reduce -> operator

def reduce_op_memberof(self, node, **kwargs):
    """Reduce -> operator"""
    if not node.expr.is_op('->'):
        return None
    assert len(node.args) == 2
    out = []
    assert isinstance(node.args[1].expr, ExprId)
    field = node.args[1].expr.name
    src, src_type = node.args[0].info
    if src_type is None:
        return None
    assert isinstance(src_type, (ObjCPtr, ObjCArray))
    struct_dst = src_type.objtype
    assert isinstance(struct_dst, ObjCStruct)
    found = False
    for name, objtype, offset, _ in struct_dst.fields:
        if name != field:
            continue
        expr = src + ExprInt(offset, src.size)
        if isinstance(objtype, (ObjCArray, ObjCStruct, ObjCUnion)):
            pass
        else:
            expr = ExprMem(expr, objtype.size * 8)
        assert not found
        found = True
        out = (expr, objtype)
    assert found
    return out

def updt_expr_types(

self, expr_types)

Update expr_types @expr_types: Dictionnary associating name to type

def updt_expr_types(self, expr_types):
    """Update expr_types
    @expr_types: Dictionnary associating name to type
    """
    self.expr_types = expr_types

class ExprToAccessC

Generate the C access object(s) for a given native Miasm expression Example: IN: @32[ptr_Test] OUT: [> a>>>]

An expression may be represented by multiple accessor (due to unions).

class ExprToAccessC(ExprReducer):
    """
    Generate the C access object(s) for a given native Miasm expression
    Example:
    IN:
    @32[ptr_Test]
    OUT:
    [<CGenDeref <CGenArray <CGenField <CGenDeref <CGenId ptr_Test>> a>>>]

    An expression may be represented by multiple accessor (due to unions).
    """

    def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
        """Init GenCAccess

        @expr_types: a dictionnary linking ID names to their types
        @types_mngr: types manager
        @enforce_strict_access: If false, generate access even on expression
        pointing to a middle of an object. If true, raise exception if such a
        pointer is encountered
        """

        self.expr_types = expr_types
        self.types_mngr = types_mngr
        self.enforce_strict_access = enforce_strict_access

    def updt_expr_types(self, expr_types):
        """Update expr_types
        @expr_types: Dictionnary associating name to type
        """

        self.expr_types = expr_types

    def cgen_access(self, cgenobj, base_type, offset, deref, lvl=0):
        """Return the access(es) which lead to the element at @offset of an
        object of type @base_type

        In case of no @deref, stops recursion as soon as we reached the base of
        an object.
        In other cases, we need to go down to the final dereferenced object

        @cgenobj: current object access
        @base_type: type of main object
        @offset: offset (in bytes) of the target sub object
        @deref: get type for a pointer or a deref
        @lvl: actual recursion level


        IN:
        - base_type: struct Toto{
            int a
            int b
          }
        - base_name: var
        - 4
        OUT:
        - CGenField(var, b)



        IN:
        - base_type: int a
        - 0
        OUT:
        - CGenAddr(a)

        IN:
        - base_type: X = int* a
        - 0
        OUT:
        - CGenAddr(X)

        IN:
        - X = int* a
        - 8
        OUT:
        - ASSERT


        IN:
        - struct toto{
            int a
            int b[10]
          }
        - 8
        OUT:
        - CGenArray(CGenField(toto, b), 1)
        """
        if base_type.size == 0:
            missing_definition(base_type)
            return set()


        void_type = self.types_mngr.void_ptr
        if isinstance(base_type, ObjCStruct):
            if not 0 <= offset < base_type.size:
                return set()

            if offset == 0 and not deref:
                # In this case, return the struct*
                return set([cgenobj])

            for fieldname, subtype, field_offset, size in base_type.fields:
                if not field_offset <= offset < field_offset + size:
                    continue
                fieldptr = CGenField(CGenDeref(cgenobj), fieldname, subtype,
                                     void_type.align, void_type.size)
                new_type = self.cgen_access(fieldptr, subtype,
                                            offset - field_offset,
                                            deref, lvl + 1)
                break
            else:
                return set()
        elif isinstance(base_type, ObjCArray):
            if base_type.objtype.size == 0:
                missing_definition(base_type.objtype)
                return set()
            element_num = offset / (base_type.objtype.size)
            field_offset = offset % base_type.objtype.size
            if element_num >= base_type.elems:
                return set()
            if offset == 0 and not deref:
                # In this case, return the array
                return set([cgenobj])

            curobj = CGenArray(cgenobj, element_num,
                               void_type.align,
                               void_type.size)
            if field_offset == 0:
                # We point to the start of the sub object,
                # return it directly
                return set([curobj])
            new_type = self.cgen_access(curobj, base_type.objtype,
                                        field_offset, deref, lvl + 1)

        elif isinstance(base_type, ObjCDecl):
            if self.enforce_strict_access and offset % base_type.size != 0:
                return set()
            elem_num = offset / base_type.size

            nobj = CGenArray(cgenobj, elem_num,
                             void_type.align, void_type.size)
            new_type = set([nobj])

        elif isinstance(base_type, ObjCUnion):
            if offset == 0 and not deref:
                # In this case, return the struct*
                return set([cgenobj])

            out = set()
            for fieldname, objtype, field_offset, size in base_type.fields:
                if not field_offset <= offset < field_offset + size:
                    continue
                field = CGenField(CGenDeref(cgenobj), fieldname, objtype,
                                  void_type.align, void_type.size)
                out.update(self.cgen_access(field, objtype,
                                            offset - field_offset,
                                            deref, lvl + 1))
            new_type = out

        elif isinstance(base_type, ObjCPtr):
            elem_num = offset / base_type.size
            if self.enforce_strict_access and offset % base_type.size != 0:
                return set()
            nobj = CGenArray(cgenobj, elem_num,
                             void_type.align, void_type.size)
            new_type = set([nobj])

        else:
            raise NotImplementedError("deref type %r" % base_type)
        return new_type

    def reduce_known_expr(self, node, ctxt, **kwargs):
        """Generate access for known expr"""
        if node.expr in ctxt:
            objcs = ctxt[node.expr]
            return set(CGenId(objc, str(node.expr)) for objc in objcs)
        return None

    def reduce_int(self, node, **kwargs):
        """Generate access for ExprInt"""

        if not isinstance(node.expr, ExprInt):
            return None
        return set([CGenInt(int(node.expr))])

    def get_solo_type(self, node):
        """Return the type of the @node if it has only one possible type,
        different from not None. In othe cases, return None.
        """
        if node.info is None or len(node.info) != 1:
            return None
        return type(list(node.info)[0].ctype)

    def reduce_op(self, node, lvl=0, **kwargs):
        """Generate access for ExprOp"""
        if not node.expr.is_op("+") or len(node.args) != 2:
            return None
        type_arg1 = self.get_solo_type(node.args[1])
        if type_arg1 != ObjCInt:
            return None
        arg0, arg1 = node.args
        if arg0.info is None:
            return None
        void_type = self.types_mngr.void_ptr
        out = set()
        if not arg1.expr.is_int():
            return None
        ptr_offset = int(arg1.expr)
        for info in arg0.info:
            if isinstance(info.ctype, ObjCArray):
                field_type = info.ctype
            elif isinstance(info.ctype, ObjCPtr):
                field_type = info.ctype.objtype
            else:
                continue
            target_type = info.ctype.objtype

            # Array-like: int* ptr; ptr[1] = X
            out.update(self.cgen_access(info, field_type, ptr_offset, False, lvl))
        return out

    def reduce_mem(self, node, lvl=0, **kwargs):
        """Generate access for ExprMem:
        * @NN[ptr<elem>] -> elem  (type)
        * @64[ptr<ptr<elem>>] -> ptr<elem>
        * @32[ptr<struct>] -> struct.00
        """

        if not isinstance(node.expr, ExprMem):
            return None
        if node.arg.info is None:
            return None
        assert isinstance(node.arg.info, set)
        void_type = self.types_mngr.void_ptr
        found = set()
        for subcgenobj in node.arg.info:
            if isinstance(subcgenobj.ctype, ObjCArray):
                nobj = CGenArray(subcgenobj, 0,
                                 void_type.align,
                                 void_type.size)
                target = nobj.ctype.objtype
                for finalcgenobj in self.cgen_access(nobj, target, 0, True, lvl):
                    assert isinstance(finalcgenobj.ctype, ObjCPtr)
                    if self.enforce_strict_access and finalcgenobj.ctype.objtype.size != node.expr.size / 8:
                        continue
                    found.add(CGenDeref(finalcgenobj))

            elif isinstance(subcgenobj.ctype, ObjCPtr):
                target = subcgenobj.ctype.objtype
                # target : type(elem)
                if isinstance(target, (ObjCStruct, ObjCUnion)):
                    for finalcgenobj in self.cgen_access(subcgenobj, target, 0, True, lvl):
                        target = finalcgenobj.ctype.objtype
                        if self.enforce_strict_access and target.size != node.expr.size / 8:
                            continue
                        found.add(CGenDeref(finalcgenobj))
                elif isinstance(target, ObjCArray):
                    if self.enforce_strict_access and subcgenobj.ctype.size != node.expr.size / 8:
                        continue
                    found.update(self.cgen_access(CGenDeref(subcgenobj), target,
                                                  0, False, lvl))
                else:
                    if self.enforce_strict_access and target.size != node.expr.size / 8:
                        continue
                    found.add(CGenDeref(subcgenobj))
        if not found:
            return None
        return found

    reduction_rules = [reduce_known_expr,
                       reduce_int,
                       reduce_op,
                       reduce_mem,
                      ]

    def get_accesses(self, expr, expr_context=None):
        """Generate C access(es) for the native Miasm expression @expr
        @expr: native Miasm expression
        @expr_context: a dictionnary linking known expressions to their
        types. An expression is linked to a tuple of types.
        """
        if expr_context is None:
            expr_context = self.expr_types
        ret = self.reduce(expr, ctxt=expr_context)
        if ret.info is None:
            return set()
        return ret.info

Ancestors (in MRO)

  • ExprToAccessC
  • miasm2.expression.expression_reduce.ExprReducer
  • __builtin__.object

Class variables

var allow_none_result

var reduction_rules

Instance variables

var enforce_strict_access

var expr_types

var types_mngr

Methods

def __init__(

self, expr_types, types_mngr, enforce_strict_access=True)

Init GenCAccess

@expr_types: a dictionnary linking ID names to their types @types_mngr: types manager @enforce_strict_access: If false, generate access even on expression pointing to a middle of an object. If true, raise exception if such a pointer is encountered

def __init__(self, expr_types, types_mngr, enforce_strict_access=True):
    """Init GenCAccess
    @expr_types: a dictionnary linking ID names to their types
    @types_mngr: types manager
    @enforce_strict_access: If false, generate access even on expression
    pointing to a middle of an object. If true, raise exception if such a
    pointer is encountered
    """
    self.expr_types = expr_types
    self.types_mngr = types_mngr
    self.enforce_strict_access = enforce_strict_access

def apply_rules(

self, node, lvl=0, **kwargs)

Find and apply reduction rules to @node

@node: ExprNode to analyse @lvl: actuel recusion level

def apply_rules(self, node, lvl=0, **kwargs):
    """Find and apply reduction rules to @node
    @node: ExprNode to analyse
    @lvl: actuel recusion level
    """
    for rule in self.reduction_rules:
        ret = rule(self, node, lvl=lvl, **kwargs)
        if ret is not None:
            log_reduce.debug("\t" * lvl + "Rule found: %r", rule)
            return ret
    if not self.allow_none_result:
        raise RuntimeError('Missing reduction rule for %r' % node.expr)

def categorize(

self, node, lvl=0, **kwargs)

Recursively apply rules to @node

@node: ExprNode to analyze @lvl: actual recusion level

def categorize(self, node, lvl=0, **kwargs):
    """Recursively apply rules to @node
    @node: ExprNode to analyze
    @lvl: actual recusion level
    """
    expr = node.expr
    log_reduce.debug("\t" * lvl + "Reduce...: %s", node.expr)
    if isinstance(expr, (ExprId, ExprInt, ExprLoc)):
        pass
    elif isinstance(expr, ExprMem):
        arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprMem(arg.expr, expr.size))
        node.arg = arg
    elif isinstance(expr, ExprSlice):
        arg = self.categorize(node.arg, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprSlice(arg.expr, expr.start, expr.stop))
        node.arg = arg
    elif isinstance(expr, ExprOp):
        new_args = []
        for arg in node.args:
            new_a = self.categorize(arg, lvl=lvl + 1, **kwargs)
            assert new_a.expr.size == arg.expr.size
            new_args.append(new_a)
        node = ExprNode(ExprOp(expr.op, *[x.expr for x in new_args]))
        node.args = new_args
        expr = node.expr
    elif isinstance(expr, ExprCompose):
        new_args = []
        new_expr_args = []
        for arg in node.args:
            arg = self.categorize(arg, lvl=lvl + 1, **kwargs)
            new_args.append(arg)
            new_expr_args.append(arg.expr)
        new_expr = ExprCompose(*new_expr_args)
        node = ExprNode(new_expr)
        node.args = new_args
    elif isinstance(expr, ExprCond):
        cond = self.categorize(node.cond, lvl=lvl + 1, **kwargs)
        src1 = self.categorize(node.src1, lvl=lvl + 1, **kwargs)
        src2 = self.categorize(node.src2, lvl=lvl + 1, **kwargs)
        node = ExprNode(ExprCond(cond.expr, src1.expr, src2.expr))
        node.cond, node.src1, node.src2 = cond, src1, src2
    else:
        raise TypeError("Unknown Expr Type %r", type(expr))
    node.info = self.apply_rules(node, lvl=lvl, **kwargs)
    log_reduce.debug("\t" * lvl + "Reduce result: %s %r",
                     node.expr, node.info)
    return node

def cgen_access(

self, cgenobj, base_type, offset, deref, lvl=0)

Return the access(es) which lead to the element at @offset of an object of type @base_type

In case of no @deref, stops recursion as soon as we reached the base of an object. In other cases, we need to go down to the final dereferenced object

@cgenobj: current object access @base_type: type of main object @offset: offset (in bytes) of the target sub object @deref: get type for a pointer or a deref @lvl: actual recursion level

IN: - base_type: struct Toto{ int a int b } - base_name: var - 4 OUT: - CGenField(var, b)

IN: - base_type: int a - 0 OUT: - CGenAddr(a)

IN: - base_type: X = int* a - 0 OUT: - CGenAddr(X)

IN: - X = int* a - 8 OUT: - ASSERT

IN: - struct toto{ int a int b[10] } - 8 OUT: - CGenArray(CGenField(toto, b), 1)

def cgen_access(self, cgenobj, base_type, offset, deref, lvl=0):
    """Return the access(es) which lead to the element at @offset of an
    object of type @base_type
    In case of no @deref, stops recursion as soon as we reached the base of
    an object.
    In other cases, we need to go down to the final dereferenced object
    @cgenobj: current object access
    @base_type: type of main object
    @offset: offset (in bytes) of the target sub object
    @deref: get type for a pointer or a deref
    @lvl: actual recursion level
    IN:
    - base_type: struct Toto{
        int a
        int b
      }
    - base_name: var
    - 4
    OUT:
    - CGenField(var, b)
    IN:
    - base_type: int a
    - 0
    OUT:
    - CGenAddr(a)
    IN:
    - base_type: X = int* a
    - 0
    OUT:
    - CGenAddr(X)
    IN:
    - X = int* a
    - 8
    OUT:
    - ASSERT
    IN:
    - struct toto{
        int a
        int b[10]
      }
    - 8
    OUT:
    - CGenArray(CGenField(toto, b), 1)
    """
    if base_type.size == 0:
        missing_definition(base_type)
        return set()
    void_type = self.types_mngr.void_ptr
    if isinstance(base_type, ObjCStruct):
        if not 0 <= offset < base_type.size:
            return set()
        if offset == 0 and not deref:
            # In this case, return the struct*
            return set([cgenobj])
        for fieldname, subtype, field_offset, size in base_type.fields:
            if not field_offset <= offset < field_offset + size:
                continue
            fieldptr = CGenField(CGenDeref(cgenobj), fieldname, subtype,
                                 void_type.align, void_type.size)
            new_type = self.cgen_access(fieldptr, subtype,
                                        offset - field_offset,
                                        deref, lvl + 1)
            break
        else:
            return set()
    elif isinstance(base_type, ObjCArray):
        if base_type.objtype.size == 0:
            missing_definition(base_type.objtype)
            return set()
        element_num = offset / (base_type.objtype.size)
        field_offset = offset % base_type.objtype.size
        if element_num >= base_type.elems:
            return set()
        if offset == 0 and not deref:
            # In this case, return the array
            return set([cgenobj])
        curobj = CGenArray(cgenobj, element_num,
                           void_type.align,
                           void_type.size)
        if field_offset == 0:
            # We point to the start of the sub object,
            # return it directly
            return set([curobj])
        new_type = self.cgen_access(curobj, base_type.objtype,
                                    field_offset, deref, lvl + 1)
    elif isinstance(base_type, ObjCDecl):
        if self.enforce_strict_access and offset % base_type.size != 0:
            return set()
        elem_num = offset / base_type.size
        nobj = CGenArray(cgenobj, elem_num,
                         void_type.align, void_type.size)
        new_type = set([nobj])
    elif isinstance(base_type, ObjCUnion):
        if offset == 0 and not deref:
            # In this case, return the struct*
            return set([cgenobj])
        out = set()
        for fieldname, objtype, field_offset, size in base_type.fields:
            if not field_offset <= offset < field_offset + size:
                continue
            field = CGenField(CGenDeref(cgenobj), fieldname, objtype,
                              void_type.align, void_type.size)
            out.update(self.cgen_access(field, objtype,
                                        offset - field_offset,
                                        deref, lvl + 1))
        new_type = out
    elif isinstance(base_type, ObjCPtr):
        elem_num = offset / base_type.size
        if self.enforce_strict_access and offset % base_type.size != 0:
            return set()
        nobj = CGenArray(cgenobj, elem_num,
                         void_type.align, void_type.size)
        new_type = set([nobj])
    else:
        raise NotImplementedError("deref type %r" % base_type)
    return new_type

def expr2node(

self, expr)

Build ExprNode mirror of @expr

@expr: Expression to analyze

def expr2node(self, expr):
    """Build ExprNode mirror of @expr
    @expr: Expression to analyze
    """
    if isinstance(expr, (ExprId, ExprLoc, ExprInt)):
        node = ExprNode(expr)
    elif isinstance(expr, (ExprMem, ExprSlice)):
        son = self.expr2node(expr.arg)
        node = ExprNode(expr)
        node.arg = son
    elif isinstance(expr, ExprOp):
        sons = [self.expr2node(arg) for arg in expr.args]
        node = ExprNode(expr)
        node.args = sons
    elif isinstance(expr, ExprCompose):
        sons = [self.expr2node(arg) for arg in expr.args]
        node = ExprNode(expr)
        node.args = sons
    elif isinstance(expr, ExprCond):
        node = ExprNode(expr)
        node.cond = self.expr2node(expr.cond)
        node.src1 = self.expr2node(expr.src1)
        node.src2 = self.expr2node(expr.src2)
    else:
        raise TypeError("Unknown Expr Type %r", type(expr))
    return node

def get_accesses(

self, expr, expr_context=None)

Generate C access(es) for the native Miasm expression @expr @expr: native Miasm expression @expr_context: a dictionnary linking known expressions to their types. An expression is linked to a tuple of types.

def get_accesses(self, expr, expr_context=None):
    """Generate C access(es) for the native Miasm expression @expr
    @expr: native Miasm expression
    @expr_context: a dictionnary linking known expressions to their
    types. An expression is linked to a tuple of types.
    """
    if expr_context is None:
        expr_context = self.expr_types
    ret = self.reduce(expr, ctxt=expr_context)
    if ret.info is None:
        return set()
    return ret.info

def get_solo_type(

self, node)

Return the type of the @node if it has only one possible type, different from not None. In othe cases, return None.

def get_solo_type(self, node):
    """Return the type of the @node if it has only one possible type,
    different from not None. In othe cases, return None.
    """
    if node.info is None or len(node.info) != 1:
        return None
    return type(list(node.info)[0].ctype)

def reduce(

self, expr, **kwargs)

Returns an ExprNode tree mirroring @expr tree. The ExprNode is computed by applying reduction rules to the expression @expr

@expr: an Expression

def reduce(self, expr, **kwargs):
    """Returns an ExprNode tree mirroring @expr tree. The ExprNode is
    computed by applying reduction rules to the expression @expr
    @expr: an Expression
    """
    node = self.expr2node(expr)
    return self.categorize(node, lvl=0, **kwargs)

def reduce_int(

self, node, **kwargs)

Generate access for ExprInt

def reduce_int(self, node, **kwargs):
    """Generate access for ExprInt"""
    if not isinstance(node.expr, ExprInt):
        return None
    return set([CGenInt(int(node.expr))])

def reduce_known_expr(

self, node, ctxt, **kwargs)

Generate access for known expr

def reduce_known_expr(self, node, ctxt, **kwargs):
    """Generate access for known expr"""
    if node.expr in ctxt:
        objcs = ctxt[node.expr]
        return set(CGenId(objc, str(node.expr)) for objc in objcs)
    return None

def reduce_mem(

self, node, lvl=0, **kwargs)

Generate access for ExprMem: @NN[ptr] -> elem (type) @64[ptr>] -> ptr * @32[ptr] -> struct.00

def reduce_mem(self, node, lvl=0, **kwargs):
    """Generate access for ExprMem:
    * @NN[ptr<elem>] -> elem  (type)
    * @64[ptr<ptr<elem>>] -> ptr<elem>
    * @32[ptr<struct>] -> struct.00
    """
    if not isinstance(node.expr, ExprMem):
        return None
    if node.arg.info is None:
        return None
    assert isinstance(node.arg.info, set)
    void_type = self.types_mngr.void_ptr
    found = set()
    for subcgenobj in node.arg.info:
        if isinstance(subcgenobj.ctype, ObjCArray):
            nobj = CGenArray(subcgenobj, 0,
                             void_type.align,
                             void_type.size)
            target = nobj.ctype.objtype
            for finalcgenobj in self.cgen_access(nobj, target, 0, True, lvl):
                assert isinstance(finalcgenobj.ctype, ObjCPtr)
                if self.enforce_strict_access and finalcgenobj.ctype.objtype.size != node.expr.size / 8:
                    continue
                found.add(CGenDeref(finalcgenobj))
        elif isinstance(subcgenobj.ctype, ObjCPtr):
            target = subcgenobj.ctype.objtype
            # target : type(elem)
            if isinstance(target, (ObjCStruct, ObjCUnion)):
                for finalcgenobj in self.cgen_access(subcgenobj, target, 0, True, lvl):
                    target = finalcgenobj.ctype.objtype
                    if self.enforce_strict_access and target.size != node.expr.size / 8:
                        continue
                    found.add(CGenDeref(finalcgenobj))
            elif isinstance(target, ObjCArray):
                if self.enforce_strict_access and subcgenobj.ctype.size != node.expr.size / 8:
                    continue
                found.update(self.cgen_access(CGenDeref(subcgenobj), target,
                                              0, False, lvl))
            else:
                if self.enforce_strict_access and target.size != node.expr.size / 8:
                    continue
                found.add(CGenDeref(subcgenobj))
    if not found:
        return None
    return found

def reduce_op(

self, node, lvl=0, **kwargs)

Generate access for ExprOp

def reduce_op(self, node, lvl=0, **kwargs):
    """Generate access for ExprOp"""
    if not node.expr.is_op("+") or len(node.args) != 2:
        return None
    type_arg1 = self.get_solo_type(node.args[1])
    if type_arg1 != ObjCInt:
        return None
    arg0, arg1 = node.args
    if arg0.info is None:
        return None
    void_type = self.types_mngr.void_ptr
    out = set()
    if not arg1.expr.is_int():
        return None
    ptr_offset = int(arg1.expr)
    for info in arg0.info:
        if isinstance(info.ctype, ObjCArray):
            field_type = info.ctype
        elif isinstance(info.ctype, ObjCPtr):
            field_type = info.ctype.objtype
        else:
            continue
        target_type = info.ctype.objtype
        # Array-like: int* ptr; ptr[1] = X
        out.update(self.cgen_access(info, field_type, ptr_offset, False, lvl))
    return out

def updt_expr_types(

self, expr_types)

Update expr_types @expr_types: Dictionnary associating name to type

def updt_expr_types(self, expr_types):
    """Update expr_types
    @expr_types: Dictionnary associating name to type
    """
    self.expr_types = expr_types

class ObjC

Generic ObjC

class ObjC(object):
    """Generic ObjC"""

    def __init__(self, align, size):
        self._align = align
        self._size = size

    @property
    def align(self):
        """Alignment (in bytes) of the C object"""
        return self._align

    @property
    def size(self):
        """Size (in bytes) of the C object"""
        return self._size

    def cmp_base(self, other):
        assert self.__class__ in OBJC_PRIO
        assert other.__class__ in OBJC_PRIO

        if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
            return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
        if self.align != other.align:
            return cmp(self.align, other.align)
        return cmp(self.size, other.size)

    def __hash__(self):
        return hash((self.__class__, self._align, self._size))

    def __str__(self):
        return objc_to_str(self)

Ancestors (in MRO)

  • ObjC
  • __builtin__.object

Instance variables

var align

Alignment (in bytes) of the C object

var size

Size (in bytes) of the C object

Methods

def __init__(

self, align, size)

def __init__(self, align, size):
    self._align = align
    self._size = size

def cmp_base(

self, other)

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCArray

C array (test[XX])

class ObjCArray(ObjC):
    """C array (test[XX])"""

    def __init__(self, objtype, elems):
        """Init ObjCArray

        @objtype: pointer target ObjC
        @elems: number of elements in the array
        """

        super(ObjCArray, self).__init__(objtype.align, elems * objtype.size)
        self._elems = elems
        self._objtype = objtype

    objtype = property(lambda self: self._objtype)
    elems = property(lambda self: self._elems)

    def __hash__(self):
        return hash((super(ObjCArray, self).__hash__(), self._elems, hash(self._objtype)))

    def __repr__(self):
        return '<%r[%d]>' % (self.objtype, self.elems)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        ret = cmp(self.elems, other.elems)
        if ret:
            return ret
        return cmp(self.objtype, other.objtype)

Ancestors (in MRO)

Class variables

var elems

var objtype

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var elems

var objtype

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self, objtype, elems)

Inheritance: ObjC.__init__

Init ObjCArray

@objtype: pointer target ObjC @elems: number of elements in the array

def __init__(self, objtype, elems):
    """Init ObjCArray
    @objtype: pointer target ObjC
    @elems: number of elements in the array
    """
    super(ObjCArray, self).__init__(objtype.align, elems * objtype.size)
    self._elems = elems
    self._objtype = objtype

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCDecl

C Declaration identified

class ObjCDecl(ObjC):
    """C Declaration identified"""

    def __init__(self, name, align, size):
        super(ObjCDecl, self).__init__(align, size)
        self._name = name

    name = property(lambda self: self._name)

    def __hash__(self):
        return hash((super(ObjCDecl, self).__hash__(), self._name))

    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.name)

    def __str__(self):
        return str(self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

Ancestors (in MRO)

Class variables

var name

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var name

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self, name, align, size)

Inheritance: ObjC.__init__

def __init__(self, name, align, size):
    super(ObjCDecl, self).__init__(align, size)
    self._name = name

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCEllipsis

C integer

class ObjCEllipsis(ObjC):
    """C integer"""

    def __init__(self):
        super(ObjCEllipsis, self).__init__(None, None)

    align = property(lambda self: self._align)
    size = property(lambda self: self._size)

    def __cmp__(self, other):
        return self.cmp_base(other)

Ancestors (in MRO)

Class variables

var align

var size

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self)

Inheritance: ObjC.__init__

def __init__(self):
    super(ObjCEllipsis, self).__init__(None, None)

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCFunc

C object for Functions

class ObjCFunc(ObjC):
    """C object for Functions"""

    def __init__(self, name, abi, type_ret, args, void_p_align, void_p_size):
        super(ObjCFunc, self).__init__(void_p_align, void_p_size)
        self._name = name
        self._abi = abi
        self._type_ret = type_ret
        self._args = tuple(args)

    args = property(lambda self: self._args)
    type_ret = property(lambda self: self._type_ret)
    abi = property(lambda self: self._abi)
    name = property(lambda self: self._name)

    def __hash__(self):
        return hash((super(ObjCFunc, self).__hash__(), hash(self._args), self._name))

    def __repr__(self):
        return "<%s %s>" % (self.__class__.__name__,
                            self.name)

    def __str__(self):
        out = []
        out.append("Function (%s)  %s: (align: %d)" % (self.abi, self.name, self.align))
        out.append("  ret: %s" % (str(self.type_ret)))
        out.append("  Args:")
        for name, arg in self.args:
            out.append("  %s %s" % (name, arg))
        return '\n'.join(out)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

Ancestors (in MRO)

Class variables

var abi

var args

var name

var type_ret

Instance variables

var abi

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var args

var name

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

var type_ret

Methods

def __init__(

self, name, abi, type_ret, args, void_p_align, void_p_size)

Inheritance: ObjC.__init__

def __init__(self, name, abi, type_ret, args, void_p_align, void_p_size):
    super(ObjCFunc, self).__init__(void_p_align, void_p_size)
    self._name = name
    self._abi = abi
    self._type_ret = type_ret
    self._args = tuple(args)

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCInt

C integer

class ObjCInt(ObjC):
    """C integer"""

    def __init__(self):
        super(ObjCInt, self).__init__(None, None)

    def __str__(self):
        return 'int'

    def __cmp__(self, other):
        return self.cmp_base(other)

Ancestors (in MRO)

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self)

Inheritance: ObjC.__init__

def __init__(self):
    super(ObjCInt, self).__init__(None, None)

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCPtr

C Pointer

class ObjCPtr(ObjC):
    """C Pointer"""

    def __init__(self, objtype, void_p_align, void_p_size):
        """Init ObjCPtr

        @objtype: pointer target ObjC
        @void_p_align: pointer alignment (in bytes)
        @void_p_size: pointer size (in bytes)
        """

        super(ObjCPtr, self).__init__(void_p_align, void_p_size)
        self._lock = False

        self.objtype = objtype
        if objtype is None:
            self._lock = False

    def get_objtype(self):
        assert self._lock is True
        return self._objtype

    def set_objtype(self, objtype):
        assert self._lock is False
        self._lock = True
        self._objtype = objtype

    objtype = property(get_objtype, set_objtype)

    def __hash__(self):
        # Don't try to hash on an unlocked Ptr (still mutable)
        assert self._lock
        return hash((super(ObjCPtr, self).__hash__(), hash(self._objtype)))

    def __repr__(self):
        return '<%s %r>' % (self.__class__.__name__,
                            self.objtype.__class__)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.objtype, other.objtype)

Ancestors (in MRO)

Class variables

var objtype

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var objtype

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self, objtype, void_p_align, void_p_size)

Inheritance: ObjC.__init__

Init ObjCPtr

@objtype: pointer target ObjC @void_p_align: pointer alignment (in bytes) @void_p_size: pointer size (in bytes)

def __init__(self, objtype, void_p_align, void_p_size):
    """Init ObjCPtr
    @objtype: pointer target ObjC
    @void_p_align: pointer alignment (in bytes)
    @void_p_size: pointer size (in bytes)
    """
    super(ObjCPtr, self).__init__(void_p_align, void_p_size)
    self._lock = False
    self.objtype = objtype
    if objtype is None:
        self._lock = False

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

def get_objtype(

self)

def get_objtype(self):
    assert self._lock is True
    return self._objtype

def set_objtype(

self, objtype)

def set_objtype(self, objtype):
    assert self._lock is False
    self._lock = True
    self._objtype = objtype

class ObjCStruct

C object for structures

class ObjCStruct(ObjC):
    """C object for structures"""

    def __init__(self, name, align, size, fields):
        super(ObjCStruct, self).__init__(align, size)
        self._name = name
        self._fields = tuple(fields)

    name = property(lambda self: self._name)
    fields = property(lambda self: self._fields)

    def __hash__(self):
        return hash((super(ObjCStruct, self).__hash__(), self._name))

    def __repr__(self):
        out = []
        out.append("Struct %s: (align: %d)" % (self.name, self.align))
        out.append("  off sz  name")
        for name, objtype, offset, size in self.fields:
            out.append("  0x%-3x %-3d %-10s %r" %
                       (offset, size, name, objtype.__class__.__name__))
        return '\n'.join(out)

    def __str__(self):
        return 'struct %s' % (self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

Ancestors (in MRO)

Class variables

var fields

var name

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var fields

var name

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self, name, align, size, fields)

Inheritance: ObjC.__init__

def __init__(self, name, align, size, fields):
    super(ObjCStruct, self).__init__(align, size)
    self._name = name
    self._fields = tuple(fields)

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)

class ObjCUnion

C object for unions

class ObjCUnion(ObjC):
    """C object for unions"""

    def __init__(self, name, align, size, fields):
        super(ObjCUnion, self).__init__(align, size)
        self._name = name
        self._fields = tuple(fields)

    name = property(lambda self: self._name)
    fields = property(lambda self: self._fields)

    def __hash__(self):
        return hash((super(ObjCUnion, self).__hash__(), self._name))

    def __repr__(self):
        out = []
        out.append("Union %s: (align: %d)" % (self.name, self.align))
        out.append("  off sz  name")
        for name, objtype, offset, size in self.fields:
            out.append("  0x%-3x %-3d %-10s %r" %
                       (offset, size, name, objtype))
        return '\n'.join(out)

    def __str__(self):
        return 'union %s' % (self.name)

    def __cmp__(self, other):
        ret = self.cmp_base(other)
        if ret:
            return ret
        return cmp(self.name, other.name)

Ancestors (in MRO)

Class variables

var fields

var name

Instance variables

var align

Inheritance: ObjC.align

Alignment (in bytes) of the C object

var fields

var name

var size

Inheritance: ObjC.size

Size (in bytes) of the C object

Methods

def __init__(

self, name, align, size, fields)

Inheritance: ObjC.__init__

def __init__(self, name, align, size, fields):
    super(ObjCUnion, self).__init__(align, size)
    self._name = name
    self._fields = tuple(fields)

def cmp_base(

self, other)

Inheritance: ObjC.cmp_base

def cmp_base(self, other):
    assert self.__class__ in OBJC_PRIO
    assert other.__class__ in OBJC_PRIO
    if OBJC_PRIO[self.__class__] != OBJC_PRIO[other.__class__]:
        return cmp(OBJC_PRIO[self.__class__], OBJC_PRIO[other.__class__])
    if self.align != other.align:
        return cmp(self.align, other.align)
    return cmp(self.size, other.size)