# The MIT License (MIT)
#
# Copyright (c) 2018 Thomas Barabosch of Fraunhofer FKIE
# <thomas.barabosch (at) fkie.fraunhofer.de>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import re
import signal

from lib.tools import memoized
from lib.analyzers.x86 import Analyzer


class MipsAnalyzer(Analyzer):
    '''
    An analyzer for an MIPS Linux GDB target. See x86.py for more info on 
    Analyzers.
    '''

    def __init__(self, target):
        Analyzer.__init__(self, target)

    @memoized
    def isReturnAv(self):
        rets = ["jar", "jr"]
        return self.isAccessViolationSignal() and \
            (self.target.current_instruction() and
             (self.target.current_instruction().mnemonic in rets))

    @memoized
    def isBlockMove(self):
        return False

    @memoized
    def isJumpInstruction(self):
        ins = self.target.current_instruction()
        # https://www2.cs.duke.edu/courses/fall13/compsci250/MIPS32_QRC.pdf
        jumps = ["b", "bal", "beq", "beqz", "bgez", "begezal", "bgtz",
                 "belz", "bltz", "bltzal", "bne", "bnez", "j", "jal",
                 "jalr", "jr"]
        return ins and ins.mnemonic in jumps

    @memoized
    # TODO: think about MIPS delay slot!!!!
    def isBranchAv(self):
        if not self.isAccessViolationSignal():
            return False
        return self.isJumpInstruction()

    @memoized
    def faultingAddress(self):
        if self.isJumpInstruction():
            # si_addr does not always contain a valid faulting address, but
            # jump instructions always access the dest op and GDB always displays
            # the absolute addr, so we can use the dest op instead of si_addr here.
            # FIXME: check type of instruction and use the corresponding operand, e.g. 1 instead of 0
            return self.target.current_instruction().operands[0].eval()
        return self.target.si_addr()
