def buildBasicBlocks(leaders, code_object, entry_addr):
    i = 0
    bb_list = []
    disassembler = Disassembler(code_object)

    while i < len(leaders):
        leader1, leader2 = leaders[i], leaders[i+1]
        addr1, addr2 = leader1.addr, leader2.addr
        bb = BasicBlock()
        bb_list.append(bb)
        bb.addr = addr1
        offset = 0
        if addr1 == entry_addr:
            bb.isEntry = True

        if leader1.type == 'S' and leader2.type == 'E':
            while addr1 + offset <= addr2:
                ins = disassembler.disasAt(addr1  + offset)
                bb.addInstruction(ins)
                offset += ins.size
            i += 2

        elif leader1.type == 'S' and leader2.type == 'S':
            while addr1 + offset < addr2:
                ins = disassembler.disasAt(addr1  + offset)
                bb.addInstruction(ins)
                offset += ins.size
            i += 1

    return bb_list
def buildBasicBlocks(leaders, code_object, entry_addr):
    i = 0
    bb_list = []
    disassembler = Disassembler(code_object)

    while i < len(leaders):
        leader1, leader2 = leaders[i], leaders[i + 1]
        addr1, addr2 = leader1.addr, leader2.addr
        bb = BasicBlock()
        bb_list.append(bb)
        bb.addr = addr1
        offset = 0
        if addr1 == entry_addr:
            bb.isEntry = True

        if leader1.type == 'S' and leader2.type == 'E':
            while addr1 + offset <= addr2:
                ins = disassembler.disasAt(addr1 + offset)
                bb.addInstruction(ins)
                offset += ins.size
            i += 2

        elif leader1.type == 'S' and leader2.type == 'S':
            while addr1 + offset < addr2:
                ins = disassembler.disasAt(addr1 + offset)
                bb.addInstruction(ins)
                offset += ins.size
            i += 1

    return bb_list
Example #3
0
 def __init__(self, filename):
     Disassembler.__init__(self, filename)
     PAPA_ROP.__init__(self, filename)
     Format_String.__init__(self, filename)
     Process.__init__(self, filename)
     Misc.__init__(self, filename)
     context.log_level = 'INFO'
     context.delete_corefiles = True
Example #4
0
def main():

    if len(argv) < 3:
        print "Usage : %s <number of instrucitons> <filename>" % argv[0]
        return

    analyzer = Analyzer(argv[1])

    da = Disassembler()
    da.disassemble(analyzer, argv[2])
def findLeaders(code_object, oep):
    Leader = collections.namedtuple('leader', ['type', 'addr'])

    leader_set = set()
    leader_set.add(Leader('S', oep))

    # Queue to contain list of addresses to be analyzed by linear sweep disassembly algorithm
    analysis_Q = Queue.Queue()
    analysis_Q.put(oep)

    analyzed_addresses = set()

    disassembler = Disassembler(code_object)

    while not analysis_Q.empty():
        addr = analysis_Q.get()

        while True:
            ins = disassembler.disasAt(addr)
            analyzed_addresses.add(addr)

            # If current instruction is a return, stop disassembling further
            # current address is an end leader
            if utils.isRetIns(ins):
                leader_set.add(Leader('E', addr))
                break

            # If current instruction is braching, stop disassembling further
            # the current instr is an end leader, branch target is start leader
            if utils.isBranchIns(ins):
                leader_set.add(Leader('E', addr))
                for target in getInsCrossRef(ins, addr):
                    leader_set.add(Leader('S', target))
                    if target not in analyzed_addresses:
                        analysis_Q.put(target)
                break

            # Current instruction is not branching
            else:
                # Get cross refs
                cross_refs = getInsCrossRef(ins, addr)
                addr = cross_refs[0] # The immediate next instruction

                # Some non branching instructions like SETUP_LOOP,
                # SETUP_EXCEPT can have more than 1 cross references
                if len(cross_refs) == 2:
                    leader_set.add(Leader('S', cross_refs[1]))

                    if cross_refs[1] not in analyzed_addresses:
                        analysis_Q.put(cross_refs[1])

    return sorted(leader_set, cmp = _leaderSortFunc)
def findLeaders(code_object, oep):
    Leader = collections.namedtuple('leader', ['type', 'addr'])

    leader_set = set()
    leader_set.add(Leader('S', oep))

    # Queue to contain list of addresses to be analyzed by linear sweep disassembly algorithm
    analysis_Q = queue.Queue()
    analysis_Q.put(oep)

    analyzed_addresses = set()

    disassembler = Disassembler(code_object)

    while not analysis_Q.empty():
        addr = analysis_Q.get()

        while True:
            ins = disassembler.disasAt(addr)
            analyzed_addresses.add(addr)

            # If current instruction is a return, stop disassembling further
            # current address is an end leader
            if utils.isRetIns(ins):
                leader_set.add(Leader('E', addr))
                break

            # If current instruction is braching, stop disassembling further
            # the current instr is an end leader, branch target is start leader
            if utils.isBranchIns(ins):
                leader_set.add(Leader('E', addr))
                for target in getInsCrossRef(ins, addr):
                    leader_set.add(Leader('S', target))
                    if target not in analyzed_addresses:
                        analysis_Q.put(target)
                break

            # Current instruction is not branching
            else:
                # Get cross refs
                cross_refs = getInsCrossRef(ins, addr)
                addr = cross_refs[0]  # The immediate next instruction

                # Some non branching instructions like SETUP_LOOP,
                # SETUP_EXCEPT can have more than 1 cross references
                if len(cross_refs) == 2:
                    leader_set.add(Leader('S', cross_refs[1]))

                    if cross_refs[1] not in analyzed_addresses:
                        analysis_Q.put(cross_refs[1])

    return sorted(leader_set, cmp=_leaderSortFunc)
