Top

miasm.expression.smt2_helper module

# Helper functions for the generation of SMT2 expressions
# The SMT2 expressions will be returned as a string.
# The expressions are divided as follows
#
# - generic SMT2 operations
# - definitions of SMT2 structures
# - bit vector operations
# - array operations

# generic SMT2 operations

def smt2_eq(a, b):
    """
    Assignment: a = b
    """
    return "(= {} {})".format(a, b)


def smt2_implies(a, b):
    """
    Implication: a => b
    """
    return "(=> {} {})".format(a, b)


def smt2_and(*args):
    """
    Conjunction: a and b and c ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(and {})".format(' '.join(args))


def smt2_or(*args):
    """
    Disjunction: a or b or c ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(or {})".format(' '.join(args))


def smt2_ite(cond, a, b):
    """
    If-then-else: cond ? a : b
    """
    return "(ite {} {} {})".format(cond, a, b)


def smt2_distinct(*args):
    """
    Distinction: a != b != c != ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(distinct {})".format(' '.join(args))


def smt2_assert(expr):
    """
    Assertion that @expr holds
    """
    return "(assert {})".format(expr)


# definitions

def declare_bv(bv, size):
    """
    Declares an bit vector @bv of size @size
    """
    return "(declare-fun {} () {})".format(bv, bit_vec(size))


def declare_array(a, bv1, bv2):
    """
    Declares an SMT2 array represented as a map
    from a bit vector to another bit vector.
    :param a: array name
    :param bv1: SMT2 bit vector
    :param bv2: SMT2 bit vector
    """
    return "(declare-fun {} () (Array {} {}))".format(a, bv1, bv2)


def bit_vec_val(v, size):
    """
    Declares a bit vector value
    :param v: int, value of the bit vector
    :param size: size of the bit vector
    """
    return "(_ bv{} {})".format(v, size)


def bit_vec(size):
    """
    Returns a bit vector of size @size
    """
    return "(_ BitVec {})".format(size)


# bit vector operations

def bvadd(a, b):
    """
    Addition: a + b
    """
    return "(bvadd {} {})".format(a, b)


def bvsub(a, b):
    """
    Subtraction: a - b
    """
    return "(bvsub {} {})".format(a, b)


def bvmul(a, b):
    """
    Multiplication: a * b
    """
    return "(bvmul {} {})".format(a, b)


def bvand(a, b):
    """
    Bitwise AND: a & b
    """
    return "(bvand {} {})".format(a, b)


def bvor(a, b):
    """
    Bitwise OR: a | b
    """
    return "(bvor {} {})".format(a, b)


def bvxor(a, b):
    """
    Bitwise XOR: a ^ b
    """
    return "(bvxor {} {})".format(a, b)


def bvneg(bv):
    """
    Unary minus: - bv
    """
    return "(bvneg {})".format(bv)


def bvsdiv(a, b):
    """
    Signed division: a / b
    """
    return "(bvsdiv {} {})".format(a, b)


def bvudiv(a, b):
    """
    Unsigned division: a / b
    """
    return "(bvudiv {} {})".format(a, b)


def bvsmod(a, b):
    """
    Signed modulo: a mod b
    """
    return "(bvsmod {} {})".format(a, b)


def bvurem(a, b):
    """
    Unsigned modulo: a mod b
    """
    return "(bvurem {} {})".format(a, b)


def bvshl(a, b):
    """
    Shift left: a << b
    """
    return "(bvshl {} {})".format(a, b)


def bvlshr(a, b):
    """
    Logical shift right: a >> b
    """
    return "(bvlshr {} {})".format(a, b)


def bvashr(a, b):
    """
    Arithmetic shift right: a a>> b
    """
    return "(bvashr {} {})".format(a, b)


def bv_rotate_left(a, b, size):
    """
    Rotates bits of a to the left b times: a <<< b

    Since ((_ rotate_left b) a) does not support
    symbolic values for b, the implementation is
    based on a C implementation.

    Therefore, the rotation will be computed as
    a << (b & (size - 1))) | (a >> (size - (b & (size - 1))))

    :param a: bit vector
    :param b: bit vector
    :param size: size of a
    """

    # define constant
    s = bit_vec_val(size, size)

    # shift = b & (size  - 1)
    shift = bvand(b, bvsub(s, bit_vec_val(1, size)))

    # (a << shift) | (a >> size - shift)
    rotate = bvor(bvshl(a, shift),
                  bvlshr(a, bvsub(s, shift)))

    return rotate


def bv_rotate_right(a, b, size):
    """
    Rotates bits of a to the right b times: a >>> b

    Since ((_ rotate_right b) a) does not support
    symbolic values for b, the implementation is
    based on a C implementation.

    Therefore, the rotation will be computed as
    a >> (b & (size - 1))) | (a << (size - (b & (size - 1))))

    :param a: bit vector
    :param b: bit vector
    :param size: size of a
    """

    # define constant
    s = bit_vec_val(size, size)

    # shift = b & (size  - 1)
    shift = bvand(b, bvsub(s, bit_vec_val(1, size)))

    # (a >> shift) | (a << size - shift)
    rotate = bvor(bvlshr(a, shift),
                  bvshl(a, bvsub(s, shift)))

    return rotate


def bv_extract(high, low, bv):
    """
    Extracts bits from a bit vector
    :param high: end bit
    :param low: start bit
    :param bv: bit vector
    """
    return "((_ extract {} {}) {})".format(high, low, bv)


def bv_concat(a, b):
    """
    Concatenation of two SMT2 expressions
    """
    return "(concat {} {})".format(a, b)


# array operations

def array_select(array, index):
    """
    Reads from an SMT2 array at index @index
    :param array: SMT2 array
    :param index: SMT2 expression, index of the array
    """
    return "(select {} {})".format(array, index)


def array_store(array, index, value):
    """
    Writes an value into an SMT2 array at address @index
    :param array: SMT array
    :param index: SMT2 expression, index of the array
    :param value: SMT2 expression, value to write
    """
    return "(store {} {} {})".format(array, index, value)

Functions

def array_select(

array, index)

Reads from an SMT2 array at index @index :param array: SMT2 array :param index: SMT2 expression, index of the array

def array_select(array, index):
    """
    Reads from an SMT2 array at index @index
    :param array: SMT2 array
    :param index: SMT2 expression, index of the array
    """
    return "(select {} {})".format(array, index)

def array_store(

array, index, value)

Writes an value into an SMT2 array at address @index :param array: SMT array :param index: SMT2 expression, index of the array :param value: SMT2 expression, value to write

def array_store(array, index, value):
    """
    Writes an value into an SMT2 array at address @index
    :param array: SMT array
    :param index: SMT2 expression, index of the array
    :param value: SMT2 expression, value to write
    """
    return "(store {} {} {})".format(array, index, value)

def bit_vec(

size)

Returns a bit vector of size @size

def bit_vec(size):
    """
    Returns a bit vector of size @size
    """
    return "(_ BitVec {})".format(size)

def bit_vec_val(

v, size)

Declares a bit vector value :param v: int, value of the bit vector :param size: size of the bit vector

def bit_vec_val(v, size):
    """
    Declares a bit vector value
    :param v: int, value of the bit vector
    :param size: size of the bit vector
    """
    return "(_ bv{} {})".format(v, size)

def bv_concat(

a, b)

Concatenation of two SMT2 expressions

def bv_concat(a, b):
    """
    Concatenation of two SMT2 expressions
    """
    return "(concat {} {})".format(a, b)

def bv_extract(

high, low, bv)

Extracts bits from a bit vector :param high: end bit :param low: start bit :param bv: bit vector

def bv_extract(high, low, bv):
    """
    Extracts bits from a bit vector
    :param high: end bit
    :param low: start bit
    :param bv: bit vector
    """
    return "((_ extract {} {}) {})".format(high, low, bv)

def bv_rotate_left(

a, b, size)

Rotates bits of a to the left b times: a <<< b

Since ((_ rotate_left b) a) does not support symbolic values for b, the implementation is based on a C implementation.

Therefore, the rotation will be computed as a << (b & (size - 1))) | (a >> (size - (b & (size - 1))))

:param a: bit vector :param b: bit vector :param size: size of a

def bv_rotate_left(a, b, size):
    """
    Rotates bits of a to the left b times: a <<< b

    Since ((_ rotate_left b) a) does not support
    symbolic values for b, the implementation is
    based on a C implementation.

    Therefore, the rotation will be computed as
    a << (b & (size - 1))) | (a >> (size - (b & (size - 1))))

    :param a: bit vector
    :param b: bit vector
    :param size: size of a
    """

    # define constant
    s = bit_vec_val(size, size)

    # shift = b & (size  - 1)
    shift = bvand(b, bvsub(s, bit_vec_val(1, size)))

    # (a << shift) | (a >> size - shift)
    rotate = bvor(bvshl(a, shift),
                  bvlshr(a, bvsub(s, shift)))

    return rotate

def bv_rotate_right(

a, b, size)

Rotates bits of a to the right b times: a >>> b

Since ((_ rotate_right b) a) does not support symbolic values for b, the implementation is based on a C implementation.

Therefore, the rotation will be computed as a >> (b & (size - 1))) | (a << (size - (b & (size - 1))))

:param a: bit vector :param b: bit vector :param size: size of a

def bv_rotate_right(a, b, size):
    """
    Rotates bits of a to the right b times: a >>> b

    Since ((_ rotate_right b) a) does not support
    symbolic values for b, the implementation is
    based on a C implementation.

    Therefore, the rotation will be computed as
    a >> (b & (size - 1))) | (a << (size - (b & (size - 1))))

    :param a: bit vector
    :param b: bit vector
    :param size: size of a
    """

    # define constant
    s = bit_vec_val(size, size)

    # shift = b & (size  - 1)
    shift = bvand(b, bvsub(s, bit_vec_val(1, size)))

    # (a >> shift) | (a << size - shift)
    rotate = bvor(bvlshr(a, shift),
                  bvshl(a, bvsub(s, shift)))

    return rotate

def bvadd(

a, b)

Addition: a + b

def bvadd(a, b):
    """
    Addition: a + b
    """
    return "(bvadd {} {})".format(a, b)

def bvand(

a, b)

Bitwise AND: a & b

def bvand(a, b):
    """
    Bitwise AND: a & b
    """
    return "(bvand {} {})".format(a, b)

def bvashr(

a, b)

Arithmetic shift right: a a>> b

def bvashr(a, b):
    """
    Arithmetic shift right: a a>> b
    """
    return "(bvashr {} {})".format(a, b)

def bvlshr(

a, b)

Logical shift right: a >> b

def bvlshr(a, b):
    """
    Logical shift right: a >> b
    """
    return "(bvlshr {} {})".format(a, b)

def bvmul(

a, b)

Multiplication: a * b

def bvmul(a, b):
    """
    Multiplication: a * b
    """
    return "(bvmul {} {})".format(a, b)

def bvneg(

bv)

Unary minus: - bv

def bvneg(bv):
    """
    Unary minus: - bv
    """
    return "(bvneg {})".format(bv)

def bvor(

a, b)

Bitwise OR: a | b

def bvor(a, b):
    """
    Bitwise OR: a | b
    """
    return "(bvor {} {})".format(a, b)

def bvsdiv(

a, b)

Signed division: a / b

def bvsdiv(a, b):
    """
    Signed division: a / b
    """
    return "(bvsdiv {} {})".format(a, b)

def bvshl(

a, b)

Shift left: a << b

def bvshl(a, b):
    """
    Shift left: a << b
    """
    return "(bvshl {} {})".format(a, b)

def bvsmod(

a, b)

Signed modulo: a mod b

def bvsmod(a, b):
    """
    Signed modulo: a mod b
    """
    return "(bvsmod {} {})".format(a, b)

def bvsub(

a, b)

Subtraction: a - b

def bvsub(a, b):
    """
    Subtraction: a - b
    """
    return "(bvsub {} {})".format(a, b)

def bvudiv(

a, b)

Unsigned division: a / b

def bvudiv(a, b):
    """
    Unsigned division: a / b
    """
    return "(bvudiv {} {})".format(a, b)

def bvurem(

a, b)

Unsigned modulo: a mod b

def bvurem(a, b):
    """
    Unsigned modulo: a mod b
    """
    return "(bvurem {} {})".format(a, b)

def bvxor(

a, b)

Bitwise XOR: a ^ b

def bvxor(a, b):
    """
    Bitwise XOR: a ^ b
    """
    return "(bvxor {} {})".format(a, b)

def declare_array(

a, bv1, bv2)

Declares an SMT2 array represented as a map from a bit vector to another bit vector. :param a: array name :param bv1: SMT2 bit vector :param bv2: SMT2 bit vector

def declare_array(a, bv1, bv2):
    """
    Declares an SMT2 array represented as a map
    from a bit vector to another bit vector.
    :param a: array name
    :param bv1: SMT2 bit vector
    :param bv2: SMT2 bit vector
    """
    return "(declare-fun {} () (Array {} {}))".format(a, bv1, bv2)

def declare_bv(

bv, size)

Declares an bit vector @bv of size @size

def declare_bv(bv, size):
    """
    Declares an bit vector @bv of size @size
    """
    return "(declare-fun {} () {})".format(bv, bit_vec(size))

def smt2_and(

*args)

Conjunction: a and b and c ...

def smt2_and(*args):
    """
    Conjunction: a and b and c ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(and {})".format(' '.join(args))

def smt2_assert(

expr)

Assertion that @expr holds

def smt2_assert(expr):
    """
    Assertion that @expr holds
    """
    return "(assert {})".format(expr)

def smt2_distinct(

*args)

Distinction: a != b != c != ...

def smt2_distinct(*args):
    """
    Distinction: a != b != c != ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(distinct {})".format(' '.join(args))

def smt2_eq(

a, b)

Assignment: a = b

def smt2_eq(a, b):
    """
    Assignment: a = b
    """
    return "(= {} {})".format(a, b)

def smt2_implies(

a, b)

Implication: a => b

def smt2_implies(a, b):
    """
    Implication: a => b
    """
    return "(=> {} {})".format(a, b)

def smt2_ite(

cond, a, b)

If-then-else: cond ? a : b

def smt2_ite(cond, a, b):
    """
    If-then-else: cond ? a : b
    """
    return "(ite {} {} {})".format(cond, a, b)

def smt2_or(

*args)

Disjunction: a or b or c ...

def smt2_or(*args):
    """
    Disjunction: a or b or c ...
    """
    # transform args into strings
    args = [str(arg) for arg in args]
    return "(or {})".format(' '.join(args))