opcode_3x.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. # (C) Copyright 2017-2018, 2020-2021, 2023-2024
  2. # by Rocky Bernstein
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. """
  18. CPython 3.2 bytecode opcodes to be used as a base for other opcodes including 3.2.
  19. This is used in bytecode disassembly among other things. This is
  20. similar to the opcodes in Python's opcode.py library.
  21. If this file changes the other opcode files may have to be adjusted accordingly.
  22. """
  23. from typing import Optional, Tuple
  24. from xdis.opcodes.base import (
  25. binary_op,
  26. call_op,
  27. compare_op,
  28. const_op,
  29. def_op,
  30. free_op,
  31. init_opdata,
  32. jabs_op,
  33. jrel_op,
  34. local_op,
  35. name_op,
  36. nargs_op,
  37. store_op,
  38. unary_op,
  39. varargs_op,
  40. )
  41. from xdis.opcodes.format.basic import format_extended_arg
  42. from xdis.opcodes.format.extended import opcode_extended_fmt_base, short_code_repr
  43. loc = locals()
  44. init_opdata(loc, None, None)
  45. # Instruction opcodes for compiled code
  46. # Blank lines correspond to available opcodes
  47. # If the POP field is -1 and the opcode is a var args operation
  48. # then the operand holds the size.
  49. #
  50. # If the POP field is negative and the opcode is a nargs operation
  51. # then pop the operand amount plus the negative of the POP amount.
  52. # fmt: off
  53. # OP NAME OPCODE POP PUSH
  54. #--------------------------------------------------
  55. def_op(loc, "STOP_CODE", 0, 0, 0, fallthrough=False)
  56. def_op(loc, "POP_TOP", 1, 1, 0)
  57. def_op(loc, "ROT_TWO", 2, 2, 2)
  58. def_op(loc, "ROT_THREE", 3, 3, 3)
  59. def_op(loc, "DUP_TOP", 4, 0, 1)
  60. # Python 3.2+
  61. def_op(loc, "DUP_TOP_TWO", 5, 0, 2)
  62. def_op(loc, "NOP", 9, 0, 0)
  63. unary_op(loc, "UNARY_POSITIVE", 10)
  64. unary_op(loc, "UNARY_NEGATIVE", 11)
  65. unary_op(loc, "UNARY_NOT", 12)
  66. unary_op(loc, "UNARY_INVERT", 15)
  67. binary_op(loc, "BINARY_POWER", 19)
  68. binary_op(loc, "BINARY_MULTIPLY", 20)
  69. binary_op(loc, "BINARY_MODULO", 22)
  70. binary_op(loc, "BINARY_ADD", 23)
  71. binary_op(loc, "BINARY_SUBTRACT", 24)
  72. binary_op(loc, "BINARY_SUBSCR", 25)
  73. binary_op(loc, "BINARY_FLOOR_DIVIDE", 26)
  74. binary_op(loc, "BINARY_TRUE_DIVIDE", 27)
  75. binary_op(loc, "INPLACE_FLOOR_DIVIDE", 28)
  76. binary_op(loc, "INPLACE_TRUE_DIVIDE", 29)
  77. # Gone from Python 3 are Python2's
  78. # SLICE+0 ... SLICE+3
  79. # STORE_SLICE+0 ... STORE_SLICE+3
  80. # DELETE_SLICE+0 ... DELETE_SLICE+3
  81. # OP NAME OPCODE POP PUSH
  82. #-----------------------------------------------
  83. store_op(loc, "STORE_MAP", 54, 3, 1)
  84. binary_op(loc, "INPLACE_ADD", 55, 2, 1)
  85. binary_op(loc, "INPLACE_SUBTRACT", 56, 2, 1)
  86. binary_op(loc, "INPLACE_MULTIPLY", 57, 2, 1)
  87. binary_op(loc, "INPLACE_MODULO", 59, 2, 1)
  88. store_op(loc, "STORE_SUBSCR", 60, 3, 0) # Implements TOS1[TOS] = TOS2.
  89. def_op(loc, "DELETE_SUBSCR", 61, 2, 0) # Implements del TOS1[TOS].
  90. binary_op(loc, "BINARY_LSHIFT", 62)
  91. binary_op(loc, "BINARY_RSHIFT", 63)
  92. binary_op(loc, "BINARY_AND", 64)
  93. binary_op(loc, "BINARY_XOR", 65)
  94. binary_op(loc, "BINARY_OR", 66)
  95. binary_op(loc, "INPLACE_POWER", 67)
  96. def_op(loc, "GET_ITER", 68, 1, 1)
  97. store_op(loc, "STORE_LOCALS", 69, 1, 0)
  98. def_op(loc, "PRINT_EXPR", 70, 1, 0)
  99. unary_op(loc, "LOAD_BUILD_CLASS", 71, 0, 1)
  100. # Python3 drops/changes:
  101. # def_op(loc, "PRINT_ITEM", 71)
  102. # def_op(loc, "PRINT_NEWLINE", 72)
  103. # def_op(loc, "PRINT_ITEM_TO", 73)
  104. # def_op(loc, "PRINT_NEWLINE_TO", 74)
  105. binary_op(loc, "INPLACE_LSHIFT", 75)
  106. binary_op(loc, "INPLACE_RSHIFT", 76)
  107. binary_op(loc, "INPLACE_AND", 77)
  108. binary_op(loc, "INPLACE_XOR", 78)
  109. binary_op(loc, "INPLACE_OR", 79)
  110. def_op(loc, "BREAK_LOOP", 80, 0, 0, fallthrough=False)
  111. def_op(loc, "WITH_CLEANUP", 81, 1, 0) # Cleans up the stack when a with statement
  112. # block exits. Handle stack special
  113. def_op(loc, "RETURN_VALUE", 83, 1, 0, fallthrough=False)
  114. def_op(loc, "IMPORT_STAR", 84, 1, 0)
  115. def_op(loc, "YIELD_VALUE", 86, 1, 1)
  116. def_op(loc, "POP_BLOCK", 87, 0, 0)
  117. def_op(loc, "END_FINALLY", 88, 1, 0)
  118. def_op(loc, "POP_EXCEPT", 89, 0, 0)
  119. HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
  120. # OP NAME OPCODE POP PUSH
  121. #-----------------------------------------------
  122. store_op(loc, "STORE_NAME", 90, 1, 0, is_type="name") # Operand is in name list
  123. name_op(loc, "DELETE_NAME", 91, 0, 0) # ""
  124. varargs_op(loc, "UNPACK_SEQUENCE", 92, 0, -1) # unpacks TOS, arg is the count
  125. jrel_op(loc, "FOR_ITER", 93, 0, 1)
  126. varargs_op(loc, "UNPACK_EX", 94, 0, 0) # assignment with a starred target; arg is count
  127. store_op(loc, "STORE_ATTR", 95, 2, 0, is_type="name") # Operand is in name list
  128. name_op(loc, "DELETE_ATTR", 96, 1, 0) # ""
  129. store_op(loc, "STORE_GLOBAL", 97, 1, 0, is_type="name") # ""
  130. name_op(loc, "DELETE_GLOBAL", 98, 0, 0) # ""
  131. # Python 2"s DUP_TOPX is gone starting in Python 3.2
  132. # OP NAME OPCODE POP PUSH
  133. #-----------------------------------------------
  134. const_op(loc, "LOAD_CONST", 100, 0, 1) # Operand is in const list
  135. loc["nullaryloadop"].add(100)
  136. name_op(loc, "LOAD_NAME", 101, 0, 1) # Operand is in name list
  137. loc["nullaryloadop"].add(101)
  138. varargs_op(loc, "BUILD_TUPLE", 102, -1, 1) # TOS is count of tuple items
  139. varargs_op(loc, "BUILD_LIST", 103, -1, 1) # TOS is count of list items
  140. varargs_op(loc, "BUILD_SET", 104, -1, 1) # TOS is count of set items
  141. varargs_op(loc, "BUILD_MAP", 105, 0, 1) # argument is dictionary count to be pushed
  142. name_op(loc, "LOAD_ATTR", 106, 1, 1) # Operand is in name list
  143. compare_op(loc, "COMPARE_OP", 107, 2, 1) # Comparison operator
  144. name_op(loc, "IMPORT_NAME", 108, 2, 1) # Imports TOS and TOS1; module pushed
  145. loc["nullaryloadop"].add(108)
  146. name_op(loc, "IMPORT_FROM", 109, 0, 1) # Operand is in name list
  147. jrel_op(loc, "JUMP_FORWARD", 110, 0, 0, fallthrough=False) # Number of bytes to skip
  148. jabs_op(loc, "JUMP_IF_FALSE_OR_POP", 111, conditional=True) # Target byte offset from beginning of code
  149. jabs_op(loc, "JUMP_IF_TRUE_OR_POP", 112, conditional=True) # ""
  150. jabs_op(loc, "JUMP_ABSOLUTE", 113, 0, 0, fallthrough=False) # Target byte offset from beginning of code
  151. jabs_op(loc, "POP_JUMP_IF_FALSE", 114, 2, 1, conditional=True) # ""
  152. jabs_op(loc, "POP_JUMP_IF_TRUE", 115, 2, 1, conditional=True) # ""
  153. name_op(loc, "LOAD_GLOBAL", 116, 0, 1) # Operand is in name list
  154. loc["nullaryloadop"].add(116)
  155. # OP NAME OPCODE POP PUSH
  156. #-----------------------------------------------
  157. jabs_op(loc, "CONTINUE_LOOP", 119, 0, 0, fallthrough=False) # Target address
  158. jrel_op(loc, "SETUP_LOOP", 120, 0, 0, conditional=True) # Distance to target address
  159. jrel_op(loc, "SETUP_EXCEPT", 121, 0, 6, conditional=True) # ""
  160. jrel_op(loc, "SETUP_FINALLY", 122, 0, 6, conditional=True) # ""
  161. local_op(loc, "LOAD_FAST", 124, 0, 1) # Local variable number
  162. loc["nullaryloadop"].add(124)
  163. store_op(loc, "STORE_FAST", 125, 1, 0, is_type="local") # Local variable number
  164. local_op(loc, "DELETE_FAST", 126, 0, 0) # Local variable number
  165. nargs_op(loc, "RAISE_VARARGS", 130, -1, 1, fallthrough=False)
  166. # Number of raise arguments (1, 2, or 3)
  167. call_op(loc, "CALL_FUNCTION", 131, -1, 1) # #args + (#kwargs << 8)
  168. nargs_op(loc, "MAKE_FUNCTION", 132, -2, 1) # TOS is number of args if < 3.6
  169. varargs_op(loc, "BUILD_SLICE", 133, 2, 1) # TOS is number of items to pop
  170. nargs_op(loc, "MAKE_CLOSURE", 134, -3, 1) # TOS is number of items to pop
  171. free_op(loc, "LOAD_CLOSURE", 135, 0, 1)
  172. loc["nullaryloadop"].add(135)
  173. loc["nullaryloadop"].add(136)
  174. free_op(loc, "LOAD_DEREF", 136, 0, 1)
  175. loc["nullaryloadop"].add(136)
  176. loc["nullaryop"].add(136)
  177. loc["nullaryloadop"].add(136)
  178. store_op(loc, "STORE_DEREF", 137, 1, 0, is_type="free")
  179. free_op(loc, "DELETE_DEREF", 138, 0, 0)
  180. # OP NAME OPCODE POP PUSH
  181. #-----------------------------------------------
  182. nargs_op(loc, "CALL_FUNCTION_VAR", 140, -2, 1) # #args + (#kwargs << 8)
  183. nargs_op(loc, "CALL_FUNCTION_KW", 141, -2, 1) # #args + (#kwargs << 8)
  184. nargs_op(loc, "CALL_FUNCTION_VAR_KW",142, -3, 1) # #args + (#kwargs << 8)
  185. jrel_op(loc, "SETUP_WITH", 143, 0, 7)
  186. def_op(loc, "LIST_APPEND", 145, 2, 1) # Calls list.append(TOS[-i], TOS).
  187. # Used to implement list comprehensions.
  188. def_op(loc, "SET_ADD", 146, 1, 0) # Calls set.add(TOS1[-i], TOS).
  189. # Used to implement set comprehensions.
  190. def_op(loc, "MAP_ADD", 147, 3, 1) # Calls dict.setitem(TOS1[-i], TOS, TOS1)
  191. # Used to implement dict comprehensions.
  192. def_op(loc, "EXTENDED_ARG", 144, 0, 0)
  193. # fmt: on
  194. EXTENDED_ARG = 144
  195. opcode_arg_fmt = {"EXTENDED_ARG": format_extended_arg}
  196. def extended_format_MAKE_FUNCTION_30_35(opc, instructions) -> Tuple[Optional[str], int]:
  197. """make_function_inst should be a "MAKE_FUNCTION" or "MAKE_CLOSURE" instruction. TOS
  198. should have the function or closure name.
  199. """
  200. # From opcode description: argc indicates the total number of
  201. # positional and keyword arguments. Sometimes the function name
  202. # is in the stack arg positions back.
  203. assert len(instructions) >= 2
  204. inst = instructions[0]
  205. assert inst.opname in ("MAKE_FUNCTION", "MAKE_CLOSURE")
  206. s = ""
  207. name_inst = instructions[1]
  208. start_offset = name_inst.offset
  209. if name_inst.opname in ("LOAD_CONST",):
  210. s += f"make_function({short_code_repr(name_inst.argval)}"
  211. return s, start_offset
  212. s += format_MAKE_FUNCTION_30_35(inst.argval)
  213. return s, start_offset
  214. def format_MAKE_FUNCTION_30_35(argc: int) -> str:
  215. pos_args, name_pair_args, annotate_args = parse_fn_counts_30_35(argc)
  216. if (pos_args, name_pair_args, annotate_args) == (0, 0, 0):
  217. return "No arguments"
  218. s = "%d positional, %d keyword only, %d annotated" % (
  219. pos_args,
  220. name_pair_args,
  221. annotate_args,
  222. )
  223. return s
  224. def parse_fn_counts_30_35(argc: int) -> Tuple[int, int, int]:
  225. """
  226. In Python 3.0 to 3.5 MAKE_CLOSURE and MAKE_FUNCTION encode
  227. arguments counts of positional, default + named, and annotation
  228. arguments a particular kind of encoding where each of
  229. the entry is a packed byte value of the lower 24 bits
  230. of ``argc``. The high bits of argc may have come from
  231. an EXTENDED_ARG instruction. Here, we unpack the values
  232. from the ``argc`` int and return a triple of the
  233. positional args, named_args, and annotation args.
  234. """
  235. annotate_count = (argc >> 16) & 0x7FFF
  236. # For some reason that I don't understand, annotate_args is off by one
  237. # when there is an EXENDED_ARG instruction from what is documented in
  238. # https://docs.python.org/3.4/library/dis.html#opcode-MAKE_CLOSURE
  239. if annotate_count > 1:
  240. annotate_count -= 1
  241. return ((argc & 0xFF), (argc >> 8) & 0xFF, annotate_count)
  242. opcode_extended_fmt_base3x = opcode_extended_fmt_base.copy()