Example #7
0
 def _reset(self, mpu_type, getc_addr=0xF004, putc_addr=0xF001):
     self._mpu = mpu_type(memory=self.memory)
     self.addrWidth = self._mpu.ADDR_WIDTH
     self.byteWidth = self._mpu.BYTE_WIDTH
     self.addrFmt = self._mpu.ADDR_FORMAT
     self.byteFmt = self._mpu.BYTE_FORMAT
     self.addrMask = self._mpu.addrMask
     self.byteMask = self._mpu.byteMask
     if getc_addr and putc_addr:
         self._install_mpu_observers(getc_addr, putc_addr)
     self._address_parser = AddressParser()
     self._disassembler = Disassembler(self._mpu, self._address_parser)
     self._assembler = Assembler(self._mpu, self._address_parser)
Example #8
0
    def __init__(self, binary):
        Disassembler.__init__(self, binary)
        self.__init_resolver()
        # initial build of graph
        self.__build_graph(self.get_blocks())
        self.__mark_signature_blocks()
        # simplify graph
        self.graph.simplify(self.__signature_blocks, self.resolver)
        # build again because we need the indirect jumps
        self.__build_graph(self.graph.get_blocks())

        self.__create_external_functions()
        self.__create_fallback_function()
Example #9
0
 def getDisassembly(self):
   if hasattr(self, "disassembly"):
     return self.disassembly
   vfile = self.node.open()
   content = vfile.read()
   vfile.close()
   disassembler = Disassembler()
   try:
     self.disassembly = ("%s - " % (self.node.name()) + disassembler.disassemble(content)).split('\n')
   except Exception as e:
     self.stateinfo = e
     self.disassembly = ["Unable to disassemble file: %s" % e] # TODO: do not show the disassembly window
   return self.disassembly
Example #10
0
def main():
    rom_parser = argparse.ArgumentParser(description='NES Disassembler')
    rom_parser.add_argument('rom_path', metavar='ROM', type=str, help='Path to NES ROM.')
    args = rom_parser.parse_args()

    print(args.rom_path)

    # Load the ROM
    with open(args.rom_path, 'rb') as rom:
        rom_hex = rom.read()

    # Create the Disassembler
    disassembler = Disassembler()
    disassembler.process_hex(rom_hex[32768:65536])
Example #11
0
def deobfuscate(codestring):
    # Instructions are stored as a string, we need
    # to convert it to an array of the raw bytes
    insBytes = bytearray(codestring)

    oep = find_oep(insBytes)
    logger.info('Original code entrypoint at {}'.format(oep))

    logger.info('Starting control flow analysis...')
    disasm = Disassembler(insBytes, oep)
    disasm.find_leaders()
    disasm.construct_basic_blocks()
    disasm.build_bb_edges()
    logger.info('Control flow analysis completed.')
    logger.info('Starting simplication of basic blocks...')
    render_graph(disasm.bb_graph, 'before.svg')
    simplifier = Simplifier(disasm.bb_graph)
    simplifier.eliminate_forwarders()
    render_graph(simplifier.bb_graph, 'after_forwarder.svg')
    simplifier.merge_basic_blocks()
    logger.info('Simplification of basic blocks completed.')
    simplified_graph = simplifier.bb_graph
    render_graph(simplified_graph, 'after.svg')
    logger.info('Beginning verification of simplified basic block graph...')

    if not verify_graph(simplified_graph):
        logger.error('Verification failed.')
        raise SystemExit

    logger.info('Verification succeeded.')
    logger.info('Assembling basic blocks...')
    asm = Assembler(simplified_graph)
    codestring = asm.assemble()
    logger.info('Successfully assembled. ')
    return codestring
Example #12
0
def test_disasm(
    addr,
    show_strings = False,
    show_line_addrs = False,
    no_pointer = False,
    cpp_macros = False,
    map_path = "R8PP01.map",
    dump_path = "ram.raw",
    spm = True,
    recursive = False
):
    ctx = DummyConfig(show_strings, show_line_addrs, no_pointer, cpp_macros, map_path, dump_path, spm, recursive)
    dis = Disassembler(ctx)
    return dis.disassemble(addr)
def findOEP(code_object):
    '''
    Finds the original entry point of a code object obfuscated by PjOrion.
    DO NOT call this for a non obfsucated code object.
    
    :param code_object: the code object
    :type code_object: code    
    :returns: the entrypoint
    :rtype: int
    '''
    disassembler = Disassembler(code_object)
    ins = disassembler.disasAt(0)

    try:
        assert utils.insMnemonic(ins) == 'SETUP_EXCEPT'
        except_handler = 0 + ins.arg + ins.size

        assert disassembler.disasAt(3).opkode == -1
        assert utils.insMnemonic(
            disassembler.disasAt(except_handler)) == 'POP_TOP'
        assert utils.insMnemonic(disassembler.disasAt(except_handler +
                                                      1)) == 'POP_TOP'
        assert utils.insMnemonic(disassembler.disasAt(except_handler +
                                                      2)) == 'POP_TOP'
        return except_handler + 3
    except:
        return -1
Example #14
0
 def display_state(self):
     lines = disassembler.disassemble(self.current_block_start, self.mem,
             self.registers[PC] + 10)
     for line in lines:
         addr, insn = line
         text = "%x: %s" % line
         if addr == self.registers[PC]:
             self.display(colored(text, 'green'))
         else:
             self.display(text)
     self.display('')
     for i, r in enumerate(self.registers):
         self.debug_output.write('%s: %04x' % (Disassembler.pretty_reg(i), r))
         if (i + 1) % 4 == 0:
             self.debug_output.write('\n')
         else:
             self.debug_output.write('\t')
     self.display('')
     for reg in self.tracked_registers:
         self.debug_output.write(colored('%s >> ' % Disassembler.pretty_reg(reg), 'blue'))
         self.display_mem(self.registers[reg])
