diff options
Diffstat (limited to 'tools/analyze_mpy.py')
| -rw-r--r-- | tools/analyze_mpy.py | 315 |
1 files changed, 265 insertions, 50 deletions
diff --git a/tools/analyze_mpy.py b/tools/analyze_mpy.py index 00be66106..376207a24 100644 --- a/tools/analyze_mpy.py +++ b/tools/analyze_mpy.py @@ -13,46 +13,79 @@ bytecode_format_sizes = { } bytecodes = { + 0x00: {"name": "MP_BC_LOAD_FAST_MULTI", + "format": "MP_OPCODE_BYTE"}, 0x10: {"name": "MP_BC_LOAD_CONST_FALSE", "format": "MP_OPCODE_BYTE"}, -#define MP_BC_LOAD_CONST_NONE (0x11) -#define MP_BC_LOAD_CONST_TRUE (0x12) -#define MP_BC_LOAD_CONST_SMALL_INT (0x14) // signed var-int -#define MP_BC_LOAD_CONST_STRING (0x16) // qstr + 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 -#define MP_BC_LOAD_NULL (0x18) + 0x18: {"name": "MP_BC_LOAD_NULL", + "format": "MP_OPCODE_BYTE"}, #define MP_BC_LOAD_FAST_N (0x19) // uint -#define MP_BC_LOAD_DEREF (0x1a) // uint -#define MP_BC_LOAD_NAME (0x1b) // qstr -#define MP_BC_LOAD_GLOBAL (0x1c) // qstr -#define MP_BC_LOAD_ATTR (0x1d) // qstr -#define MP_BC_LOAD_METHOD (0x1e) // qstr -#define MP_BC_LOAD_SUPER_METHOD (0x1f) // qstr + 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 -#define MP_BC_STORE_GLOBAL (0x25) // qstr -#define MP_BC_STORE_ATTR (0x26) // qstr -#define MP_BC_STORE_SUBSCR (0x27) + 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 -#define MP_BC_DUP_TOP (0x30) + 0x30: {"name": "MP_BC_DUP_TOP", + "format": "MP_OPCODE_BYTE"}, #define MP_BC_DUP_TOP_TWO (0x31) -#define MP_BC_POP_TOP (0x32) -#define MP_BC_ROT_TWO (0x33) -#define MP_BC_ROT_THREE (0x34) + 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"}, -#define MP_BC_JUMP (0x35) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_TRUE (0x36) // rel byte code offset, 16-bit signed, in excess -#define MP_BC_POP_JUMP_IF_FALSE (0x37) // rel byte code offset, 16-bit signed, in excess + 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 @@ -62,44 +95,172 @@ bytecodes = { #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 -#define MP_BC_POP_BLOCK (0x44) + 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 -#define MP_BC_GET_ITER_STACK (0x47) + 0x47: {"name": "MP_BC_GET_ITER_STACK", + "format": "MP_OPCODE_BYTE"}, -#define MP_BC_BUILD_TUPLE (0x50) // uint -#define MP_BC_BUILD_LIST (0x51) // uint -#define MP_BC_BUILD_MAP (0x53) // uint -#define MP_BC_STORE_MAP (0x54) + + 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 -#define MP_BC_RETURN_VALUE (0x5b) -#define MP_BC_RAISE_VARARGS (0x5c) // byte + 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 -#define MP_BC_MAKE_FUNCTION_DEFARGS (0x61) // uint -#define MP_BC_MAKE_CLOSURE (0x62) // uint -#define MP_BC_MAKE_CLOSURE_DEFARGS (0x63) // uint -#define MP_BC_CALL_FUNCTION (0x64) // uint -#define MP_BC_CALL_FUNCTION_VAR_KW (0x65) // uint -#define MP_BC_CALL_METHOD (0x66) // uint -#define MP_BC_CALL_METHOD_VAR_KW (0x67) // uint - -#define MP_BC_IMPORT_NAME (0x68) // qstr + 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(<MP_UNARY_OP_NUM_BYTECODE) + + # // 9 relational operations, should return a bool + 0xd7: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_LESS", + "format": "MP_OPCODE_BYTE"}, + 0xd8: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_MORE", + "format": "MP_OPCODE_BYTE"}, + 0xd9: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_EQUAL", + "format": "MP_OPCODE_BYTE"}, + 0xda: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_LESS_EQUAL", + "format": "MP_OPCODE_BYTE"}, + 0xdb: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_MORE_EQUAL", + "format": "MP_OPCODE_BYTE"}, + 0xdc: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_NOT_EQUAL", + "format": "MP_OPCODE_BYTE"}, + # dc: MP_BINARY_OP_NOT_EQUAL, + # dd: MP_BINARY_OP_IN, + # de: MP_BINARY_OP_IS, + # df: MP_BINARY_OP_EXCEPTION_MATCH, + # + # // 12 inplace arithmetic operations + # e0: MP_BINARY_OP_INPLACE_OR, + # e1: MP_BINARY_OP_INPLACE_XOR, + # e2: MP_BINARY_OP_INPLACE_AND, + # e3: MP_BINARY_OP_INPLACE_LSHIFT, + # e4: MP_BINARY_OP_INPLACE_RSHIFT, + # e5: MP_BINARY_OP_INPLACE_ADD, + 0xe5: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_INPLACE_ADD", + "format": "MP_OPCODE_BYTE"}, + 0xe6: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_INPLACE_SUBTRACT", + "format": "MP_OPCODE_BYTE"}, + # e7: MP_BINARY_OP_INPLACE_MULTIPLY, + # e8: MP_BINARY_OP_INPLACE_FLOOR_DIVIDE, + # e9: MP_BINARY_OP_INPLACE_TRUE_DIVIDE, + # ea: MP_BINARY_OP_INPLACE_MODULO, + # eb: MP_BINARY_OP_INPLACE_POWER, + # + # // 12 normal arithmetic operations + # ec: MP_BINARY_OP_OR, + # ed: MP_BINARY_OP_XOR, + # ee: MP_BINARY_OP_AND, + # ef: MP_BINARY_OP_LSHIFT, + # f0: MP_BINARY_OP_RSHIFT, #define MP_BC_BINARY_OP_MULTI (0xd7) // + op(<MP_BINARY_OP_NUM_BYTECODE) + 0xf1: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_ADD", + "format": "MP_OPCODE_BYTE"}, + 0xf2: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_SUBTRACT", + "format": "MP_OPCODE_BYTE"}, + 0xf3: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_MULTIPLY", + "format": "MP_OPCODE_BYTE"}, + 0xf4: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_FLOOR_DIVIDE", + "format": "MP_OPCODE_BYTE"}, + 0xf5: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_TRUE_DIVIDE", + "format": "MP_OPCODE_BYTE"}, + 0xf6: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_MODULO", + "format": "MP_OPCODE_BYTE"}, + 0xf7: {"name": "MP_BC_BINARY_OP_MULTI MP_BINARY_OP_POWER", + "format": "MP_OPCODE_BYTE"}, } def read_uint(encoded_uint, peek=False): @@ -149,40 +310,94 @@ class RawCode: def __init__(self, encoded_raw_code): bc_len = read_uint(encoded_raw_code) bc = encoded_raw_code.read(bc_len) - prelude = Prelude(io.BufferedReader(io.BytesIO(bc))) - encoded_code_info = bc[:prelude.code_info_size] - bc_start = prelude.code_info_size - while bc[bc_start] == 0xff: - bc_start += 1 - bc = bc[bc_start:] + bc = io.BufferedReader(io.BytesIO(bc)) + prelude = Prelude(bc) + encoded_code_info = bc.read(prelude.code_info_size) + bc.read(1) + while bc.peek(1)[0] == 0xff: + bc.read(1) + bc = bytearray(bc.read()) + #print(encoded_code_info, bc) self.qstrs = [] self.simple_name = self._load_qstr(encoded_raw_code) self.source_file = self._load_qstr(encoded_raw_code) # the simple name and source file qstr indexes get written back into the byte code somehow + #print(bc) self._load_bytecode_qstrs(encoded_raw_code, bc) + + #print(encoded_raw_code.peek(20)[:20]) + + n_obj = read_uint(encoded_raw_code) + n_raw_code = read_uint(encoded_raw_code) + + self.const_table = [] + for i in range(prelude.n_pos_args + prelude.n_kwonly_args): + self.const_table.append(self._load_qstr(encoded_raw_code)) + print("load args", self.const_table[-1]) + for i in range(n_obj): + self.const_table.append(self._load_obj(encoded_raw_code)) + print("load obj", self.const_table[-1]) + for i in range(n_raw_code): + print("load raw code") + self.const_table.append(RawCode(encoded_raw_code)) + print(self.qstrs[self.simple_name], self.qstrs[self.source_file]) - print(binascii.hexlify(encoded_raw_code.peek(20)[:20])) + #print(binascii.hexlify(encoded_raw_code.peek(20)[:20])) def _load_qstr(self, encoded_qstr): string_len = read_uint(encoded_qstr) string = encoded_qstr.read(string_len).decode("utf-8") + print(string) if string in self.qstrs: - return self.qstr.index(string) + return self.qstrs.index(string) new_index = len(self.qstrs) self.qstrs.append(string) return new_index - def _load_bytecode_qstrs(encoded_raw_code, bytecode): + def _load_obj(self, encoded_obj): + obj_type = encoded_obj.read(1) + if obj_type == b'e': + return "..." + else: + str_len = read_uint(encoded_obj) + s = encoded_obj.read(str_len) + if obj_type == b's': + return s.decode("utf-8") + elif obj_type == b'b': + return s + elif obj_type == b'i': + return int(s) + elif obj_type == b'f': + return float(s) + elif obj_type == b'c': + return float(s) + raise RuntimeError("Unknown object type {}".format(obj_type)) + + def _load_bytecode_qstrs(self, encoded_raw_code, bytecode): i = 0 while i < len(bytecode): - opcode, opcode_size = mp_opcode_format(bytecode[i]) - if opcode == MP_OPCODE_QSTR: + bc = bytecode[i] + if bc not in bytecodes: + raise RuntimeError("missing code 0x{:x} at {}".format(bc, i)) + return + bc = bytecodes[bc] + opcode = bc["name"] + print(opcode) + opcode_size = bytecode_format_sizes[bc["format"]] + if bc["format"] == "MP_OPCODE_QSTR": qstr_index = self._load_qstr(encoded_raw_code) bytecode[i+1] = qstr_index bytecode[i+2] = qstr_index >> 8 - opcode += opcode_size + 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): |
