Example #1
0
 def __init__(self, bytecode, mappingInfo, assertInfo={}):
     self.bc = bytecode
     self.addr2line = mappingInfo
     self.assertInfo = assertInfo
     # Useful to set line breakpoints
     self.line2addr = {}
     for addr, lines in mappingInfo.items():
         for line in lines:
             self.line2addr[line] = addr
     self.lineBreakpoints = []
     self.sim = Simulator(bytecode, self.assertInfo, self.addr2line)
     self.reset()
Example #2
0
class BCInterpreter:

    def __init__(self, bytecode, mappingInfo):
        self.bc = bytecode
        self.dbginf = mappingInfo
        self.sim = Simulator(bytecode)
        self.reset()

    def reset(self):
        self.sim.reset()

    def setBreakpoints(self, lineno):
        pass

    def setBreakpointsMem(self, addr):
        pass

    def stepforward(self):
        self.sim.nextInstr()

    def stepinto(self):
        self.sim.nextInstr()

    def stepout(self):
        pass

    def run(self):
        pass

    def getMemory(self):
        return self.sim.mem.serialize()

    def getRegisters(self):
        return list(r.get() for r in self.sim.regs)

    def getCurrentLine(self):
        pc = self.sim.regs[15].get()
        assert pc in self.dbginf, "Line outside of linked memory!"
        return self.dbginf[pc][-1]