Example #15
0
    def debugRun(source_code, vm):
        #why this runs, its because of the lox interpreter environment, which remains in existence even after this function ends 
        scanner = Scanner(source_code)
        scanner.scanTokens()
        
        print(scanner.toString())
        
        parser = Parser(scanner.token_list)
        parser.parse()

        print("##################################AST###################################")
        print(ASTPrinter().printAll(parser.AST))
        print("########################################################################")
        compiler = Compiler()
        compiler.compileAll(parser.AST)

        disassembler = Disassembler(compiler.chunk)
        print("#############################ByteCode###################################")
        print(disassembler.pretty_print())
        print("########################################################################")

        vm.run(compiler.chunk)
Example #16
0
    def run(source_code, vm):
        #why this runs, its because of the lox interpreter environment, which remains in existence even after this function ends 
        scanner = Scanner(source_code)
        scanner.scanTokens()
        
        parser = Parser(scanner.token_list)
        parser.parse()

        compiler = Compiler()
        compiler.compileAll(parser.AST)

        disassembler = Disassembler(compiler.chunk)
       
        vm.run(compiler.chunk)
def findOEP(code_object):
    '''
    Finds the original entry point of a code object obfuscated by PjOrion.
    DO NOT call this for a non obfsucated code object.
    
    :param code_object: the code object
    :type code_object: code    
    :returns: the entrypoint
    :rtype: int
    '''    
    disassembler = Disassembler(code_object)
    ins = disassembler.disasAt(0)

    try:
        assert utils.insMnemonic(ins) == 'SETUP_EXCEPT'
        except_handler = 0 + ins.arg + ins.size

        assert disassembler.disasAt(3).opkode == -1
        assert utils.insMnemonic(disassembler.disasAt(except_handler)) == 'POP_TOP'
        assert utils.insMnemonic(disassembler.disasAt(except_handler + 1)) == 'POP_TOP'
        assert utils.insMnemonic(disassembler.disasAt(except_handler + 2)) == 'POP_TOP'
        return except_handler + 3
    except:
        return -1
Example #18
0
    def trace(self, pc, name, is_byte_insn, args, m):
        if self.loop_header is not None:
            if self.loop_header == pc:
                self.loop_count += 1
                return
            elif self.loop_header < pc <= self.loop_end:
                return
            else:
                self.tracefile.write('<loop %d times>\n' % self.loop_count)
                self.loop_header = None
                self.loop_count = 0

        if name[0] == 'j' and name != 'jmp' and -0x20 <= args[0] < 0:
            target = args[0] + pc
            simple_loop = True
            for op_pc, op_name in reversed(self.circular_buffer):
                if op_pc == target:
                    break
                if op_name[0] == 'j':
                    simple_loop = False
                    break
            if simple_loop:
                self.loop_header = target
                self.loop_end = pc

        if name[0] != 'j':
            emulated_name, emulated_args = \
                    Disassembler.try_emulate_insn(name, args)
            if is_byte_insn:
                emulated_name += '.b'
            arg_strs = map(Disassembler.pretty_addr, emulated_args)
            values = []
            for i, s in enumerate(arg_strs):
                if s[0] != '#':
                    values.append('%04x (%04x)' %
                            (m.get_addr(args[i], inc=False), m.registers[args[i].loc]))
            arg_str = ", ".join(arg_strs)
            if len(values) > 0:
                arg_str += ' [%s]' % ", ".join(values)
        else:
            emulated_name = name
            arg_str = '$%+x [%04x]' % (args[0], args[0] + pc)

        self.circular_buffer.append((pc, name))

        self.tracefile.write("%04x %s\t%s\n" % (pc,
            emulated_name, arg_str))
Example #19
0
def test():

    from disassembler import Disassembler
    from vm import Vm

    byte_array = Chunk()
    #############################################################
    constant = 100
    byte_array.pushConstant(constant, at_line=1)
    #############################################################

    constant = 200
    byte_array.pushConstant(constant, at_line=1)
    #############################################################

    byte_array.push(OpCode.OP_ADD, at_line=1)
    byte_array.push(OpCode.OP_RETURN, at_line=1)

    print(Disassembler(byte_array).disassemble())

    vm = Vm(byte_array)

    print("vm result ", vm.run())
