#!/usr/bin/env python3 # SPDX-FileCopyrightText: 2014 MicroPython & CircuitPython contributors (https://github.com/adafruit/circuitpython/graphs/contributors) # # SPDX-License-Identifier: MIT import sys import binascii import io bytecode_format_sizes = { "MP_OPCODE_BYTE": 1, "MP_OPCODE_QSTR": 3, "MP_OPCODE_VAR_UINT": None, # Unknown because uint encoding uses the top bit to indicate the end. "MP_OPCODE_OFFSET": 3, "MP_OPCODE_BYTE_EXTRA": 2, "MP_OPCODE_VAR_UINT_EXTRA": None, "MP_OPCODE_OFFSET_EXTRA": 4, } bytecodes = { 0x00: {"name": "MP_BC_LOAD_FAST_MULTI", "format": "MP_OPCODE_BYTE"}, 0x10: {"name": "MP_BC_LOAD_CONST_FALSE", "format": "MP_OPCODE_BYTE"}, 0x11: {"name": "MP_BC_LOAD_CONST_NONE", "format": "MP_OPCODE_BYTE"}, 0x12: {"name": "MP_BC_LOAD_CONST_TRUE", "format": "MP_OPCODE_BYTE"}, 0x14: {"name": "MP_BC_LOAD_CONST_SMALL_INT", "format": "MP_OPCODE_VAR_UINT"}, 0x16: {"name": "MP_BC_LOAD_CONST_STRING", "format": "MP_OPCODE_QSTR"}, 0x17: {"name": "MP_BC_LOAD_CONST_OBJ", "format": "MP_OPCODE_VAR_UINT"}, # define MP_BC_LOAD_CONST_OBJ (0x17) // ptr 0x18: {"name": "MP_BC_LOAD_NULL", "format": "MP_OPCODE_BYTE"}, # define MP_BC_LOAD_FAST_N (0x19) // uint 0x1A: {"name": "MP_BC_LOAD_DEREF", "format": "MP_OPCODE_VAR_UINT"}, 0x1B: {"name": "MP_BC_LOAD_NAME", "format": "MP_OPCODE_QSTR"}, 0x1C: {"name": "MP_BC_LOAD_GLOBAL", "format": "MP_OPCODE_QSTR"}, 0x1D: {"name": "MP_BC_LOAD_ATTR", "format": "MP_OPCODE_QSTR"}, 0x1E: {"name": "MP_BC_LOAD_METHOD", "format": "MP_OPCODE_QSTR"}, 0x1F: {"name": "MP_BC_LOAD_SUPER_METHOD", "format": "MP_OPCODE_QSTR"}, 0x20: {"name": "MP_BC_LOAD_BUILD_CLASS", "format": "MP_OPCODE_BYTE"}, # define MP_BC_LOAD_BUILD_CLASS (0x20) # define MP_BC_LOAD_SUBSCR (0x21) 0x21: {"name": "MP_BC_LOAD_SUBSCR", "format": "MP_OPCODE_BYTE"}, # define MP_BC_STORE_FAST_N (0x22) // uint # define MP_BC_STORE_DEREF (0x23) // uint # define MP_BC_STORE_NAME (0x24) // qstr 0x24: {"name": "MP_BC_STORE_NAME", "format": "MP_OPCODE_QSTR"}, 0x25: {"name": "MP_BC_STORE_GLOBAL", "format": "MP_OPCODE_QSTR"}, 0x26: {"name": "MP_BC_STORE_ATTR", "format": "MP_OPCODE_QSTR"}, 0x27: {"name": "MP_BC_LOAD_SUBSCR", "format": "MP_OPCODE_BYTE"}, 0x28: {"name": "MP_BC_DELETE_FAST", "format": "MP_OPCODE_VAR_UINT"}, # define MP_BC_DELETE_FAST (0x28) // uint # define MP_BC_DELETE_DEREF (0x29) // uint # define MP_BC_DELETE_NAME (0x2a) // qstr # define MP_BC_DELETE_GLOBAL (0x2b) // qstr 0x30: {"name": "MP_BC_DUP_TOP", "format": "MP_OPCODE_BYTE"}, # define MP_BC_DUP_TOP_TWO (0x31) 0x32: {"name": "MP_BC_POP_TOP", "format": "MP_OPCODE_BYTE"}, 0x33: {"name": "MP_BC_ROT_TWO", "format": "MP_OPCODE_BYTE"}, 0x34: {"name": "MP_BC_ROT_THREE", "format": "MP_OPCODE_BYTE"}, 0x35: {"name": "MP_BC_JUMP", "format": "MP_OPCODE_OFFSET"}, 0x36: {"name": "MP_BC_POP_JUMP_IF_TRUE", "format": "MP_OPCODE_OFFSET"}, 0x37: {"name": "MP_BC_POP_JUMP_IF_FALSE", "format": "MP_OPCODE_OFFSET"}, # define MP_BC_JUMP_IF_TRUE_OR_POP (0x38) // rel byte code offset, 16-bit signed, in excess # define MP_BC_JUMP_IF_FALSE_OR_POP (0x39) // rel byte code offset, 16-bit signed, in excess # define MP_BC_SETUP_WITH (0x3d) // rel byte code offset, 16-bit unsigned # define MP_BC_WITH_CLEANUP (0x3e) # define MP_BC_SETUP_EXCEPT (0x3f) // rel byte code offset, 16-bit unsigned # define MP_BC_SETUP_FINALLY (0x40) // rel byte code offset, 16-bit unsigned # define MP_BC_END_FINALLY (0x41) # define MP_BC_GET_ITER (0x42) # define MP_BC_FOR_ITER (0x43) // rel byte code offset, 16-bit unsigned 0x43: {"name": "MP_BC_FOR_ITER", "format": "MP_OPCODE_OFFSET"}, 0x44: {"name": "MP_BC_POP_BLOCK", "format": "MP_OPCODE_BYTE"}, # define MP_BC_POP_EXCEPT (0x45) # define MP_BC_UNWIND_JUMP (0x46) // rel byte code offset, 16-bit signed, in excess; then a byte 0x47: {"name": "MP_BC_GET_ITER_STACK", "format": "MP_OPCODE_BYTE"}, 0x50: {"name": "MP_BC_BUILD_TUPLE", "format": "MP_OPCODE_VAR_UINT"}, 0x51: {"name": "MP_BC_BUILD_LIST", "format": "MP_OPCODE_VAR_UINT"}, 0x53: {"name": "MP_BC_BUILD_MAP", "format": "MP_OPCODE_VAR_UINT"}, 0x54: {"name": "MP_BC_STORE_MAP", "format": "MP_OPCODE_BYTE"}, # define MP_BC_BUILD_SET (0x56) // uint # define MP_BC_BUILD_SLICE (0x58) // uint # define MP_BC_STORE_COMP (0x57) // uint 0x57: {"name": "MP_BC_STORE_COMP", "format": "MP_OPCODE_VAR_UINT"}, # define MP_BC_UNPACK_SEQUENCE (0x59) // uint # define MP_BC_UNPACK_EX (0x5a) // uint 0x5B: {"name": "MP_BC_RETURN_VALUE", "format": "MP_OPCODE_BYTE"}, 0x5C: {"name": "MP_BC_RAISE_VARARGS", "format": "MP_OPCODE_BYTE_EXTRA"}, # define MP_BC_YIELD_VALUE (0x5d) # define MP_BC_YIELD_FROM (0x5e) # define MP_BC_MAKE_FUNCTION (0x60) // uint 0x60: {"name": "MP_BC_MAKE_FUNCTION", "format": "MP_OPCODE_VAR_UINT"}, 0x61: {"name": "MP_BC_MAKE_FUNCTION_DEFARGS", "format": "MP_OPCODE_VAR_UINT"}, 0x62: {"name": "MP_BC_MAKE_CLOSURE", "format": "MP_OPCODE_VAR_UINT_EXTRA"}, 0x63: {"name": "MP_BC_MAKE_CLOSURE", "format": "MP_OPCODE_VAR_UINT_EXTRA"}, 0x64: {"name": "MP_BC_CALL_FUNCTION", "format": "MP_OPCODE_VAR_UINT"}, 0x65: {"name": "MP_BC_CALL_FUNCTION_VAR_KW", "format": "MP_OPCODE_VAR_UINT"}, 0x66: {"name": "MP_BC_CALL_METHOD", "format": "MP_OPCODE_VAR_UINT"}, 0x67: {"name": "MP_BC_CALL_METHOD_VAR_KW", "format": "MP_OPCODE_VAR_UINT"}, 0x68: {"name": "MP_BC_IMPORT_NAME", "format": "MP_OPCODE_QSTR"}, 0x69: {"name": "MP_BC_IMPORT_FROM", "format": "MP_OPCODE_QSTR"}, # define MP_BC_IMPORT_FROM (0x69) // qstr # define MP_BC_IMPORT_STAR (0x6a) # define MP_BC_LOAD_CONST_SMALL_INT_MULTI (0x70) // + N(64) 0x7F: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI -1", "format": "MP_OPCODE_BYTE"}, 0x80: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI 0", "format": "MP_OPCODE_BYTE"}, 0x81: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI 1", "format": "MP_OPCODE_BYTE"}, 0x82: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI 2", "format": "MP_OPCODE_BYTE"}, 0x83: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI 3", "format": "MP_OPCODE_BYTE"}, 0x84: {"name": "MP_BC_LOAD_CONST_SMALL_INT_MULTI 4", "format": "MP_OPCODE_BYTE"}, # define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16) 0xB0: {"name": "MP_BC_LOAD_FAST_MULTI 0", "format": "MP_OPCODE_BYTE"}, 0xB1: {"name": "MP_BC_LOAD_FAST_MULTI 1", "format": "MP_OPCODE_BYTE"}, 0xB2: {"name": "MP_BC_LOAD_FAST_MULTI 2", "format": "MP_OPCODE_BYTE"}, 0xB3: {"name": "MP_BC_LOAD_FAST_MULTI 3", "format": "MP_OPCODE_BYTE"}, 0xB4: {"name": "MP_BC_LOAD_FAST_MULTI 4", "format": "MP_OPCODE_BYTE"}, 0xB5: {"name": "MP_BC_LOAD_FAST_MULTI 5", "format": "MP_OPCODE_BYTE"}, 0xB6: {"name": "MP_BC_LOAD_FAST_MULTI 6", "format": "MP_OPCODE_BYTE"}, 0xB7: {"name": "MP_BC_LOAD_FAST_MULTI 7", "format": "MP_OPCODE_BYTE"}, 0xB8: {"name": "MP_BC_LOAD_FAST_MULTI 8", "format": "MP_OPCODE_BYTE"}, # define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16) 0xC0: {"name": "MP_BC_STORE_FAST_MULTI 0", "format": "MP_OPCODE_BYTE"}, 0xC1: {"name": "MP_BC_STORE_FAST_MULTI 1", "format": "MP_OPCODE_BYTE"}, 0xC2: {"name": "MP_BC_STORE_FAST_MULTI 2", "format": "MP_OPCODE_BYTE"}, 0xC3: {"name": "MP_BC_STORE_FAST_MULTI 3", "format": "MP_OPCODE_BYTE"}, 0xC4: {"name": "MP_BC_STORE_FAST_MULTI 4", "format": "MP_OPCODE_BYTE"}, 0xC5: {"name": "MP_BC_STORE_FAST_MULTI 5", "format": "MP_OPCODE_BYTE"}, 0xC6: {"name": "MP_BC_STORE_FAST_MULTI 6", "format": "MP_OPCODE_BYTE"}, 0xC7: {"name": "MP_BC_STORE_FAST_MULTI 7", "format": "MP_OPCODE_BYTE"}, # define MP_BC_UNARY_OP_MULTI (0xd0) // + op(> 8 if not opcode_size: i += 2 while (bytecode[i] & 0x80) != 0: i += 1 if bc["format"] == "MP_OPCODE_VAR_UINT_EXTRA": i += 1 else: i += opcode_size class mpyFile: def __init__(self, encoded_mpy): # this matches mp-raw_code_save in py/persistentcode.c first_byte = encoded_mpy.read(1) if first_byte != b"C": raise ValueError("Not a valid first byte. Should be 'C' but is {}".format(first_byte)) self.version = encoded_mpy.read(1)[0] self.feature_flags = encoded_mpy.read(1)[0] self.small_int_bits = encoded_mpy.read(1)[0] self.raw_code = RawCode(encoded_mpy) if __name__ == "__main__": with open(sys.argv[1], "rb") as f: mpy = mpyFile(f) print(mpy.version) print(mpy.feature_flags) print(mpy.small_int_bits)