diff options
| author | Peter LaFosse <peter@vector35.com> | 2022-02-17 13:53:57 -0500 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2022-02-17 13:56:14 -0500 |
| commit | 3c20567d78c534b6e20eb7e8a31ef06a21a4b157 (patch) | |
| tree | 2846c56192e50bdf83df3fefd6f4a1402c7ea44c /python | |
| parent | 159bda74c5b5b8e7c1898cbe707d90e01cb09101 (diff) | |
Add some additional function.py unit tests
Diffstat (limited to 'python')
| -rw-r--r-- | python/examples/nes.py | 934 |
1 files changed, 471 insertions, 463 deletions
diff --git a/python/examples/nes.py b/python/examples/nes.py index 7c7857a4..913ad8dc 100644 --- a/python/examples/nes.py +++ b/python/examples/nes.py @@ -21,10 +21,10 @@ import struct import traceback import os -from typing import Callable, List, Any +from typing import Callable, List, Type, Optional, Dict, Tuple, NewType -from binaryninja.architecture import Architecture, InstructionInfo, RegisterInfo, RegisterName -from binaryninja.lowlevelil import LowLevelILLabel, LLIL_TEMP +from binaryninja.architecture import Architecture, InstructionInfo, RegisterInfo, RegisterName, FlagName, FlagWriteTypeName, FlagType +from binaryninja.lowlevelil import LowLevelILLabel, LLIL_TEMP, ExpressionIndex, LowLevelILFunction, ILRegisterType, LowLevelILConst, LowLevelILInstruction from binaryninja.function import InstructionTextToken from binaryninja.binaryview import BinaryView from binaryninja.types import Symbol @@ -33,397 +33,44 @@ from binaryninja.enums import ( BranchType, InstructionTextTokenType, LowLevelILOperation, LowLevelILFlagCondition, FlagRole, SegmentFlag, SymbolType ) -InstructionNames = [ - "brk", "ora", None, None, None, "ora", "asl", None, # 0x00 - "php", "ora", "asl@", None, None, "ora", "asl", None, # 0x08 - "bpl", "ora", None, None, None, "ora", "asl", None, # 0x10 - "clc", "ora", None, None, None, "ora", "asl", None, # 0x18 - "jsr", "and", None, None, "bit", "and", "rol", None, # 0x20 - "plp", "and", "rol@", None, "bit", "and", "rol", None, # 0x28 - "bmi", "and", None, None, None, "and", "rol", None, # 0x30 - "sec", "and", None, None, None, "and", "rol", None, # 0x38 - "rti", "eor", None, None, None, "eor", "lsr", None, # 0x40 - "pha", "eor", "lsr@", None, "jmp", "eor", "lsr", None, # 0x48 - "bvc", "eor", None, None, None, "eor", "lsr", None, # 0x50 - "cli", "eor", None, None, None, "eor", "lsr", None, # 0x58 - "rts", "adc", None, None, None, "adc", "ror", None, # 0x60 - "pla", "adc", "ror@", None, "jmp", "adc", "ror", None, # 0x68 - "bvs", "adc", None, None, None, "adc", "ror", None, # 0x70 - "sei", "adc", None, None, None, "adc", "ror", None, # 0x78 - None, "sta", None, None, "sty", "sta", "stx", None, # 0x80 - "dey", None, "txa", None, "sty", "sta", "stx", None, # 0x88 - "bcc", "sta", None, None, "sty", "sta", "stx", None, # 0x90 - "tya", "sta", "txs", None, None, "sta", None, None, # 0x98 - "ldy", "lda", "ldx", None, "ldy", "lda", "ldx", None, # 0xa0 - "tay", "lda", "tax", None, "ldy", "lda", "ldx", None, # 0xa8 - "bcs", "lda", None, None, "ldy", "lda", "ldx", None, # 0xb0 - "clv", "lda", "tsx", None, "ldy", "lda", "ldx", None, # 0xb8 - "cpy", "cmp", None, None, "cpy", "cmp", "dec", None, # 0xc0 - "iny", "cmp", "dex", None, "cpy", "cmp", "dec", None, # 0xc8 - "bne", "cmp", None, None, None, "cmp", "dec", None, # 0xd0 - "cld", "cmp", None, None, None, "cmp", "dec", None, # 0xd8 - "cpx", "sbc", None, None, "cpx", "sbc", "inc", None, # 0xe0 - "inx", "sbc", "nop", None, "cpx", "sbc", "inc", None, # 0xe8 - "beq", "sbc", None, None, None, "sbc", "inc", None, # 0xf0 - "sed", "sbc", None, None, None, "sbc", "inc", None # 0xf8 -] +Mnemonic = NewType('Mnemonic', str) +Operand = NewType('Operand', int) -NONE = 0 -ABS = 1 -ABS_DEST = 2 -ABS_X = 3 -ABS_X_DEST = 4 -ABS_Y = 5 -ABS_Y_DEST = 6 -ACCUM = 7 -ADDR = 8 -IMMED = 9 -IND = 10 -IND_X = 11 -IND_X_DEST = 12 -IND_Y = 13 -IND_Y_DEST = 14 -REL = 15 -ZERO = 16 -ZERO_DEST = 17 -ZERO_X = 18 -ZERO_X_DEST = 19 -ZERO_Y = 20 -ZERO_Y_DEST = 21 -InstructionOperandTypes = [ - NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x00 - NONE, IMMED, ACCUM, NONE, NONE, ABS, ABS_DEST, NONE, # 0x08 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x10 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x18 - ADDR, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0x20 - NONE, IMMED, ACCUM, NONE, ABS, ABS, ABS_DEST, NONE, # 0x28 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x30 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x38 - NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x40 - NONE, IMMED, ACCUM, NONE, ADDR, ABS, ABS_DEST, NONE, # 0x48 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x50 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x58 - NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x60 - NONE, IMMED, ACCUM, NONE, IND, ABS, ABS_DEST, NONE, # 0x68 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x70 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x78 - NONE, IND_X_DEST, NONE, NONE, ZERO_DEST, ZERO_DEST, ZERO_DEST, NONE, # 0x80 - NONE, NONE, NONE, NONE, ABS_DEST, ABS_DEST, ABS_DEST, NONE, # 0x88 - REL, IND_Y_DEST, NONE, NONE, ZERO_X_DEST, ZERO_X_DEST, ZERO_Y_DEST, NONE, # 0x90 - NONE, ABS_Y_DEST, NONE, NONE, NONE, ABS_X_DEST, NONE, NONE, # 0x98 - IMMED, IND_X, IMMED, NONE, ZERO, ZERO, ZERO, NONE, # 0xa0 - NONE, IMMED, NONE, NONE, ABS, ABS, ABS, NONE, # 0xa8 - REL, IND_Y, NONE, NONE, ZERO_X, ZERO_X, ZERO_Y, NONE, # 0xb0 - NONE, ABS_Y, NONE, NONE, ABS_X, ABS_X, ABS_Y, NONE, # 0xb8 - IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xc0 - NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xc8 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xd0 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0xd8 - IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xe0 - NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xe8 - REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xf0 - NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE # 0xf8 -] +NONE = Operand(0) +ABS = Operand(1) +ABS_DEST = Operand(2) +ABS_X = Operand(3) +ABS_X_DEST = Operand(4) +ABS_Y = Operand(5) +ABS_Y_DEST = Operand(6) +ACCUM = Operand(7) +ADDR = Operand(8) +IMMED = Operand(9) +IND = Operand(10) +IND_X = Operand(11) +IND_X_DEST = Operand(12) +IND_Y = Operand(13) +IND_Y_DEST = Operand(14) +REL = Operand(15) +ZERO = Operand(16) +ZERO_DEST = Operand(17) +ZERO_X = Operand(18) +ZERO_X_DEST = Operand(19) +ZERO_Y = Operand(20) +ZERO_Y_DEST = Operand(21) -OperandLengths = [ - 0, # NONE - 2, # ABS - 2, # ABS_DEST - 2, # ABS_X - 2, # ABS_X_DEST - 2, # ABS_Y - 2, # ABS_Y_DEST - 0, # ACCUM - 2, # ADDR - 1, # IMMED - 2, # IND - 1, # IND_X - 1, # IND_X_DEST - 1, # IND_Y - 1, # IND_Y_DEST - 1, # REL - 1, # ZERO - 1, # ZERO_DEST - 1, # ZERO_X - 1, # ZERO_X_DEST - 1, # ZERO_Y - 1 # ZERO_Y_DEST -] -OperandTokens: List[Callable[[int], List[InstructionTextToken]]] = [ - lambda value: [], # NONE - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ABS - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value) - ], # ABS_DEST - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") - ], # ABS_X - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") - ], # ABS_X_DEST - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ], # ABS_Y - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ], # ABS_Y_DEST - lambda value: [InstructionTextToken(InstructionTextTokenType.RegisterToken, "a")], # ACCUM - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ADDR - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "#"), - InstructionTextToken(InstructionTextTokenType.IntegerToken, "$%.2x" % value, value) - ], # IMMED - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "["), - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, "]") - ], # IND - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "["), - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"), - InstructionTextToken(InstructionTextTokenType.TextToken, "]") - ], # IND_X - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "["), - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"), - InstructionTextToken(InstructionTextTokenType.TextToken, "]") - ], # IND_X_DEST - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "["), - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, "], "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ], # IND_Y - lambda value: [ - InstructionTextToken(InstructionTextTokenType.TextToken, "["), - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, "], "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ], # IND_Y_DEST - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # REL - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value)], # ZERO - lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value) - ], # ZERO_DEST - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") - ], # ZERO_X - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") - ], # ZERO_X_DEST - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ], # ZERO_Y - lambda value: [ - InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), - InstructionTextToken(InstructionTextTokenType.TextToken, ", "), - InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") - ] # ZERO_Y_DEST -] - - -def indirect_load(il, value): - if (value & 0xff) == 0xff: - lo_addr = il.const_pointer(2, value) - hi_addr = il.const_pointer(2, (value & 0xff00) | ((value + 1) & 0xff)) - lo = il.zero_extend(2, il.load(1, lo_addr)) - hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8)) - return il.or_expr(2, lo, hi) - return il.load(2, il.const_pointer(2, value)) - - -def load_zero_page_16(il, value): - if il[value].operation == LowLevelILOperation.LLIL_CONST: - if il[value].constant == 0xff: - lo = il.zero_extend(2, il.load(1, il.const_pointer(2, 0xff))) - hi = il.shift_left(2, il.zero_extend(2, il.load(1, il.const_pointer(2, 0)), il.const(2, 8))) - return il.or_expr(2, lo, hi) - return il.load(2, il.const_pointer(2, il[value].constant)) - il.append(il.set_reg(1, LLIL_TEMP(0), value)) - value = il.reg(1, LLIL_TEMP(0)) - lo_addr = value - hi_addr = il.add(1, value, il.const(1, 1)) - lo = il.zero_extend(2, il.load(1, lo_addr)) - hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8)) - return il.or_expr(2, lo, hi) - - -OperandIL = [ - lambda il, value: None, # NONE - lambda il, value: il.load(1, il.const_pointer(2, value)), # ABS - lambda il, value: il.const(2, value), # ABS_DEST - lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x")))), # ABS_X - lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "x"))), # ABS_X_DEST - lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y")))), # ABS_Y - lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, "y"))), # ABS_Y_DEST - lambda il, value: il.reg(1, "a"), # ACCUM - lambda il, value: il.const_pointer(2, value), # ADDR - lambda il, value: il.const(1, value), # IMMED - lambda il, value: indirect_load(il, value), # IND - lambda il, value: il.load(1, load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x")))), # IND_X - lambda il, value: load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, "x"))), # IND_X_DEST - lambda il, value: il.load(1, il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y"))), # IND_Y - lambda il, value: il.add(2, load_zero_page_16(il, il.const(1, value)), il.reg(1, "y")), # IND_Y_DEST - lambda il, value: il.const_pointer(2, value), # REL - lambda il, value: il.load(1, il.const_pointer(2, value)), # ZERO - lambda il, value: il.const_pointer(2, value), # ZERO_DEST - lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x")))), # ZERO_X - lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "x"))), # ZERO_X_DEST - lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y")))), # ZERO_Y - lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, "y"))) # ZERO_Y_DEST -] - - -def cond_branch(il, cond, dest): - t = None - if il[dest].operation == LowLevelILOperation.LLIL_CONST: - t = il.get_label_for_address(Architecture['6502'], il[dest].constant) # type: ignore - if t is None: - t = LowLevelILLabel() - indirect = True - else: - indirect = False - f = LowLevelILLabel() - il.append(il.if_expr(cond, t, f)) - if indirect: - il.mark_label(t) - il.append(il.jump(dest)) - il.mark_label(f) - return None - - -def jump(il, dest): - label = None - if il[dest].operation == LowLevelILOperation.LLIL_CONST: - label = il.get_label_for_address(Architecture['6502'], il[dest].constant) # type: ignore - if label is None: - il.append(il.jump(dest)) - else: - il.append(il.goto(label)) - return None - - -def get_p_value(il): - c = il.flag_bit(1, "c", 0) - z = il.flag_bit(1, "z", 1) - i = il.flag_bit(1, "i", 2) - d = il.flag_bit(1, "d", 3) - b = il.flag_bit(1, "b", 4) - v = il.flag_bit(1, "v", 6) - s = il.flag_bit(1, "s", 7) - return il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, c, z), i), d), b), v), s) - - -def set_p_value(il, value): - il.append(il.set_reg(1, LLIL_TEMP(0), value)) - il.append(il.set_flag("c", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x01)))) - il.append(il.set_flag("z", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x02)))) - il.append(il.set_flag("i", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x04)))) - il.append(il.set_flag("d", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x08)))) - il.append(il.set_flag("b", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x10)))) - il.append(il.set_flag("v", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x40)))) - il.append(il.set_flag("s", il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x80)))) - return None - - -def rti(il): - set_p_value(il, il.pop(1)) - return il.ret(il.pop(2)) - - -InstructionIL = { - "adc": - lambda il, operand: il.set_reg(1, "a", il.add_carry(1, il.reg(1, "a"), operand, il.flag("c"), flags="*")), "asl": - lambda il, operand: il.store(1, operand, il.shift_left(1, il.load(1, operand), il.const(1, 1), flags="czs")), - "asl@": - lambda il, operand: il.set_reg(1, "a", il.shift_left(1, operand, il.const(1, 1), flags="czs")), "and": - lambda il, operand: il.set_reg(1, "a", il.and_expr(1, il.reg(1, "a"), operand, flags="zs")), "bcc": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_UGE), operand), "bcs": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_ULT), operand), "beq": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_E), operand), "bit": - lambda il, operand: il.and_expr(1, il.reg(1, "a"), operand, flags="czs"), "bmi": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NEG), operand), - "bne": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NE), operand), "bpl": - lambda il, operand: cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_POS), operand), "brk": - lambda il, operand: il.system_call(), "bvc": - lambda il, operand: cond_branch(il, il.not_expr(0, il.flag("v")), operand), "bvs": - lambda il, operand: cond_branch(il, il.flag("v"), operand), "clc": - lambda il, operand: il.set_flag("c", il.const(0, 0)), "cld": - lambda il, operand: il.set_flag("d", il.const(0, 0)), "cli": - lambda il, operand: il.set_flag("i", il.const(0, 0)), "clv": - lambda il, operand: il.set_flag("v", il.const(0, 0)), "cmp": - lambda il, operand: il.sub(1, il.reg(1, "a"), operand, flags="czs"), "cpx": - lambda il, operand: il.sub(1, il.reg(1, "x"), operand, flags="czs"), "cpy": - lambda il, operand: il.sub(1, il.reg(1, "y"), operand, flags="czs"), - "dec": - lambda il, operand: il.store(1, operand, il.sub(1, il.load(1, operand), il.const(1, 1), flags="zs")), "dex": - lambda il, operand: il.set_reg(1, "x", il.sub(1, il.reg(1, "x"), il.const(1, 1), flags="zs")), "dey": - lambda il, operand: il.set_reg(1, "y", il.sub(1, il.reg(1, "y"), il.const(1, 1), flags="zs")), "eor": - lambda il, operand: il.set_reg(1, "a", il.xor_expr(1, il.reg(1, "a"), operand, flags="zs")), "inc": - lambda il, operand: il.store(1, operand, il.add(1, il.load(1, operand), il.const(1, 1), flags="zs")), "inx": - lambda il, operand: il.set_reg(1, "x", il.add(1, il.reg(1, "x"), il.const(1, 1), flags="zs")), "iny": - lambda il, operand: il.set_reg(1, "y", il.add(1, il.reg(1, "y"), il.const(1, 1), flags="zs")), "jmp": - lambda il, operand: jump(il, operand), "jsr": - lambda il, operand: il.call(operand), "lda": - lambda il, operand: il.set_reg(1, "a", operand, flags="zs"), "ldx": - lambda il, operand: il.set_reg(1, "x", operand, flags="zs"), "ldy": - lambda il, operand: il.set_reg(1, "y", operand, flags="zs"), - "lsr": - lambda il, operand: il. - store(1, operand, il.logical_shift_right(1, il.load(1, operand), il.const(1, 1), flags="czs")), "lsr@": - lambda il, operand: il.set_reg(1, "a", il.logical_shift_right(1, il.reg(1, "a"), il.const(1, 1), flags="czs")), - "nop": - lambda il, operand: il.nop(), "ora": - lambda il, operand: il.set_reg(1, "a", il.or_expr(1, il.reg(1, "a"), operand, flags="zs")), "pha": - lambda il, operand: il.push(1, il.reg(1, "a")), "php": - lambda il, operand: il.push(1, get_p_value(il)), "pla": - lambda il, operand: il.set_reg(1, "a", il.pop(1), flags="zs"), "plp": - lambda il, operand: set_p_value(il, il.pop(1)), - "rol": - lambda il, operand: il. - store(1, operand, il.rotate_left_carry(1, il.load(1, operand), il.const(1, 1), il.flag("c"), flags="czs")), "rol@": - lambda il, operand: il. - set_reg(1, "a", il.rotate_left_carry(1, il.reg(1, "a"), il.const(1, 1), il.flag("c"), flags="czs")), "ror": - lambda il, operand: il. - store(1, operand, il.rotate_right_carry(1, il.load(1, operand), il.const(1, 1), il.flag("c"), flags="czs")), - "ror@": - lambda il, operand: il. - set_reg(1, "a", il.rotate_right_carry(1, il.reg(1, "a"), il.const(1, 1), il.flag("c"), flags="czs")), "rti": - lambda il, operand: rti(il), "rts": - lambda il, operand: il.ret(il.add(2, il.pop(2), il.const(2, 1))), "sbc": - lambda il, operand: il.set_reg(1, "a", il.sub_borrow(1, il.reg(1, "a"), operand, il.flag("c"), flags="*")), - "sec": - lambda il, operand: il.set_flag("c", il.const(0, 1)), "sed": - lambda il, operand: il.set_flag("d", il.const(0, 1)), "sei": - lambda il, operand: il.set_flag("i", il.const(0, 1)), "sta": - lambda il, operand: il.store(1, operand, il.reg(1, "a")), "stx": - lambda il, operand: il.store(1, operand, il.reg(1, "x")), "sty": - lambda il, operand: il.store(1, operand, il.reg(1, "y")), "tax": - lambda il, operand: il.set_reg(1, "x", il.reg(1, "a"), flags="zs"), "tay": - lambda il, operand: il.set_reg(1, "y", il.reg(1, "a"), flags="zs"), "tsx": - lambda il, operand: il.set_reg(1, "x", il.reg(1, "s"), flags="zs"), "txa": - lambda il, operand: il.set_reg(1, "a", il.reg(1, "x"), flags="zs"), "txs": - lambda il, operand: il.set_reg(1, "s", il.reg(1, "x")), "tya": - lambda il, operand: il.set_reg(1, "a", il.reg(1, "y"), flags="zs") -} +x_reg = RegisterName("x") +y_reg = RegisterName("y") +a_reg = RegisterName("a") +s_reg = RegisterName("s") +c_flag = FlagName("c") +d_flag = FlagName("d") +i_flag = FlagName("i") +v_flag = FlagName("v") +s_flag = FlagName("s") +b_flag = FlagName("b") +z_flag = FlagName("z") class M6502(Architecture): @@ -432,55 +79,415 @@ class M6502(Architecture): default_int_size = 1 instr_alignment = 1 max_instr_length = 3 - regs = { - "a": RegisterInfo(RegisterName("a"), 1), "x": RegisterInfo(RegisterName("x"), 1), - "y": RegisterInfo(RegisterName("y"), 1), "s": RegisterInfo(RegisterName("s"), 1) + regs:Dict[RegisterName, RegisterInfo] = { + a_reg: RegisterInfo(a_reg, 1), x_reg: RegisterInfo(x_reg, 1), + y_reg: RegisterInfo(y_reg, 1), s_reg: RegisterInfo(s_reg, 1) } stack_pointer = "s" - flags = ["c", "z", "i", "d", "b", "v", "s"] - flag_write_types = ["*", "czs", "zvs", "zs"] + flags = [c_flag, z_flag, i_flag, d_flag, b_flag, v_flag, s_flag] + flag_write_types = [FlagWriteTypeName("*"), FlagWriteTypeName("czs"), FlagWriteTypeName("zvs"),FlagWriteTypeName( "zs")] flag_roles = { - "c": FlagRole.SpecialFlagRole, # Not a normal carry flag, subtract result is inverted - "z": FlagRole.ZeroFlagRole, "v": FlagRole.OverflowFlagRole, "s": FlagRole.NegativeSignFlagRole + c_flag: FlagRole.SpecialFlagRole, # Not a normal carry flag, subtract result is inverted + z_flag: FlagRole.ZeroFlagRole, v_flag: FlagRole.OverflowFlagRole, s_flag: FlagRole.NegativeSignFlagRole } flags_required_for_flag_condition = { - LowLevelILFlagCondition.LLFC_UGE: ["c"], LowLevelILFlagCondition.LLFC_ULT: ["c"], - LowLevelILFlagCondition.LLFC_E: ["z"], LowLevelILFlagCondition.LLFC_NE: ["z"], - LowLevelILFlagCondition.LLFC_NEG: ["s"], LowLevelILFlagCondition.LLFC_POS: ["s"] + LowLevelILFlagCondition.LLFC_UGE: [c_flag], LowLevelILFlagCondition.LLFC_ULT: [c_flag], + LowLevelILFlagCondition.LLFC_E: [z_flag], LowLevelILFlagCondition.LLFC_NE: [z_flag], + LowLevelILFlagCondition.LLFC_NEG: [s_flag], LowLevelILFlagCondition.LLFC_POS: [s_flag] } flags_written_by_flag_write_type = { "*": ["c", "z", "v", "s"], "czs": ["c", "z", "s"], "zvs": ["z", "v", "s"], "zs": ["z", "s"] } - def decode_instruction(self, data, addr): + InstructionIL:Dict[Mnemonic, Callable[[LowLevelILFunction, Optional[ExpressionIndex]], Optional[ExpressionIndex]]] = { + Mnemonic("adc"):lambda il, operand: il.set_reg(1, a_reg, il.add_carry(1, il.reg(1, a_reg), operand, il.flag(c_flag), flags=FlagName("*"))), + Mnemonic("asl"):lambda il, operand: il.store(1, operand, il.shift_left(1, il.load(1, operand), il.const(1, 1), flags=FlagName("czs"))), + Mnemonic("asl@"):lambda il, operand: il.set_reg(1, a_reg, il.shift_left(1, operand, il.const(1, 1), flags=FlagName("czs"))), + Mnemonic("and"):lambda il, operand: il.set_reg(1, a_reg, il.and_expr(1, il.reg(1, a_reg), operand, flags=FlagName("zs"))), + Mnemonic("bcc"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_UGE), operand), + Mnemonic("bcs"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_ULT), operand), + Mnemonic("beq"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_E), operand), + Mnemonic("bit"):lambda il, operand: il.and_expr(1, il.reg(1, a_reg), operand, flags=FlagName("czs")), + Mnemonic("bmi"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NEG), operand), + Mnemonic("bne"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_NE), operand), + Mnemonic("bpl"):lambda il, operand: M6502.cond_branch(il, il.flag_condition(LowLevelILFlagCondition.LLFC_POS), operand), + Mnemonic("brk"):lambda il, operand: il.system_call(), + Mnemonic("bvc"):lambda il, operand: M6502.cond_branch(il, il.not_expr(0, il.flag(v_flag)), operand), + Mnemonic("bvs"):lambda il, operand: M6502.cond_branch(il, il.flag(v_flag), operand), + Mnemonic("clc"):lambda il, operand: il.set_flag(c_flag, il.const(0, 0)), + Mnemonic("cld"):lambda il, operand: il.set_flag(d_flag, il.const(0, 0)), + Mnemonic("cli"):lambda il, operand: il.set_flag(i_flag, il.const(0, 0)), + Mnemonic("clv"):lambda il, operand: il.set_flag(v_flag, il.const(0, 0)), + Mnemonic("cmp"):lambda il, operand: il.sub(1, il.reg(1, a_reg), operand, flags=FlagName("czs")), + Mnemonic("cpx"):lambda il, operand: il.sub(1, il.reg(1, x_reg), operand, flags=FlagName("czs")), + Mnemonic("cpy"):lambda il, operand: il.sub(1, il.reg(1, y_reg), operand, flags=FlagName("czs")), + Mnemonic("dec"):lambda il, operand: il.store(1, operand, il.sub(1, il.load(1, operand), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("dex"):lambda il, operand: il.set_reg(1, x_reg, il.sub(1, il.reg(1, x_reg), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("dey"):lambda il, operand: il.set_reg(1, y_reg, il.sub(1, il.reg(1, y_reg), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("eor"):lambda il, operand: il.set_reg(1, a_reg, il.xor_expr(1, il.reg(1, a_reg), operand, flags=FlagName("zs"))), + Mnemonic("inc"):lambda il, operand: il.store(1, operand, il.add(1, il.load(1, operand), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("inx"):lambda il, operand: il.set_reg(1, x_reg, il.add(1, il.reg(1, x_reg), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("iny"):lambda il, operand: il.set_reg(1, y_reg, il.add(1, il.reg(1, y_reg), il.const(1, 1), flags=FlagName("zs"))), + Mnemonic("jmp"):lambda il, operand: M6502.jump(il, operand), + Mnemonic("jsr"):lambda il, operand: il.call(operand), + Mnemonic("lda"):lambda il, operand: il.set_reg(1, a_reg, operand, flags=FlagName("zs")), + Mnemonic("ldx"):lambda il, operand: il.set_reg(1, x_reg, operand, flags=FlagName("zs")), + Mnemonic("ldy"):lambda il, operand: il.set_reg(1, y_reg, operand, flags=FlagName("zs")), + Mnemonic("lsr"):lambda il, operand: il.store(1, operand, il.logical_shift_right(1, il.load(1, operand), il.const(1, 1), flags=FlagName("czs"))), + Mnemonic("lsr@"):lambda il, operand: il.set_reg(1, a_reg, il.logical_shift_right(1, il.reg(1, a_reg), il.const(1, 1), flags=FlagName("czs"))), + Mnemonic("nop"):lambda il, operand: il.nop(), + Mnemonic("ora"):lambda il, operand: il.set_reg(1, a_reg, il.or_expr(1, il.reg(1, a_reg), operand, flags=FlagName("zs"))), + Mnemonic("pha"):lambda il, operand: il.push(1, il.reg(1, a_reg)), + Mnemonic("php"):lambda il, operand: il.push(1, M6502.get_p_value(il)), + Mnemonic("pla"):lambda il, operand: il.set_reg(1, a_reg, il.pop(1), flags=FlagName("zs")), + Mnemonic("plp"):lambda il, operand: M6502.set_p_value(il, il.pop(1)), + Mnemonic("rol"):lambda il, operand: il.store(1, operand, il.rotate_left_carry(1, il.load(1, operand), il.const(1, 1), il.flag(c_flag), flags=FlagName("czs"))), + Mnemonic("rol@"):lambda il, operand: il.set_reg(1, a_reg, il.rotate_left_carry(1, il.reg(1, a_reg), il.const(1, 1), il.flag(c_flag), flags=FlagName("czs"))), + Mnemonic("ror"):lambda il, operand: il.store(1, operand, il.rotate_right_carry(1, il.load(1, operand), il.const(1, 1), il.flag(c_flag), flags=FlagName("czs"))), + Mnemonic("ror@"):lambda il, operand: il.set_reg(1, a_reg, il.rotate_right_carry(1, il.reg(1, a_reg), il.const(1, 1), il.flag(c_flag), flags=FlagName("czs"))), + Mnemonic("rti"):lambda il, operand: M6502.rti(il), + Mnemonic("rts"):lambda il, operand: il.ret(il.add(2, il.pop(2), il.const(2, 1))), + Mnemonic("sbc"):lambda il, operand: il.set_reg(1, a_reg, il.sub_borrow(1, il.reg(1, a_reg), operand, il.flag(c_flag), flags=FlagName("*"))), + Mnemonic("sec"):lambda il, operand: il.set_flag(c_flag, il.const(0, 1)), + Mnemonic("sed"):lambda il, operand: il.set_flag(d_flag, il.const(0, 1)), + Mnemonic("sei"):lambda il, operand: il.set_flag(i_flag, il.const(0, 1)), + Mnemonic("sta"):lambda il, operand: il.store(1, operand, il.reg(1, a_reg)), + Mnemonic("stx"):lambda il, operand: il.store(1, operand, il.reg(1, x_reg)), + Mnemonic("sty"):lambda il, operand: il.store(1, operand, il.reg(1, y_reg)), + Mnemonic("tax"):lambda il, operand: il.set_reg(1, x_reg, il.reg(1, a_reg), flags=FlagName("zs")), + Mnemonic("tay"):lambda il, operand: il.set_reg(1, y_reg, il.reg(1, a_reg), flags=FlagName("zs")), + Mnemonic("tsx"):lambda il, operand: il.set_reg(1, x_reg, il.reg(1, s_reg), flags=FlagName("zs")), + Mnemonic("txa"):lambda il, operand: il.set_reg(1, a_reg, il.reg(1, x_reg), flags=FlagName("zs")), + Mnemonic("txs"):lambda il, operand: il.set_reg(1, s_reg, il.reg(1, x_reg)), + Mnemonic("tya"):lambda il, operand: il.set_reg(1, a_reg, il.reg(1, y_reg), flags=FlagName("zs")) + } + + OperandIL:List[Callable[[LowLevelILFunction, int], Optional[ExpressionIndex]]] = [ + lambda il, value: None, # NONE + lambda il, value: il.load(1, il.const_pointer(2, value)), # ABS + lambda il, value: il.const(2, value), # ABS_DEST + lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, x_reg)))), # ABS_X + lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, x_reg))), # ABS_X_DEST + lambda il, value: il.load(1, il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, y_reg)))), # ABS_Y + lambda il, value: il.add(2, il.const(2, value), il.zero_extend(2, il.reg(1, y_reg))), # ABS_Y_DEST + lambda il, value: il.reg(1, a_reg), # ACCUM + lambda il, value: il.const_pointer(2, value), # ADDR + lambda il, value: il.const(1, value), # IMMED + lambda il, value: M6502.indirect_load(il, value), # IND + lambda il, value: il.load(1, M6502.load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, x_reg)))), # IND_X + lambda il, value: M6502.load_zero_page_16(il, il.add(1, il.const(1, value), il.reg(1, x_reg))), # IND_X_DEST + lambda il, value: il.load(1, il.add(2, M6502.load_zero_page_16(il, il.const(1, value)), il.reg(1, y_reg))), # IND_Y + lambda il, value: il.add(2, M6502.load_zero_page_16(il, il.const(1, value)), il.reg(1, y_reg)), # IND_Y_DEST + lambda il, value: il.const_pointer(2, value), # REL + lambda il, value: il.load(1, il.const_pointer(2, value)), # ZERO + lambda il, value: il.const_pointer(2, value), # ZERO_DEST + lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, x_reg)))), # ZERO_X + lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, x_reg))), # ZERO_X_DEST + lambda il, value: il.load(1, il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, y_reg)))), # ZERO_Y + lambda il, value: il.zero_extend(2, il.add(1, il.const(1, value), il.reg(1, y_reg))) # ZERO_Y_DEST + ] + + InstructionNames:List[Optional[Mnemonic]] = [ + Mnemonic("brk"), Mnemonic("ora"), None, None, None, Mnemonic("ora"), Mnemonic("asl"), None, # 0x00 + Mnemonic("php"), Mnemonic("ora"), Mnemonic("asl@"), None, None, Mnemonic("ora"), Mnemonic("asl"), None, # 0x08 + Mnemonic("bpl"), Mnemonic("ora"), None, None, None, Mnemonic("ora"), Mnemonic("asl"), None, # 0x10 + Mnemonic("clc"), Mnemonic("ora"), None, None, None, Mnemonic("ora"), Mnemonic("asl"), None, # 0x18 + Mnemonic("jsr"), Mnemonic("and"), None, None, Mnemonic("bit"), Mnemonic("and"), Mnemonic("rol"), None, # 0x20 + Mnemonic("plp"), Mnemonic("and"), Mnemonic("rol@"), None, Mnemonic("bit"), Mnemonic("and"), Mnemonic("rol"), None, # 0x28 + Mnemonic("bmi"), Mnemonic("and"), None, None, None, Mnemonic("and"), Mnemonic("rol"), None, # 0x30 + Mnemonic("sec"), Mnemonic("and"), None, None, None, Mnemonic("and"), Mnemonic("rol"), None, # 0x38 + Mnemonic("rti"), Mnemonic("eor"), None, None, None, Mnemonic("eor"), Mnemonic("lsr"), None, # 0x40 + Mnemonic("pha"), Mnemonic("eor"), Mnemonic("lsr@"), None, Mnemonic("jmp"), Mnemonic("eor"), Mnemonic("lsr"), None, # 0x48 + Mnemonic("bvc"), Mnemonic("eor"), None, None, None, Mnemonic("eor"), Mnemonic("lsr"), None, # 0x50 + Mnemonic("cli"), Mnemonic("eor"), None, None, None, Mnemonic("eor"), Mnemonic("lsr"), None, # 0x58 + Mnemonic("rts"), Mnemonic("adc"), None, None, None, Mnemonic("adc"), Mnemonic("ror"), None, # 0x60 + Mnemonic("pla"), Mnemonic("adc"), Mnemonic("ror@"), None, Mnemonic("jmp"), Mnemonic("adc"), Mnemonic("ror"), None, # 0x68 + Mnemonic("bvs"), Mnemonic("adc"), None, None, None, Mnemonic("adc"), Mnemonic("ror"), None, # 0x70 + Mnemonic("sei"), Mnemonic("adc"), None, None, None, Mnemonic("adc"), Mnemonic("ror"), None, # 0x78 + None, Mnemonic("sta"), None, None, Mnemonic("sty"), Mnemonic("sta"), Mnemonic("stx"), None, # 0x80 + Mnemonic("dey"), None, Mnemonic("txa"), None, Mnemonic("sty"), Mnemonic("sta"), Mnemonic("stx"), None, # 0x88 + Mnemonic("bcc"), Mnemonic("sta"), None, None, Mnemonic("sty"), Mnemonic("sta"), Mnemonic("stx"), None, # 0x90 + Mnemonic("tya"), Mnemonic("sta"), Mnemonic("txs"), None, None, Mnemonic("sta"), None, None, # 0x98 + Mnemonic("ldy"), Mnemonic("lda"), Mnemonic("ldx"), None, Mnemonic("ldy"), Mnemonic("lda"), Mnemonic("ldx"), None, # 0xa0 + Mnemonic("tay"), Mnemonic("lda"), Mnemonic("tax"), None, Mnemonic("ldy"), Mnemonic("lda"), Mnemonic("ldx"), None, # 0xa8 + Mnemonic("bcs"), Mnemonic("lda"), None, None, Mnemonic("ldy"), Mnemonic("lda"), Mnemonic("ldx"), None, # 0xb0 + Mnemonic("clv"), Mnemonic("lda"), Mnemonic("tsx"), None, Mnemonic("ldy"), Mnemonic("lda"), Mnemonic("ldx"), None, # 0xb8 + Mnemonic("cpy"), Mnemonic("cmp"), None, None, Mnemonic("cpy"), Mnemonic("cmp"), Mnemonic("dec"), None, # 0xc0 + Mnemonic("iny"), Mnemonic("cmp"), Mnemonic("dex"), None, Mnemonic("cpy"), Mnemonic("cmp"), Mnemonic("dec"), None, # 0xc8 + Mnemonic("bne"), Mnemonic("cmp"), None, None, None, Mnemonic("cmp"), Mnemonic("dec"), None, # 0xd0 + Mnemonic("cld"), Mnemonic("cmp"), None, None, None, Mnemonic("cmp"), Mnemonic("dec"), None, # 0xd8 + Mnemonic("cpx"), Mnemonic("sbc"), None, None, Mnemonic("cpx"), Mnemonic("sbc"), Mnemonic("inc"), None, # 0xe0 + Mnemonic("inx"), Mnemonic("sbc"), Mnemonic("nop"), None, Mnemonic("cpx"), Mnemonic("sbc"), Mnemonic("inc"), None, # 0xe8 + Mnemonic("beq"), Mnemonic("sbc"), None, None, None, Mnemonic("sbc"), Mnemonic("inc"), None, # 0xf0 + Mnemonic("sed"), Mnemonic("sbc"), None, None, None, Mnemonic("sbc"), Mnemonic("inc"), None # 0xf8 + ] + + OperandTokens: List[Callable[[int], List[InstructionTextToken]]] = [ + lambda value: [], # NONE + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ABS + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value) + ], # ABS_DEST + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") + ], # ABS_X + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") + ], # ABS_X_DEST + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ], # ABS_Y + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ], # ABS_Y_DEST + lambda value: [InstructionTextToken(InstructionTextTokenType.RegisterToken, "a")], # ACCUM + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # ADDR + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "#"), + InstructionTextToken(InstructionTextTokenType.IntegerToken, "$%.2x" % value, value) + ], # IMMED + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "["), + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, "]") + ], # IND + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "["), + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"), + InstructionTextToken(InstructionTextTokenType.TextToken, "]") + ], # IND_X + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "["), + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x"), + InstructionTextToken(InstructionTextTokenType.TextToken, "]") + ], # IND_X_DEST + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "["), + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, "], "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ], # IND_Y + lambda value: [ + InstructionTextToken(InstructionTextTokenType.TextToken, "["), + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, "], "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ], # IND_Y_DEST + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.4x" % value, value)], # REL + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value)], # ZERO + lambda value: [InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value) + ], # ZERO_DEST + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") + ], # ZERO_X + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "x") + ], # ZERO_X_DEST + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ], # ZERO_Y + lambda value: [ + InstructionTextToken(InstructionTextTokenType.PossibleAddressToken, "$%.2x" % value, value), + InstructionTextToken(InstructionTextTokenType.TextToken, ", "), + InstructionTextToken(InstructionTextTokenType.RegisterToken, "y") + ] # ZERO_Y_DEST + ] + + InstructionOperandTypes:List[Optional[Operand]] = [ + NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x00 + NONE, IMMED, ACCUM, NONE, NONE, ABS, ABS_DEST, NONE, # 0x08 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x10 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x18 + ADDR, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0x20 + NONE, IMMED, ACCUM, NONE, ABS, ABS, ABS_DEST, NONE, # 0x28 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x30 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x38 + NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x40 + NONE, IMMED, ACCUM, NONE, ADDR, ABS, ABS_DEST, NONE, # 0x48 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x50 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x58 + NONE, IND_X, NONE, NONE, NONE, ZERO, ZERO_DEST, NONE, # 0x60 + NONE, IMMED, ACCUM, NONE, IND, ABS, ABS_DEST, NONE, # 0x68 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0x70 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0x78 + NONE, IND_X_DEST, NONE, NONE, ZERO_DEST, ZERO_DEST, ZERO_DEST, NONE, # 0x80 + NONE, NONE, NONE, NONE, ABS_DEST, ABS_DEST, ABS_DEST, NONE, # 0x88 + REL, IND_Y_DEST, NONE, NONE, ZERO_X_DEST, ZERO_X_DEST, ZERO_Y_DEST, NONE, # 0x90 + NONE, ABS_Y_DEST, NONE, NONE, NONE, ABS_X_DEST, NONE, NONE, # 0x98 + IMMED, IND_X, IMMED, NONE, ZERO, ZERO, ZERO, NONE, # 0xa0 + NONE, IMMED, NONE, NONE, ABS, ABS, ABS, NONE, # 0xa8 + REL, IND_Y, NONE, NONE, ZERO_X, ZERO_X, ZERO_Y, NONE, # 0xb0 + NONE, ABS_Y, NONE, NONE, ABS_X, ABS_X, ABS_Y, NONE, # 0xb8 + IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xc0 + NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xc8 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xd0 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE, # 0xd8 + IMMED, IND_X, NONE, NONE, ZERO, ZERO, ZERO_DEST, NONE, # 0xe0 + NONE, IMMED, NONE, NONE, ABS, ABS, ABS_DEST, NONE, # 0xe8 + REL, IND_Y, NONE, NONE, NONE, ZERO_X, ZERO_X_DEST, NONE, # 0xf0 + NONE, ABS_Y, NONE, NONE, NONE, ABS_X, ABS_X_DEST, NONE # 0xf8 + ] + + OperandLengths:List[int] = [ + 0, # NONE + 2, # ABS + 2, # ABS_DEST + 2, # ABS_X + 2, # ABS_X_DEST + 2, # ABS_Y + 2, # ABS_Y_DEST + 0, # ACCUM + 2, # ADDR + 1, # IMMED + 2, # IND + 1, # IND_X + 1, # IND_X_DEST + 1, # IND_Y + 1, # IND_Y_DEST + 1, # REL + 1, # ZERO + 1, # ZERO_DEST + 1, # ZERO_X + 1, # ZERO_X_DEST + 1, # ZERO_Y + 1 # ZERO_Y_DEST + ] + + + @staticmethod + def load_zero_page_16(il:LowLevelILFunction, value:ExpressionIndex) -> ExpressionIndex: + instr = LowLevelILInstruction.create(il, value) + if isinstance(instr, LowLevelILConst): + if instr.constant == 0xff: + lo = il.zero_extend(2, il.load(1, il.const_pointer(2, 0xff))) + hi = il.shift_left(2, il.zero_extend(2, il.load(1, il.const_pointer(2, 0))), il.const(2, 8)) + return il.or_expr(2, lo, hi) + return il.load(2, il.const_pointer(2, instr.constant)) + il.append(il.set_reg(1, LLIL_TEMP(0), value)) + expr = il.reg(1, LLIL_TEMP(0)) + lo_addr = expr + hi_addr = il.add(1, expr, il.const(1, 1)) + lo = il.zero_extend(2, il.load(1, lo_addr)) + hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8)) + return il.or_expr(2, lo, hi) + + @staticmethod + def indirect_load(il:LowLevelILFunction, value:int) -> ExpressionIndex: + if (value & 0xff) == 0xff: + lo_addr = il.const_pointer(2, value) + hi_addr = il.const_pointer(2, (value & 0xff00) | ((value + 1) & 0xff)) + lo = il.zero_extend(2, il.load(1, lo_addr)) + hi = il.shift_left(2, il.zero_extend(2, il.load(1, hi_addr)), il.const(2, 8)) + return il.or_expr(2, lo, hi) + return il.load(2, il.const_pointer(2, value)) + + @staticmethod + def cond_branch(il:LowLevelILFunction, cond:ExpressionIndex, dest:ExpressionIndex) -> None: + t = None + instr = LowLevelILInstruction.create(il, dest) + if isinstance(instr, LowLevelILConst): + t = il.get_label_for_address(Architecture['6502'], instr.constant) # type: ignore + if t is None: + t = LowLevelILLabel() + indirect = True + else: + indirect = False + f = LowLevelILLabel() + il.append(il.if_expr(cond, t, f)) + if indirect: + il.mark_label(t) + il.append(il.jump(dest)) + il.mark_label(f) + return None + + @staticmethod + def jump(il:LowLevelILFunction, dest:ExpressionIndex) -> None: + label = None + instr = LowLevelILInstruction.create(il, dest) + if isinstance(instr, LowLevelILConst): + label = il.get_label_for_address(Architecture['6502'], instr.constant) # type: ignore + if label is None: + il.append(il.jump(dest)) + else: + il.append(il.goto(label)) + return None + + @staticmethod + def get_p_value(il:LowLevelILFunction) -> ExpressionIndex: + c = il.flag_bit(1, c_flag, 0) + z = il.flag_bit(1, z_flag, 1) + i = il.flag_bit(1, i_flag, 2) + d = il.flag_bit(1, d_flag, 3) + b = il.flag_bit(1, b_flag, 4) + v = il.flag_bit(1, v_flag, 6) + s = il.flag_bit(1, s_flag, 7) + return il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, il.or_expr(1, c, z), i), d), b), v), s) + + @staticmethod + def set_p_value(il:LowLevelILFunction, value:ExpressionIndex) -> None: + il.append(il.set_reg(1, LLIL_TEMP(0), value)) + il.append(il.set_flag(c_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x01)))) + il.append(il.set_flag(z_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x02)))) + il.append(il.set_flag(i_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x04)))) + il.append(il.set_flag(d_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x08)))) + il.append(il.set_flag(b_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x10)))) + il.append(il.set_flag(v_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x40)))) + il.append(il.set_flag(s_flag, il.test_bit(1, il.reg(1, LLIL_TEMP(0)), il.const(1, 0x80)))) + return None + + @staticmethod + def rti(il:LowLevelILFunction) -> ExpressionIndex: + M6502.set_p_value(il, il.pop(1)) + return il.ret(il.pop(2)) + + @staticmethod + def decode_instruction(data:bytes, addr:int) -> Optional[Tuple[Mnemonic, Operand, int, int]]: if len(data) < 1: - return None, None, None, None + return None opcode = ord(data[0:1]) - instr = InstructionNames[opcode] + instr = M6502.InstructionNames[opcode] if instr is None: - return None, None, None, None - - operand = InstructionOperandTypes[opcode] - length = 1 + OperandLengths[operand] + return None + operand = M6502.InstructionOperandTypes[opcode] + assert operand is not None + length = 1 + M6502.OperandLengths[operand] if len(data) < length: - return None, None, None, None + return None - if OperandLengths[operand] == 0: - value = None + if M6502.OperandLengths[operand] == 0: + value = 0 elif operand == REL: value = (addr + 2 + struct.unpack("b", data[1:2])[0]) & 0xffff - elif OperandLengths[operand] == 1: + elif M6502.OperandLengths[operand] == 1: value = ord(data[1:2]) else: value = struct.unpack("<H", data[1:3])[0] return instr, operand, length, value - def get_instruction_info(self, data, addr): - instr, operand, length, value = self.decode_instruction(data, addr) - if instr is None: + def get_instruction_info(self, data:bytes, addr:int) -> Optional[InstructionInfo]: + result = M6502.decode_instruction(data, addr) + if result is None: return None - + instr, operand, length, _ = result + assert length is not None result = InstructionInfo() result.length = length if instr == "jmp": @@ -498,32 +505,30 @@ class M6502(Architecture): result.add_branch(BranchType.FalseBranch, addr + 2) return result - def get_instruction_text(self, data, addr): - instr, operand, length, value = self.decode_instruction(data, addr) - if instr is None or operand is None or length is None or value is None: + def get_instruction_text(self, data: bytes, addr: int) -> Optional[Tuple[List[InstructionTextToken], int]]: + result = M6502.decode_instruction(data, addr) + if result is None: return None - - tokens = [] + instr, operand, length, value = result + tokens:List[InstructionTextToken] = [] tokens.append(InstructionTextToken(InstructionTextTokenType.TextToken, "%-7s " % instr.replace("@", ""))) - tokens += OperandTokens[operand](value) + tokens += M6502.OperandTokens[operand](value) return tokens, length - def get_instruction_low_level_il(self, data, addr, il): - instr, operand, length, value = self.decode_instruction(data, addr) - if instr is None or operand is None or length is None or value is None: + def get_instruction_low_level_il(self, data: bytes, addr: int, il: LowLevelILFunction) -> Optional[int]: + result = M6502.decode_instruction(data, addr) + if result is None: return None - - operand = OperandIL[operand](il, value) - instr = InstructionIL[instr](il, operand) - if isinstance(instr, list): - for i in instr: - il.append(i) - elif instr is not None: - il.append(instr) - + instr, operand, length, value = result + if instr is None or operand is None or length is None: + return None + op = M6502.OperandIL[operand](il, value) + i = M6502.InstructionIL[instr](il, op) + if i is not None: + il.append(i) return length - def get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il): + def get_flag_write_low_level_il(self, op: LowLevelILOperation, size: int, write_type: Optional[FlagWriteTypeName], flag: FlagType, operands: List[ILRegisterType], il: LowLevelILFunction) -> ExpressionIndex: if flag == 'c': if (op == LowLevelILOperation.LLIL_SUB) or (op == LowLevelILOperation.LLIL_SBB): # Subtraction carry flag is inverted from the commom implementation @@ -532,47 +537,49 @@ class M6502(Architecture): return self.get_default_flag_write_low_level_il(op, size, FlagRole.CarryFlagRole, operands, il) return Architecture.get_flag_write_low_level_il(self, op, size, write_type, flag, operands, il) - def is_never_branch_patch_available(self, data, addr): + def is_never_branch_patch_available(self, data:bytes, addr:int) -> bool: if (data[0:1] == b"\x10") or (data[0:1] == b"\x30") or (data[0:1] == b"\x50") or (data[0:1] == b"\x70") or ( data[0:1] == b"\x90" ) or (data[0:1] == b"\xb0") or (data[0:1] == b"\xd0") or (data[0:1] == b"\xf0"): return True return False - def is_invert_branch_patch_available(self, data, addr): + def is_invert_branch_patch_available(self, data:bytes, addr:int) -> bool: if (data[0:1] == b"\x10") or (data[0:1] == b"\x30") or (data[0:1] == b"\x50") or (data[0:1] == b"\x70") or ( data[0:1] == b"\x90" ) or (data[0:1] == b"\xb0") or (data[0:1] == b"\xd0") or (data[0:1] == b"\xf0"): return True return False - def is_always_branch_patch_available(self, data, addr): + def is_always_branch_patch_available(self, data:bytes, addr:int) -> bool: return False - def is_skip_and_return_zero_patch_available(self, data, addr): + def is_skip_and_return_zero_patch_available(self, data:bytes, addr:int) -> bool: return (data[0:1] == b"\x20") and (len(data) == 3) - def is_skip_and_return_value_patch_available(self, data, addr): + def is_skip_and_return_value_patch_available(self, data:bytes, addr:int) -> bool: return (data[0:1] == b"\x20") and (len(data) == 3) - def convert_to_nop(self, data, addr): + def convert_to_nop(self, data:bytes, addr:int) -> bytes: return b"\xea" * len(data) - def never_branch(self, data, addr): + def never_branch(self, data:bytes, addr:int) -> Optional[bytes]: if (data[0:1] == b"\x10") or (data[0:1] == b"\x30") or (data[0:1] == b"\x50") or (data[0:1] == b"\x70") or ( data[0:1] == b"\x90" ) or (data[0:1] == b"\xb0") or (data[0:1] == b"\xd0") or (data[0:1] == b"\xf0"): return b"\xea" * len(data) return None - def invert_branch(self, data, addr): + def invert_branch(self, data:bytes, addr:int) -> Optional[bytes]: if (data[0:1] == b"\x10") or (data[0:1] == b"\x30") or (data[0:1] == b"\x50") or (data[0:1] == b"\x70") or ( data[0:1] == b"\x90" ) or (data[0:1] == b"\xb0") or (data[0:1] == b"\xd0") or (data[0:1] == b"\xf0"): - return chr(ord(data[0:1]) ^ 0x20) + data[1:] + result = bytearray(data) + result[0] ^= 0x20 + return bytes(result) return None - def skip_and_return_value(self, data, addr, value): + def skip_and_return_value(self, data:bytes, addr:int, value:int) -> Optional[bytes]: if (data[0:1] != b"\x20") or (len(data) != 3): return None return b"\xa9" + (value & 0xff).to_bytes(1, "little") + b"\xea" @@ -583,12 +590,12 @@ class NESView(BinaryView): long_name = "NES ROM" bank = None - def __init__(self, data): + def __init__(self, data:BinaryView): BinaryView.__init__(self, parent_view=data, file_metadata=data.file) self.platform = Architecture['6502'].standalone_platform # type: ignore @classmethod - def is_valid_for_data(cls, data): + def is_valid_for_data(cls, data:BinaryView) -> bool: hdr = data.read(0, 16) if len(hdr) < 16: return False @@ -600,8 +607,9 @@ class NESView(BinaryView): return False return True - def init(self): + def init(self) -> bool: try: + assert self.parent_view is not None hdr = self.parent_view.read(0, 16) self.rom_banks = struct.unpack("B", hdr[4:5])[0] self.vrom_banks = struct.unpack("B", hdr[5:6])[0] @@ -615,18 +623,18 @@ class NESView(BinaryView): # Add mapping for RAM and hardware registers, not backed by file contents self.add_auto_segment( - 0, 0x8000, 0, 0, SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable + 0, 0x8000, 0, 0, SegmentFlag(SegmentFlag.SegmentReadable | SegmentFlag.SegmentWritable | SegmentFlag.SegmentExecutable) ) # Add ROM mappings assert self.__class__.bank is not None self.add_auto_segment( 0x8000, 0x4000, self.rom_offset + (self.__class__.bank * 0x4000), 0x4000, - SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable + SegmentFlag(SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) ) self.add_auto_segment( 0xc000, 0x4000, self.rom_offset + self.rom_length - 0x4000, 0x4000, - SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable + SegmentFlag(SegmentFlag.SegmentReadable | SegmentFlag.SegmentExecutable) ) nmi = struct.unpack("<H", self.read(0xfffa, 2))[0] @@ -672,13 +680,14 @@ class NESView(BinaryView): self.define_auto_symbol(Symbol(SymbolType.DataSymbol, 0x4017, "JOY2")) sym_files = [ - self.file.filename + ".%x.nl" % self.__class__.bank, self.file.filename + ".ram.nl", - self.file.filename + ".%x.nl" % (self.rom_banks - 1) + self.file.filename + f".{self.__class__.bank:x}.nl", + self.file.filename + ".ram.nl", + self.file.filename + f".{self.rom_banks - 1:x}.nl" ] - for f in sym_files: - if os.path.exists(f): - with open(f, "r") as f: - lines = f.readlines() + for file_name in sym_files: + if os.path.exists(file_name): + with open(file_name, "r") as cur_file: + lines = cur_file.readlines() for line in lines: line = line.strip() sym = line.split('#') @@ -695,22 +704,21 @@ class NESView(BinaryView): log_error(traceback.format_exc()) return False - def perform_is_executable(self): + def perform_is_executable(self) -> bool: return True - def perform_get_entry_point(self): + def perform_get_entry_point(self) -> int: return struct.unpack("<H", self.perform_read(0xfffc, 2))[0] -banks = [] -for i in range(0, 32): - +banks:List[Type['NESViewBank']] = [] +for i in range(32): class NESViewBank(NESView): bank = i name = "NES Bank %X" % i long_name = "NES ROM (bank %X)" % i - def __init__(self, data): + def __init__(self, data:BinaryView): NESView.__init__(self, data) banks.append(NESViewBank) |