Example #20
0
class Monitor(cmd.Cmd):

    Microprocessors = {
        '6502': NMOS6502,
        '65C02': CMOS65C02,
        '65Org16': V65Org16
    }

    def __init__(self,
                 argv=None,
                 stdin=None,
                 stdout=None,
                 mpu_type=NMOS6502,
                 memory=None,
                 putc_addr=0xF001,
                 getc_addr=0xF004):
        self.mpu_type = mpu_type
        self.memory = memory
        self.putc_addr = putc_addr
        self.getc_addr = getc_addr
        self._breakpoints = []
        self._width = 78
        self.prompt = "."
        self.quiet_mode = False  # !!lb
        self._add_shortcuts()
        cmd.Cmd.__init__(self, stdin=stdin, stdout=stdout)

        if argv is None:
            argv = sys.argv
        quiet, addr, load, rom, goto = self._parse_args(
            argv)  # !!lb added quiet, addr

        self._reset(self.mpu_type, self.getc_addr, self.putc_addr)

        if quiet is not None:  # !!lb
            self.quiet_mode = quiet

        if load is not None:
            # self.do_load("%r" % load)     # !!lb replaced by following
            if addr is None:
                self.do_load("%r" % load)
            else:
                load_addr = self._address_parser.number(addr)
                self.do_load("%r %x" % (load, load_addr))

        if goto is not None:
            self.do_goto(goto)

        if rom is not None:
            # load a ROM and run from the reset vector
            self.do_load("%r top" % rom)
            physMask = self._mpu.memory.physMask
            reset = self._mpu.RESET & physMask
            dest = self._mpu.memory[reset] + \
                (self._mpu.memory[reset + 1] << self.byteWidth)
            self.do_goto("$%x" % dest)

    def _parse_args(self, argv):
        try:
            shortopts = 'hqa:i:o:m:l:r:g:'  # !!lb added qa:
            longopts = [
                'help',
                'quiet',
                'addr='  # !!lb added quiet, addr=
                'mpu=',
                'input=',
                'output=',
                'load=',
                'rom=',
                'goto='
            ]
            options, args = getopt.getopt(argv[1:], shortopts, longopts)
        except getopt.GetoptError as exc:
            self._output(exc.args[0])
            self._usage()
            self._exit(1)

        quiet, addr, load, rom, goto = None, None, None, None, None  # !!lb added quiet, addr

        for opt, value in options:
            if opt in ('-i', '--input'):
                self.getc_addr = int(value, 16)

            if opt in ('-o', '--output'):
                self.putc_addr = int(value, 16)

            if opt in ('-m', '--mpu'):
                mpu_type = self._get_mpu(value)
                if mpu_type is None:
                    mpus = sorted(self.Microprocessors.keys())
                    msg = "Fatal: no such MPU. Available MPUs: %s"
                    self._output(msg % ', '.join(mpus))
                    sys.exit(1)
                self.mpu_type = mpu_type

            if opt in ("-h", "--help"):
                self._usage()
                self._exit(0)

            if opt in ('-l', '--load'):
                load = value

            if opt in ('-a', '--addr'):  # !!lb
                addr = value

            if opt in ('-r', '--rom'):
                rom = value

            if opt in ('-g', '--goto'):
                goto = value

            if opt in ('-q', '--quiet'):  # !!lb
                quiet = True

        return quiet, addr, load, rom, goto  # !!lb added quiet, addr

    def _usage(self):
        usage = __doc__ % sys.argv[0]
        self._output(usage)

    def onecmd(self, line):
        line = self._preprocess_line(line)

        result = None
        try:
            result = cmd.Cmd.onecmd(self, line)
        except KeyboardInterrupt:
            self._output("Interrupt")
        except Exception:
            (file, fun, line), t, v, tbinfo = compact_traceback()
            error = 'Error: %s, %s: file: %s line: %s' % (t, v, file, line)
            self._output(error)

        if not line.startswith("quit"):
            self._output_mpu_status()

        return result

    def _reset(self, mpu_type, getc_addr=0xF004, putc_addr=0xF001):
        self._mpu = mpu_type(memory=self.memory)
        self.addrWidth = self._mpu.ADDR_WIDTH
        self.byteWidth = self._mpu.BYTE_WIDTH
        self.addrFmt = self._mpu.ADDR_FORMAT
        self.byteFmt = self._mpu.BYTE_FORMAT
        self.addrMask = self._mpu.addrMask
        self.byteMask = self._mpu.byteMask
        if getc_addr and putc_addr:
            self._install_mpu_observers(getc_addr, putc_addr)
        self._address_parser = AddressParser()
        self._disassembler = Disassembler(self._mpu, self._address_parser)
        self._assembler = Assembler(self._mpu, self._address_parser)

    def _add_shortcuts(self):
        self._shortcuts = {
            'EOF': 'quit',
            '~': 'tilde',
            'a': 'assemble',
            'ab': 'add_breakpoint',
            'al': 'add_label',
            'd': 'disassemble',
            'db': 'delete_breakpoint',
            'dl': 'delete_label',
            'exit': 'quit',
            'f': 'fill',
            '>': 'fill',
            'g': 'goto',
            'go': 'go',  # !!lb
            'h': 'help',
            '?': 'help',
            'l': 'load',
            'm': 'mem',
            'q': 'quit',
            'r': 'registers',
            'ret': 'return',
            'rad': 'radix',
            's': 'save',
            'shb': 'show_breakpoints',
            'shl': 'show_labels',
            'x': 'quit',
            'z': 'step'
        }

    def _preprocess_line(self, line):
        # line comments
        quoted = False
        for pos, char in enumerate(line):
            if char in ('"', "'"):
                quoted = not quoted
            if (not quoted) and (char == ';'):
                line = line[:pos]
                break

        # whitespace & leading dots
        line = line.strip(' \t').lstrip('.')

        # special case for vice compatibility
        if line.startswith('~'):
            line = self._shortcuts['~'] + ' ' + line[1:]

        # command shortcuts
        for shortcut, command in self._shortcuts.items():
            if line == shortcut:
                line = command
                break

            pattern = '^%s\s+' % re.escape(shortcut)
            matches = re.match(pattern, line)
            if matches:
                start, end = matches.span()
                line = "%s %s" % (command, line[end:])
                break

        return line

    def _get_mpu(self, name):
        requested = name.lower()
        mpu = None
        for key, klass in self.Microprocessors.items():
            if key.lower() == requested:
                mpu = klass
                break
        return mpu

    def _install_mpu_observers(self, getc_addr, putc_addr):
        def putc(address, value):
            try:
                self.stdout.write(chr(value))
            except UnicodeEncodeError:  # Python 3
                self.stdout.write("?")
            self.stdout.flush()

        def getc(address):
            char = console.getch_noblock(self.stdin)
            if char:
                byte = ord(char)
            else:
                byte = 0
            return byte

        m = ObservableMemory(subject=self.memory, addrWidth=self.addrWidth)
        m.subscribe_to_write([self.putc_addr], putc)
        m.subscribe_to_read([self.getc_addr], getc)

        self._mpu.memory = m

    def _output_mpu_status(self):
        self._output("\n" + repr(self._mpu))

    def _output(self, stuff):
        self.stdout.write("%s\n" % stuff)

    def _exit(self, exitcode=0):
        sys.exit(exitcode)

    def do_help(self, args):
        args = self._shortcuts.get(args.strip(), args)
        return cmd.Cmd.do_help(self, args)

    def help_version(self):
        self._output("version\t\tDisplay Py65 version information.")

    def do_version(self, args):
        self._output("\nPy65 Monitor")
        self._output("(Reformed Devs Code Golf 2019.06 edition)")  # !!lb

    def help_help(self):
        self._output("help\t\tPrint a list of available actions.")
        self._output("help <action>\tPrint help for <action>.")

    def help_reset(self):
        self._output("reset\t\tReset the microprocessor")

    def do_reset(self, args):
        klass = self._mpu.__class__
        self._reset(mpu_type=klass)

    def do_mpu(self, args):
        def available_mpus():
            mpus = list(self.Microprocessors.keys())
            mpus.sort()
            self._output("Available MPUs: %s" % ', '.join(mpus))

        if args == '':
            self._output("Current MPU is %s" % self._mpu.name)
            available_mpus()
        else:
            new_mpu = self._get_mpu(args)
            if new_mpu is None:
                self._output("Unknown MPU: %s" % args)
                available_mpus()
            else:
                self._reset(new_mpu, self.getc_addr, self.putc_addr)
                self._output("Reset with new MPU %s" % self._mpu.name)

    def help_mpu(self):
        self._output("mpu\t\tPrint available microprocessors.")
        self._output("mpu <type>\tSelect a new microprocessor.")

    def do_quit(self, args):
        self._output('')
        return 1

    def help_quit(self):
        self._output("To quit, type ^D or use the quit command.")

    def do_assemble(self, args):
        splitted = args.split(None, 1)
        if len(splitted) != 2:
            return self._interactive_assemble(args)

        statement = splitted[1]
        try:
            start = self._address_parser.number(splitted[0])
            bytes = self._assembler.assemble(statement, start)
            end = start + len(bytes)
            self._mpu.memory[start:end] = bytes
            self.do_disassemble(self.addrFmt % start)
        except KeyError as exc:
            self._output(exc.args[0])  # "Label not found: foo"
        except OverflowError:
            self._output("Overflow error: %s" % args)
        except SyntaxError:
            self._output("Syntax error: %s" % statement)

    def help_assemble(self):
        self._output("assemble\t\t\t"
                     "Start interactive assembly at the program counter.")
        self._output("assemble <address>\t\t"
                     "Start interactive assembly at the address.")
        self._output("assemble <address> <statement>\t"
                     "Assemble a statement at the address.")

    def _interactive_assemble(self, args):
        if args == '':
            start = self._mpu.pc
        else:
            try:
                start = self._address_parser.number(args)
            except KeyError as exc:
                self._output(exc.args[0])  # "Label not found: foo"
                return

        while True:
            prompt = "\r$" + (self.addrFmt % start) + "   " + \
                (" " * int(1 + self.byteWidth / 4) * 3)

            line = console.line_input(prompt,
                                      stdin=self.stdin,
                                      stdout=self.stdout)

            if not line.strip():
                self.stdout.write("\n")
                return

            # assemble into memory
            try:
                bytes = self._assembler.assemble(line, pc=start)
                numbytes = len(bytes)

                end = start + numbytes
                self._mpu.memory[start:end] = bytes

                # print disassembly
                _, disasm = self._disassembler.instruction_at(start)
                fdisasm = self._format_disassembly(start, numbytes, disasm)
                indent = ' ' * (len(prompt + line) + 5)
                self.stdout.write("\r" + indent + "\r")
                self.stdout.write(fdisasm + "\n")

                # advance to next address
                start += numbytes
                if start >= (2**self._mpu.ADDR_WIDTH):
                    start = 0
            except KeyError:
                addr = self.addrFmt % start
                self.stdout.write("\r$%s  ?Label\n" % addr)
            except OverflowError:
                addr = self.addrFmt % start
                self.stdout.write("\r$%s  ?Overflow\n" % addr)
            except SyntaxError:
                addr = self.addrFmt % start
                self.stdout.write("\r$%s  ?Syntax\n" % addr)

    def do_disassemble(self, args):
        splitted = shlex.split(args)
        if len(splitted) != 1:
            return self.help_disassemble()

        address_parts = splitted[0].split(":")
        start = self._address_parser.number(address_parts[0])
        if len(address_parts) > 1:
            end = self._address_parser.number(address_parts[1])
        else:
            end = start

        max_address = (2**self._mpu.ADDR_WIDTH) - 1
        cur_address = start
        needs_wrap = start > end

        while needs_wrap or cur_address <= end:
            length, disasm = self._disassembler.instruction_at(cur_address)
            self._output(self._format_disassembly(cur_address, length, disasm))

            remaining = length
            while remaining:
                remaining -= 1
                cur_address += 1
                if start > end and cur_address > max_address:
                    needs_wrap = False
                    cur_address = 0

    def _format_disassembly(self, address, length, disasm):
        cur_address = address
        max_address = (2**self._mpu.ADDR_WIDTH) - 1

        bytes_remaining = length
        dump = ''

        while bytes_remaining:
            if cur_address > max_address:
                cur_address = 0
            dump += self.byteFmt % self._mpu.memory[cur_address] + " "
            cur_address += 1
            bytes_remaining -= 1

        fieldwidth = 1 + int(1 + self.byteWidth / 4) * 3
        fieldfmt = "%%-%ds" % fieldwidth
        return "$" + self.addrFmt % address + "  " + fieldfmt % dump + disasm

    def help_disassemble(self):
        self._output("disassemble <address_range>")
        self._output("Disassemble instructions in the address range.")
        self._output('Range is specified like "<start>:<end>".')

    def help_step(self):
        self._output("step")
        self._output("Single-step through instructions.")

    def do_step(self, args):
        self._mpu.step()
        self.do_disassemble(self.addrFmt % self._mpu.pc)

    def help_return(self):
        self._output("return")
        self._output("Continues execution and returns to the monitor just")
        self._output("before the next RTS or RTI is executed.")

    def do_return(self, args):
        returns = [0x60, 0x40]  # RTS, RTI
        self._run(stopcodes=returns)

    def help_goto(self):
        self._output("goto <address>")
        self._output("Change the PC to address and continue execution.")

    def do_goto(self, args):
        if args == '':
            return self.help_goto()

        self._mpu.pc = self._address_parser.number(args)
        brks = [0x00]  # BRK
        self._run(stopcodes=brks)

    def help_go(self):  # !!lb
        self._output("go")
        self._output("Continue execution.")

    def do_go(self, args):  # !!lb
        brks = [0x00]  # BRK
        self._run(stopcodes=brks)

    def _run(self, stopcodes):
        stopcodes = set(stopcodes)
        breakpoints = set(self._breakpoints)
        mpu = self._mpu
        mem = self._mpu.memory

        if not breakpoints:
            while True:
                mpu.step()
                if mem[mpu.pc] in stopcodes:
                    break
        else:
            while True:
                mpu.step()
                pc = mpu.pc
                if mem[pc] in stopcodes:
                    break
                if pc in breakpoints:
                    msg = "Breakpoint %d reached."
                    self._output(msg % self._breakpoints.index(pc))
                    break

    def help_radix(self):
        self._output("radix [H|D|O|B]")
        self._output("Set default radix to hex, decimal, octal, or binary.")
        self._output("With no argument, the current radix is printed.")

    def help_cycles(self):
        self._output("Display the total number of cycles executed.")

    def do_cycles(self, args):
        self._output(str(self._mpu.processorCycles))

    def do_radix(self, args):
        radixes = {'Hexadecimal': 16, 'Decimal': 10, 'Octal': 8, 'Binary': 2}

        if args != '':
            new = args[0].lower()
            changed = False
            for name, radix in radixes.items():
                if name[0].lower() == new:
                    self._address_parser.radix = radix
                    changed = True
            if not changed:
                self._output("Illegal radix: %s" % args)

        for name, radix in radixes.items():
            if self._address_parser.radix == radix:
                self._output("Default radix is %s" % name)

    def help_tilde(self):
        self._output("~ <number>")
        self._output("Display a number in decimal, hex, octal, and binary.")

    def do_tilde(self, args):
        if args == '':
            return self.help_tilde()

        try:
            num = self._address_parser.number(args)
            self._output("+%u" % num)
            self._output("$" + self.byteFmt % num)
            self._output("%04o" % num)
            self._output(itoa(num, 2).zfill(8))
        except KeyError:
            self._output("Bad label: %s" % args)
        except OverflowError:
            self._output("Overflow error: %s" % args)

    def help_registers(self):
        self._output("registers[<name>=<value> [, <name>=<value>]*]")
        self._output("Assign respective registers.  With no parameters,")
        self._output("display register values.")

    def do_registers(self, args):
        if args == '':
            return

        pairs = re.findall('([^=,\s]*)=([^=,\s]*)', args)
        if pairs == []:
            return self._output("Syntax error: %s" % args)

        for register, value in pairs:
            if register not in ('pc', 'sp', 'a', 'x', 'y', 'p'):
                self._output("Invalid register: %s" % register)
            else:
                try:
                    intval = self._address_parser.number(value)
                except KeyError as exc:  # label not found
                    self._output(exc.args[0])
                    continue
                except OverflowError as exc:  # wider than address space
                    msg = "Overflow: %r too wide for register %r"
                    self._output(msg % (value, register))
                    continue

                if register != 'pc':
                    if intval != (intval & self.byteMask):
                        msg = "Overflow: %r too wide for register %r"
                        self._output(msg % (value, register))
                        continue

                setattr(self._mpu, register, intval)

    def help_cd(self):
        self._output("cd <directory>")
        self._output("Change the working directory.")

    def do_cd(self, args):
        if args == '':
            return self.help_cd()

        try:
            os.chdir(args)
        except OSError as exc:
            msg = "Cannot change directory: [%d] %s" % (exc.errno,
                                                        exc.strerror)
            self._output(msg)
        self.do_pwd()

    def help_pwd(self):
        self._output("Show the current working directory.")

    def do_pwd(self, args=None):
        cwd = os.getcwd()
        self._output(cwd)

    def help_load(self):
        self._output("load <filename|url> <address|top>")
        self._output("Load a file into memory at the specified address.")
        self._output('An address of "top" loads into the top of memory.')
        self._output("Commodore-style load address bytes are ignored.")

    def do_load(self, args):
        split = shlex.split(args)
        if len(split) not in (1, 2):
            self._output("Syntax error: %s" % args)
            return

        filename = split[0]

        if "://" in filename:
            try:
                f = urlopen(filename)
                bytes = f.read()
                f.close()
            except Exception as exc:
                msg = "Cannot fetch remote file: %s" % str(exc)
                self._output(msg)
                return
        else:
            try:
                f = open(filename, 'rb')
                bytes = f.read()
                f.close()
            except (OSError, IOError) as exc:
                msg = "Cannot load file: [%d] %s" % (exc.errno, exc.strerror)
                self._output(msg)
                return

        if len(split) == 2:
            if split[1] == "top":
                # load a ROM to top of memory
                top_address = self.addrMask
                program_size = len(bytes) // (self.byteWidth // 8)
                start = top_address - program_size + 1
            else:
                start = self._address_parser.number(split[1])
        else:
            start = self._mpu.pc

        if self.byteWidth == 8:
            if isinstance(bytes, str):
                bytes = map(ord, bytes)
            else:  # Python 3
                bytes = [b for b in bytes]

        elif self.byteWidth == 16:

            def format(msb, lsb):
                if isinstance(bytes, str):
                    return (ord(msb) << 8) + ord(lsb)
                else:  # Python 3
                    return (msb << 8) + lsb

            bytes = list(map(format, bytes[0::2], bytes[1::2]))

        self._fill(start, start, bytes)

    def help_save(self):
        self._output("save \"filename\" <start> <end>")
        self._output("Save the specified memory range as a binary file.")
        self._output("Commodore-style load address bytes are not written.")

    def do_save(self, args):
        split = shlex.split(args)
        if len(split) != 3:
            self._output("Syntax error: %s" % args)
            return

        filename = split[0]
        start = self._address_parser.number(split[1])
        end = self._address_parser.number(split[2])

        mem = self._mpu.memory[start:end + 1]
        try:
            f = open(filename, 'wb')
            for m in mem:
                # output each octect from msb first
                for shift in range(self.byteWidth - 8, -1, -8):
                    f.write(bytearray([(m >> shift) & 0xff]))
            f.close()
        except (OSError, IOError) as exc:
            msg = "Cannot save file: [%d] %s" % (exc.errno, exc.strerror)
            self._output(msg)
            return

        self._output("Saved +%d bytes to %s" % (len(mem), filename))

    def help_fill(self):
        self._output("fill <address_range> <data_list>")
        self._output("Fill memory in the address range with the data in")
        self._output("<data_list>.  If the size of the address range is")
        self._output("greater than the size of the data_list, the data_list ")
        self._output("is repeated.")

    def do_fill(self, args):
        split = shlex.split(args)
        if len(split) < 2:
            return self.help_fill()

        try:
            start, end = self._address_parser.range(split[0])
            filler = list(map(self._address_parser.number, split[1:]))
        except KeyError as exc:
            self._output(exc.args[0])  # "Label not found: foo"
        else:
            self._fill(start, end, filler)

    def _fill(self, start, end, filler):
        address = start
        length, index = len(filler), 0

        if start == end:
            end = start + length - 1
            if (end > self.addrMask):
                end = self.addrMask

        while address <= end:
            address &= self.addrMask
            self._mpu.memory[address] = (filler[index] & self.byteMask)
            index += 1
            if index == length:
                index = 0
            address += 1

        if not self.quiet_mode:  # !!lb
            fmt = (end - start + 1, start, end)
            starttoend = "$" + self.addrFmt + " to $" + self.addrFmt
            self._output(("Wrote +%d bytes from " + starttoend) % fmt)

    def help_mem(self):
        self._output("mem <address_range>")
        self._output("Display the contents of memory.")
        self._output('Range is specified like "<start:end>".')

    def do_mem(self, args):
        split = shlex.split(args)
        if len(split) != 1:
            return self.help_mem()

        start, end = self._address_parser.range(split[0])

        line = self.addrFmt % start + ":"
        for address in range(start, end + 1):
            byte = self._mpu.memory[address]
            more = "  " + self.byteFmt % byte

            exceeded = len(line) + len(more) > self._width
            if exceeded:
                self._output(line)
                line = self.addrFmt % address + ":"
            line += more
        self._output(line)

    def help_add_label(self):
        self._output("add_label <address> <label>")
        self._output("Map a given address to a label.")

    def do_add_label(self, args):
        split = shlex.split(args)
        if len(split) != 2:
            self._output("Syntax error: %s" % args)
            return self.help_add_label()

        try:
            address = self._address_parser.number(split[0])
        except KeyError as exc:
            self._output(exc.args[0])  # "Label not found: foo"
        except OverflowError:
            self._output("Overflow error: %s" % args)
        else:
            label = split[1]
            self._address_parser.labels[label] = address

    def help_show_labels(self):
        self._output("show_labels")
        self._output("Display current label mappings.")

    def do_show_labels(self, args):
        values = list(self._address_parser.labels.values())
        keys = list(self._address_parser.labels.keys())

        byaddress = list(zip(values, keys))
        byaddress.sort()
        for address, label in byaddress:
            self._output(self.addrFmt % address + ": " + label)

    def help_delete_label(self):
        self._output("delete_label <label>")
        self._output("Remove the specified label from the label tables.")

    def do_delete_label(self, args):
        if args == '':
            return self.help_delete_label()

        if args in self._address_parser.labels:
            del self._address_parser.labels[args]

    def do_width(self, args):
        if args != '':
            try:
                new_width = int(args)
                if new_width >= 10:
                    self._width = new_width
                else:
                    self._output("Minimum terminal width is 10")
            except ValueError:
                self._output("Illegal width: %s" % args)

        self._output("Terminal width is %d" % self._width)

    def help_width(self):
        self._output("width <columns>")
        self._output("Set the width used by some commands to wrap output.")
        self._output("With no argument, the current width is printed.")

    def do_add_breakpoint(self, args):
        split = shlex.split(args)
        if len(split) != 1:
            self._output("Syntax error: %s" % args)
            return self.help_add_breakpoint()

        address = self._address_parser.number(split[0])

        if address in self._breakpoints:
            self._output("Breakpoint already present at $%04X" % address)
        else:
            self._breakpoints.append(address)
            msg = "Breakpoint %d added at $%04X"
            self._output(msg % (len(self._breakpoints) - 1, address))

    def help_add_breakpoint(self):
        self._output("add_breakpoint <address|label>")
        self._output(
            "Add a breakpoint on execution at the given address or label")

    def do_delete_breakpoint(self, args):
        split = shlex.split(args)
        if len(split) != 1:
            self._output("Syntax error: %s" % args)
            return self.help_delete_breakpoint()

        number = None
        try:
            number = int(split[0])
            if number < 0 or number > len(self._breakpoints):
                self._output("Invalid breakpoint number %d", number)
                return
        except ValueError:
            self._output("Illegal number: %s" % args)
            return

        if self._breakpoints[number] is not None:
            self._breakpoints[number] = None
            self._output("Breakpoint %d removed" % number)
        else:
            self._output("Breakpoint %d already removed" % number)

    def help_delete_breakpoint(self):
        self._output("delete_breakpoint <number>")
        self._output(
            "Delete the breakpoint on execution marked by the given number")

    def do_show_breakpoints(self, args):
        for i, address in enumerate(self._breakpoints):
            if address is not None:
                bpinfo = "Breakpoint %d: $%04X" % (i, address)
                label = self._address_parser.label_for(address)
                if label is not None:
                    bpinfo += " " + label
                self._output(bpinfo)

    def help_show_breakpoints(self):
        self._output("show_breakpoints")
        self._output("Lists the currently assigned breakpoints")