Example #3
0
class BCInterpreter:
    def __init__(self, bytecode, mappingInfo, assertInfo={}):
        self.bc = bytecode
        self.addr2line = mappingInfo
        self.assertInfo = assertInfo
        # Useful to set line breakpoints
        self.line2addr = {}
        for addr, lines in mappingInfo.items():
            for line in lines:
                self.line2addr[line] = addr
        self.lineBreakpoints = []
        self.sim = Simulator(bytecode, self.assertInfo, self.addr2line)
        self.reset()

    def reset(self):
        self.sim.reset()

    def getBreakpointInstr(self, diff=False):
        if diff and hasattr(self, '_oldLineBreakpoints'):
            ret = list(set(self.lineBreakpoints) ^ self._oldLineBreakpoints)
        else:
            ret = self.lineBreakpoints

        self._oldLineBreakpoints = set(self.lineBreakpoints)
        return ret

    def setBreakpointInstr(self, listLineNumbers):
        # First, we remove all execution breakpoints
        self.sim.mem.removeExecuteBreakpoints(
            removeList=[self.line2addr[b] for b in self.lineBreakpoints])

        # Now we add all breakpoint
        # The easy case is when the line is directly mapped to a memory address (e.g. it is an instruction)
        # When it's not, we have to find the closest next line which is mapped
        # If there is no such line (we are asked to put a breakpoint after the last line of code) then no breakpoint is set
        self.lineBreakpoints = []
        for lineno in listLineNumbers:
            if lineno in self.line2addr:
                self.sim.mem.setBreakpoint(self.line2addr[lineno], 1)
                nextLine = lineno + 1
                while nextLine in self.line2addr and self.line2addr[
                        nextLine] == self.line2addr[lineno]:
                    nextLine += 1
                self.lineBreakpoints.append(nextLine - 1)

    def getBreakpointsMem(self):
        return {
            'r':
            [k for k, v in self.sim.mem.breakpoints.items() if (v & 6) == 4],
            'w':
            [k for k, v in self.sim.mem.breakpoints.items() if (v & 6) == 2],
            'rw':
            [k for k, v in self.sim.mem.breakpoints.items() if (v & 6) == 6],
            'e':
            [k for k, v in self.sim.mem.breakpoints.items() if bool(v & 1)],
        }

    def setBreakpointMem(self, addr, mode):
        # Mode = 'r' | 'w' | 'rw' | 'e' | '' (passing an empty string removes the breakpoint)
        modeOctal = 4 * ('r' in mode) + 2 * ('w' in mode) + 1 * ('e' in mode)
        self.sim.mem.setBreakpoint(addr, modeOctal)

    def toggleBreakpointMem(self, addr, mode):
        # Mode = 'r' | 'w' | 'rw' | 'e' | '' (passing an empty string removes the breakpoint)
        modeOctal = 4 * ('r' in mode) + 2 * ('w' in mode) + 1 * ('e' in mode)
        bkptInfo = self.sim.mem.toggleBreakpoint(addr, modeOctal)
        if 'e' in mode:
            addrprod4 = (addr // 4) * 4
            if addrprod4 in self.addr2line:
                if bkptInfo & 1:  # Add line breakpoint
                    self.lineBreakpoints.append(self.addr2line[addrprod4][-1])
                else:  # Remove line breakpoint
                    try:
                        self.lineBreakpoints.remove(
                            self.addr2line[addrprod4][-1])
                    except ValueError:
                        # Not sure how we can reach this, but just in case, it is not a huge problem so we do not want to crash
                        pass

    def setBreakpointRegister(self, bank, reg, mode):
        # Mode = 'r' | 'w' | 'rw' | '' (passing an empty string removes the breakpoint)
        modeOctal = 4 * ('r' in mode) + 2 * ('w' in mode)
        bank = "User" if bank == "user" else bank.upper()
        self.sim.regs.getRegisterFromBank(bank, reg).breakpoint = modeOctal

    def setBreakpointFlag(self, flag, mode):
        # Mode = 'r' | 'w' | 'rw' | '' (passing an empty string removes the breakpoint)
        modeOctal = 4 * ('r' in mode) + 2 * ('w' in mode)
        self.sim.flags.breakpoints[flag.upper()] = modeOctal

    def setInterrupt(self,
                     type,
                     clearinterrupt,
                     ncyclesbefore=0,
                     ncyclesperiod=0,
                     begincountat=0):
        # type is either "FIQ" or "IRQ"
        # ncyclesbefore is the number of cycles to wait before the first interrupt
        # ncyclesperiod the number of cycles between two interrupts
        # clearinterrupt must be set to True if one wants to clear the interrupt
        # begincountat gives the t=0 as a cycle number. If it is 0, then the first interrupt will happen at time t=ncyclesbefore
        #   if it is > 0, then it will be at t = ncyclesbefore + begincountat
        #   if < 0, then the begin cycle is set at the current cycle
        self.sim.interruptActive = not clearinterrupt
        self.sim.interruptParams['b'] = ncyclesbefore
        self.sim.interruptParams['a'] = ncyclesperiod
        self.sim.interruptParams[
            't0'] = begincountat if begincountat >= 0 else self.sim.sysHandle.countCycles
        self.sim.interruptParams['type'] = type.upper()
        self.sim.lastInterruptCycle = -1

    @property
    def shouldStop(self):
        return self.sim.isStepDone()

    @property
    def currentBreakpoint(self):
        # Returns a list of namedTuple with the fields
        # 'source' = 'register' | 'memory' | 'flag' | 'assert' | 'pc'
        # 'mode' = integer (same interpretation as Unix permissions)
        #                   if source='memory' then mode can also be 8 : it means that we're trying to access an uninitialized memory address
        # 'infos' = supplemental information (register index if source='register', flag name if source='flag', address if source='memory')
        #               if source='assert', then infos is a tuple (line (integer), description (string))
        # If no breakpoint has been trigged in the last instruction, then return None
        return self.sim.sysHandle.breakpointInfo if self.sim.sysHandle.breakpointTrigged else None

    def step(self, stepMode=None):
        # stepMode= "into" | "forward" | "out" | "run"
        # None means to keep the current mode, whatever it is
        if stepMode is not None:
            self.sim.setStepCondition(stepMode)
        self.sim.nextInstr()

    def stepBack(self, count=1):
        # step back 'count' times
        self.sim.stepBack(count)

    def getMemory(self, addr, returnHexaStr=True):
        val = self.sim.mem.get(addr, 1, mayTriggerBkpt=False)
        if val is None:
            return "--"
        if returnHexaStr:
            return "{:02X}".format(unpack("B", val)[0])
        else:
            return val

    def getMemoryFormatted(self):
        return self.sim.mem.serializeFormatted()

    def setMemory(self, addr, val):
        # if addr is not initialized, then do nothing
        # val is a bytearray of one element (1 byte)
        if self.sim.mem._getRelativeAddr(addr, 1) is None:
            return
        try:
            val = int(val, base=16)
        except ValueError:  # Invalid value
            return
        self.sim.mem.set(addr, val[0], 1)
        pc = self.sim.regs[15].get(mayTriggerBkpt=False)
        pc -= 8 if getSetting("PCbehavior") == "+8" else 0
        if 0 <= addr - pc < 4:
            # We decode the instruction again
            self.sim.fetchAndDecode()

    def getCurrentInfos(self):
        # Return [["highlightread", ["r3", "SVC_r12", "z", "sz"]], ["highlightwrite", ["r1", "MEM_adresseHexa"]], ["nextline", 42], ["disassembly", ""]]
        # We must clone each element so we do not change the internals of the simulator
        s = tuple(x[:] for x in self.sim.disassemblyInfo)

        # Convert nextline from addr to line number
        idx = [i for i, x in enumerate(s) if x[0] == "nextline"]
        try:
            s[idx[0]][1] = self.addr2line[s[idx[0]][1]][-1]
        except IndexError:
            s = [x for i, x in enumerate(s) if x[0] != "nextline"]

        return s

    def getRegisters(self):
        return self.sim.regs.getAllRegisters()

    def setRegisters(self, regsDict):
        for r, v in regsDict.items():
            self.sim.regs[r].set(v, mayTriggerBkpt=False)
        # Changing the registers may change some infos in the prediction (for instance, memory cells affected by a mem access)
        self.sim.decodeInstr()

    def getFlags(self):
        # Return a dictionnary of the flags; if the current mode has a SPSR, then this method also returns
        # its flags, with their name prepended with 'S', in the same dictionnary
        d = self.sim.flags.getAllFlags()
        if self.sim.regs.getSPSR() is not None:
            d.update({
                "S{}".format(k): v
                for k, v in self.sim.regs.getSPSR().getAllFlags().items()
            })
        return d

    def setFlags(self, flagsDict):
        # Set the flags in CPSR and the current SPSR (if there is such register)
        # The input is a dictionnary with flag names as keys and booleans as values
        # To set the SPSR flags, the keys to use are the same as the CPSR, but prepended with a 'S'
        # (e.g. use 'SC' to reference carry flag in the current SPSR)
        hasSPSR = self.sim.regs.getSPSR() is not None
        for f, v in flagsDict.items():
            if hasSPSR and len(f) == 2:
                f = f[1]
                self.sim.regs.getSPSR().setFlag(f.upper(),
                                                int(v),
                                                mayTriggerBkpt=False)
            elif len(f) == 1:
                self.sim.flags.setFlag(f.upper(), int(v), mayTriggerBkpt=False)
        # Changing the flags may change the decision to execute or not the next instruction, we update it
        self.sim.decodeInstr()

    def getProcessorMode(self):
        return self.sim.flags.getMode()

    def getCycleCount(self):
        return self.sim.sysHandle.countCycles

    def getChanges(self):
        # Return the modified registers, memory, flags
        #
        d = {}
        dRegsAndFlags, dBank = self.sim.regs.getRegistersAndFlagsChanges()
        if dBank is not None:
            d["bank"] = dBank
        if len(dRegsAndFlags) > 0:
            d["register"] = dRegsAndFlags

        lMem = self.sim.mem.getMemoryChanges()
        if len(lMem) > 0:
            d["memory"] = lMem
        return d

    def getCurrentLine(self):
        pc = self.sim.regs[15].get(mayTriggerBkpt=False)
        pc -= 8 if getSetting("PCbehavior") == "+8" else 0
        assert pc in self.addr2line, "Line outside of linked memory!"
        assert len(self.addr2line[pc]) > 0, "Line outside of linked memory!"
        return self.addr2line[pc][-1]

    def getCurrentInstructionAddress(self):
        pc = self.sim.regs[15].get(mayTriggerBkpt=False)
        pc -= 8 if getSetting("PCbehavior") == "+8" else 0
        return pc
Example #4
0
 def __init__(self, bytecode, mappingInfo):
     self.bc = bytecode
     self.dbginf = mappingInfo
     self.sim = Simulator(bytecode)
     self.reset()