# Copyright (c) 2014, Fundacion Dr. Manuel Sadosky
# All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:

# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.

# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
This module contains all the classes that handle the intermediate
representation language. It is basically the REIL language with minor
changes. Below there is an overview of the REIL language and its
instruction format. For full details see "REIL: A platform-independent
intermediate representation of disassembled code for static code
analysis."

All algorithms within the framework are designed to operate on the
intermediate representation. This provides great flexibility when it
comes to implement a cross-platform framework.

Instruction Format
------------------

    mnemonic oprnd1, oprnd2, oprnd3

Instructions
------------

    Arithmetic    : ADD, SUB, MUL, DIV, MOD, BSH
    Bitwise       : AND, OR, XOR
    Data Transfer : LDM, STM, STR
    Conditional   : BISZ, JCC
    Other         : UNDEF, UNKN, NOP

"""

# Display operands size in intruction
show_size = True

# TODO: Create module util and move this function there.
def split_address(address):
    return address >> 0x08, address & 0xff

class ReilMnemonic(object):

    """Enumeration of IR mnemonics.
    """

    # Arithmetic Instructions
    ADD   = 1
    SUB   = 2
    MUL   = 3
    DIV   = 4
    MOD   = 5
    BSH   = 6

    # Bitwise Instructions
    AND   = 7
    OR    = 8
    XOR   = 9

    # Data Transfer Instructions
    LDM   = 10
    STM   = 11
    STR   = 12

    # Conditional Instructions
    BISZ  = 13
    JCC   = 14

    # Other Instructions
    UNKN  = 15
    UNDEF = 16
    NOP   = 17

    # Added Instructions
    RET   = 18

    # Extensions
    SEXT  = 19

    @staticmethod
    def to_string(mnemonic):
        """Return the string representation of the given mnemonic.
        """
        strings = {
            # Arithmetic Instructions
            ReilMnemonic.ADD : "add",
            ReilMnemonic.SUB : "sub",
            ReilMnemonic.MUL : "mul",
            ReilMnemonic.DIV : "div",
            ReilMnemonic.MOD : "mod",
            ReilMnemonic.BSH : "bsh",

            # Bitwise Instructions
            ReilMnemonic.AND : "and",
            ReilMnemonic.OR : "or",
            ReilMnemonic.XOR : "xor",

            # Data Transfer Instructions
            ReilMnemonic.LDM : "ldm",
            ReilMnemonic.STM : "stm",
            ReilMnemonic.STR : "str",

            # Conditional Instructions
            ReilMnemonic.BISZ : "bisz",
            ReilMnemonic.JCC : "jcc",

            # Other Instructions
            ReilMnemonic.UNKN  : "unkn" ,
            ReilMnemonic.UNDEF : "undef" ,
            ReilMnemonic.NOP : "nop" ,

            # Added Instructions
            ReilMnemonic.RET : "ret",

            # Extensions
            ReilMnemonic.SEXT : "sext",
        }

        return strings[mnemonic]

    @staticmethod
    def from_string(string):
        """Return the mnemonic represented by the given string.
        """
        mnemonics = {
            # Arithmetic Instructions
            "add" : ReilMnemonic.ADD,
            "sub" : ReilMnemonic.SUB,
            "mul" : ReilMnemonic.MUL,
            "div" : ReilMnemonic.DIV,
            "mod" : ReilMnemonic.MOD,
            "bsh" : ReilMnemonic.BSH,

            # Bitwise Instructions
            "and" : ReilMnemonic.AND,
            "or" : ReilMnemonic.OR,
            "xor" : ReilMnemonic.XOR,

            # Data Transfer Instructions
            "ldm" : ReilMnemonic.LDM,
            "stm" : ReilMnemonic.STM,
            "str" : ReilMnemonic.STR,

            # Conditional Instructions
            "bisz" : ReilMnemonic.BISZ,
            "jcc" : ReilMnemonic.JCC,

            # Other Instructions
            "unkn" : ReilMnemonic.UNKN,
            "undef" : ReilMnemonic.UNDEF,
            "nop" : ReilMnemonic.NOP,

            # Added Instructions
            "ret" : ReilMnemonic.RET,

            # Added Instructions
            "sext" : ReilMnemonic.SEXT,
        }

        return mnemonics[string]


REIL_MNEMONICS = (
    # Arithmetic Instructions
    ReilMnemonic.ADD,
    ReilMnemonic.SUB,
    ReilMnemonic.MUL,
    ReilMnemonic.DIV,
    ReilMnemonic.MOD,
    ReilMnemonic.BSH,

    # Bitwise Instructions
    ReilMnemonic.AND,
    ReilMnemonic.OR,
    ReilMnemonic.XOR,

    # Data Transfer Instructions
    ReilMnemonic.LDM,
    ReilMnemonic.STM,
    ReilMnemonic.STR,

    # Conditional Instructions
    ReilMnemonic.BISZ,
    ReilMnemonic.JCC,

    # Other Instructions
    ReilMnemonic.UNKN,
    ReilMnemonic.UNDEF,
    ReilMnemonic.NOP,

    # Added Instructions
    ReilMnemonic.RET,

    # Extensions
    ReilMnemonic.SEXT,
)

class ReilInstruction(object):

    """Representation of a REIL instruction.
    """

    __slots__ = [
        '_mnemonic',
        '_operands',
        '_comment',
        '_address',
    ]

    def __init__(self):