Example #21
0
def dasm():
    return Disassembler()
Example #22
0
    def execute_next(self):
        cpuoff = self.registers[SR] & (1 << 4)
        if cpuoff:
            self.display('<CPUOFF bit set. Exiting.>')
        if cpuoff or self.door_unlocked:
            self.display('<Executed %d instructions.>' % self.insn_count)
            return False
        pc = self.registers[PC]

        self.insn_count += 1
        step_count = self.step_count
        if self.step_count > 0:
            self.step_count -= 1

        should_break = self.should_break(pc)
        if should_break:
            if self.breakpoints[pc] == 1: # -1 is a permanent breakpoint
                del self.breakpoints[pc]
                if pc in self.breakpoint_conditions:
                    del self.breakpoint_conditions[pc]
            elif self.breakpoints > 1:
                self.breakpoints[pc] -= 1

        if should_break or step_count == 1:
            self.handle_cmds()
        pc = self.registers[PC] # in case of reset

        is_ret = False
        is_call = False
        if pc == 0x10:
            self.handle_callgate(self.registers[SR])
            self.mem[0x10] = 0x4130 # ret

        handler, is_byte_insn, args, size = self.decoder.decode(pc, self.mem)
        self.operand_bytes = 1 if is_byte_insn else 2

        if handler is None:
            raise Exception('Failed to decode instruction at pc %x.' % pc)

        name = handler.__name__[3:]
        self.next_pc = pc + size
        self.registers[PC] += 2

        if not self.peephole_execute(name, is_byte_insn, args, size):
            if self.trace is not None:
                self.trace(pc, name, is_byte_insn, args, self)

            handler(*args)

        is_ret = Disassembler.is_ret(name, args)
        is_call = name == 'call'

        if self.registers[PC] == pc + 2:
            self.registers[PC] = self.next_pc
        else:
            self.current_block_start = self.registers[PC]
            if self.break_at_finish >= 0:
                if is_ret:
                    self.break_at_finish -= 1
                    if self.break_at_finish == -1:
                        self.step_count = 1
                elif is_call:
                    self.break_at_finish += 1

            if is_call:
                self.callsites.append(pc)
                self.call_targets.append(self.registers[PC])
            elif is_ret:
                self.callsites.pop()
                self.call_targets.pop()

        return True
Example #23
0
#!/usr/bin/python
import argparse

from disassembler import Disassembler
from disassembly_writer import DisassemblyWriter

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Chip-8 disassembler using traversal tree algorithm.")
    parser.add_argument("romfile", help="The rom filename to load")
    args = parser.parse_args()

    dasm = Disassembler(args.romfile)
    dasm.decode(0x200)

    writer = DisassemblyWriter(args.romfile, dasm.labels, dasm.disassembly)
    writer.create_disassembly()
Example #24
0
def main():
    ctx = Config()
    dis = Disassembler(ctx)
    txt = dis.disassemble(ctx.addr)
    stdout.buffer.write(txt.encode("utf8")) # TODO: is there a better way to fix this?
Example #25
0
import sys
from disassembler import Disassembler
import os

disassembler = Disassembler()
disassembler.run()
disassembler.print()

Example #26
0
        # Assemble file.
        handler.assemble()

    elif args.disassemble:

        # Check to see if a start address was added.
        if args.startaddr:

            # Check to see if the address is valid.
            intval = int(args.startaddr, 16)

            if intval < 1 or intval > 65535:
                raise ValueError

        # Set up disassembler.
        handler = Disassembler(infile, outfile, intval, args.counter,
                               args.program)

        # Disassemble file.
        handler.disassemble()

    elif args.execute or args.debug:

        # Check to see if a start address was added.
        if args.startaddr:

            # Check to see if the address is valid.
            intval = int(args.startaddr, 16)

            if intval < 1 or intval > 65535:
                raise ValueError
Example #27
0
import argparse

from rom import ROM
from disassembler import Disassembler
from instrumentation import processInstrumentation
from annotation import simple
from annotation import sdcc

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("rom", type=str)
    parser.add_argument("--instrumentation", action='append', default=[])
    parser.add_argument("--source")
    parser.add_argument("--output", type=str, required=True)
    parser.add_argument("--plugin", action='append', default=[])
    args = parser.parse_args()

    for plugin in args.plugin:
        exec(open(plugin, "rt").read())

    rom = ROM(args.rom)
    disassembler = Disassembler(rom)
    disassembler.readSources(args.source if args.source else args.output)
    for instrumentation_file in args.instrumentation:
        processInstrumentation(instrumentation_file)
    disassembler.processRom()
    disassembler.export(args.output)
Example #28
0
def run_dasm(memory):
    memory_size = len(memory.ram)
    dasm = Disassembler(memory)

    for _ in range(0, memory_size):
        dasm.disassembly()
Example #29
0
from helper import open_as_byte_array
from disassembler import Disassembler
from cpu import CPU65816
from graphics import PictureProcessingUnit
from memory import MemoryMapper
import sys

if len(sys.argv) <= 1:
    print("usage: python PySNES.py ROM_PATH [start] [end]")
    exit(0)

ROM = open_as_byte_array(sys.argv[1])
#print_hex_dump(ba)[0:32]
header = ROMHeader(ROM)
header.dump()
d = Disassembler()
RAM = [0] * (2**17 - 1)  # 128 KB
SRAM = [0] * 0x7FFF  # 32 KB

memory = MemoryMapper(header, RAM, ROM, SRAM, False, 0x7FFF)
c = CPU65816(memory)
ppu = PictureProcessingUnit()
ppu.init()
while True:
    instr_str = d.disassemble_single_opcode(memory,
                                            c.PC,
                                            add_new_line=False,
                                            add_descr=False,
                                            add_addr=False,
                                            M=c.isM(),
                                            X=c.isX())