opcode_2x.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. # (C) Copyright 2018, 2020-2024 by Rocky Bernstein
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software
  15. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. """CPython core set of bytecode opcodes based on version 2.3
  17. This is used in bytecode disassembly among other things. This is
  18. similar to the opcodes in Python's opcode.py library.
  19. If this file changes the other opcode files may have to be adjusted accordingly.
  20. """
  21. from typing import Optional, Tuple
  22. from xdis.opcodes.base import (
  23. binary_op,
  24. call_op,
  25. compare_op,
  26. const_op,
  27. def_op,
  28. free_op,
  29. init_opdata,
  30. jabs_op,
  31. jrel_op,
  32. local_op,
  33. name_op,
  34. nargs_op,
  35. store_op,
  36. ternary_op,
  37. unary_op,
  38. varargs_op,
  39. )
  40. from xdis.opcodes.format.basic import format_MAKE_FUNCTION_10_27, opcode_arg_fmt_base
  41. from xdis.opcodes.format.extended import (
  42. get_arglist,
  43. get_instruction_arg,
  44. opcode_extended_fmt_base,
  45. )
  46. loc = locals()
  47. init_opdata(loc, None, None)
  48. # Instruction opcodes for compiled code
  49. # Blank lines correspond to available opcodes
  50. # If the POP field is -1 and the opcode is var args operation
  51. # (hasvargs | hasnargs) operation, then
  52. # the operand holds the size.
  53. # fmt: off
  54. # OP NAME OPCODE POP PUSH
  55. #-----------------------------------------------
  56. def_op(loc, "STOP_CODE", 0, 0, 0, fallthrough=False)
  57. def_op(loc, "POP_TOP", 1, 1, 0)
  58. def_op(loc, "ROT_TWO", 2, 2, 2)
  59. def_op(loc, "ROT_THREE", 3, 3, 3)
  60. def_op(loc, "DUP_TOP", 4, 0, 1)
  61. def_op(loc, "ROT_FOUR", 5, 4, 4)
  62. unary_op(loc, "UNARY_POSITIVE", 10)
  63. unary_op(loc, "UNARY_NEGATIVE", 11)
  64. unary_op(loc, "UNARY_NOT", 12)
  65. unary_op(loc, "UNARY_CONVERT", 13)
  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_DIVIDE", 21)
  70. binary_op(loc, "BINARY_MODULO", 22)
  71. binary_op(loc, "BINARY_ADD", 23)
  72. binary_op(loc, "BINARY_SUBTRACT", 24)
  73. binary_op(loc, "BINARY_SUBSCR", 25)
  74. binary_op(loc, "BINARY_FLOOR_DIVIDE", 26)
  75. binary_op(loc, "BINARY_TRUE_DIVIDE", 27)
  76. binary_op(loc, "INPLACE_FLOOR_DIVIDE", 28)
  77. binary_op(loc, "INPLACE_TRUE_DIVIDE", 29)
  78. unary_op(loc, "SLICE+0", 30)
  79. binary_op(loc, "SLICE+1", 31)
  80. binary_op(loc, "SLICE+2", 32)
  81. ternary_op(loc, "SLICE+3", 33)
  82. # OP NAME OPCODE POP PUSH
  83. #-----------------------------------------------
  84. store_op(loc, "STORE_SLICE+0", 40, 2, 0)
  85. store_op(loc, "STORE_SLICE+1", 41, 3, 0)
  86. store_op(loc, "STORE_SLICE+2", 42, 3, 0)
  87. store_op(loc, "STORE_SLICE+3", 43, 4, 0)
  88. def_op(loc, "DELETE_SLICE+0", 50, 1, 0)
  89. def_op(loc, "DELETE_SLICE+1", 51, 2, 0)
  90. def_op(loc, "DELETE_SLICE+2", 52, 2, 0)
  91. def_op(loc, "DELETE_SLICE+3", 53, 3, 0)
  92. binary_op(loc, "INPLACE_ADD", 55)
  93. binary_op(loc, "INPLACE_SUBTRACT", 56)
  94. binary_op(loc, "INPLACE_MULTIPLY", 57)
  95. binary_op(loc, "INPLACE_DIVIDE", 58)
  96. binary_op(loc, "INPLACE_MODULO", 59)
  97. store_op(loc, "STORE_SUBSCR", 60, 3, 0) # Implements TOS1[TOS] = TOS2.
  98. def_op(loc, "DELETE_SUBSCR", 61, 2, 0) # Implements del TOS1[TOS].
  99. binary_op(loc, "BINARY_LSHIFT", 62)
  100. binary_op(loc, "BINARY_RSHIFT", 63)
  101. binary_op(loc, "BINARY_AND", 64)
  102. binary_op(loc, "BINARY_XOR", 65)
  103. binary_op(loc, "BINARY_OR", 66)
  104. binary_op(loc, "INPLACE_POWER", 67)
  105. def_op(loc, "GET_ITER", 68, 1, 1)
  106. def_op(loc, "PRINT_EXPR", 70, 1, 0)
  107. def_op(loc, "PRINT_ITEM", 71, 1, 0)
  108. def_op(loc, "PRINT_NEWLINE", 72, 0, 0)
  109. def_op(loc, "PRINT_ITEM_TO", 73, 2, 0)
  110. def_op(loc, "PRINT_NEWLINE_TO", 74, 1, 0)
  111. def_op(loc, "INPLACE_LSHIFT", 75, 2, 1)
  112. def_op(loc, "INPLACE_RSHIFT", 76, 2, 1)
  113. def_op(loc, "INPLACE_AND", 77, 2, 1)
  114. def_op(loc, "INPLACE_XOR", 78, 2, 1)
  115. def_op(loc, "INPLACE_OR", 79, 2, 1)
  116. def_op(loc, "BREAK_LOOP", 80, 0, 0, fallthrough=False)
  117. def_op(loc, "LOAD_LOCALS", 82, 0, 1)
  118. def_op(loc, "RETURN_VALUE", 83, 1, 0, fallthrough=False)
  119. def_op(loc, "IMPORT_STAR", 84, 1, 0)
  120. def_op(loc, "EXEC_STMT", 85, 3, 0)
  121. def_op(loc, "YIELD_VALUE", 86, 1, 1)
  122. def_op(loc, "POP_BLOCK", 87, 0, 0)
  123. def_op(loc, "END_FINALLY", 88, 1, 0)
  124. def_op(loc, "BUILD_CLASS", 89, 2, 0)
  125. HAVE_ARGUMENT = 90 # Opcodes from here have an argument:
  126. # OP NAME OPCODE POP PUSH
  127. #-----------------------------------------------
  128. store_op(loc, "STORE_NAME", 90, 1, 0, is_type="name")
  129. # Operand is in name list
  130. name_op(loc, "DELETE_NAME", 91, 0, 0) # ""
  131. varargs_op(loc, "UNPACK_SEQUENCE", 92, -1, 1) # TOS is number of tuple items
  132. jrel_op(loc, "FOR_ITER", 93, 0, 1) # TOS is read
  133. store_op(loc, "STORE_ATTR", 95, 2, 0, is_type="name")
  134. # Operand is in name list
  135. name_op(loc, "DELETE_ATTR", 96, 1, 0) # ""
  136. store_op(loc, "STORE_GLOBAL", 97, 1, 0, is_type="name") # ""
  137. name_op(loc, "DELETE_GLOBAL", 98, 0, 0) # ""
  138. nargs_op(loc, "DUP_TOPX", 99, -1, 2) # number of items to duplicate
  139. const_op(loc, "LOAD_CONST", 100, 0, 1) # Operand is in const list
  140. loc["nullaryloadop"].add(100)
  141. loc["nullaryloadop"].add(100)
  142. name_op(loc, "LOAD_NAME", 101, 0, 1) # Operand is in name list
  143. loc["nullaryloadop"].add(101)
  144. varargs_op(loc, "BUILD_TUPLE", 102, -1, 1) # TOS is number of tuple items
  145. varargs_op(loc, "BUILD_LIST", 103, -1, 1) # TOS is number of list items
  146. varargs_op(loc, "BUILD_MAP", 104, 0, 1) # TOS is number of kwarg items.
  147. # Always zero for now
  148. name_op(loc, "LOAD_ATTR", 105, 1, 1) # Operand is in name list
  149. compare_op(loc, "COMPARE_OP", 106, 2, 1) # Comparison operator
  150. name_op(loc, "IMPORT_NAME", 107, 0, 1) # For < 2.6; Imports namei; module
  151. # pushed
  152. name_op(loc, "IMPORT_FROM", 108, 0, 1) # Operand is in name list
  153. jrel_op(loc, "JUMP_FORWARD", 110, 0, 0, fallthrough=False)
  154. # Number of bytes to skip
  155. jrel_op(loc, "JUMP_IF_FALSE", 111, 1, 1, True) # ""
  156. jrel_op(loc, "JUMP_IF_TRUE", 112, 1, 1, True) # ""
  157. jabs_op(loc, "JUMP_ABSOLUTE", 113, 0, 0, fallthrough=False)
  158. # Target byte offset from beginning of
  159. #code
  160. name_op(loc, "LOAD_GLOBAL", 116, 0, 1) # Operand is in name list
  161. loc["nullaryloadop"].add(116)
  162. jabs_op(loc, "CONTINUE_LOOP", 119, 0, 0, fallthrough=False) # Target address
  163. jrel_op(loc, "SETUP_LOOP", 120, 0, 0, conditional=True) # Distance to
  164. # target address
  165. jrel_op(loc, "SETUP_EXCEPT", 121, 0, 3, conditional=True) # ""
  166. jrel_op(loc, "SETUP_FINALLY", 122, 0, 3, conditional=True) # ""
  167. local_op(loc, "LOAD_FAST", 124, 0, 1) # Local variable number
  168. loc["nullaryloadop"].add(124)
  169. store_op(loc, "STORE_FAST", 125, 1, 0, is_type="local") # Local variable
  170. # number
  171. local_op(loc, "DELETE_FAST", 126, 0, 0) # Local variable number is in operand
  172. nargs_op(loc, "RAISE_VARARGS", 130, -1, 2, fallthrough=False)
  173. # Number of raise arguments (1, 2, or 3)
  174. call_op(loc, "CALL_FUNCTION", 131, -1, 2) # TOS is #args + (#kwargs << 8)
  175. nargs_op(loc, "MAKE_FUNCTION", 132, -1, 2) # TOS is number of args with
  176. # default values
  177. varargs_op(loc, "BUILD_SLICE", 133, 2, 1) # TOS is number of items
  178. def_op(loc, "MAKE_CLOSURE", 134, -3, 1)
  179. free_op(loc, "LOAD_CLOSURE", 135, 0, 1) # Load of a closured variable
  180. loc["nullaryloadop"].add(135)
  181. free_op(loc, "LOAD_DEREF", 136, 0, 1)
  182. loc["nullaryop"].add(136)
  183. loc["nullaryloadop"].add(136)
  184. store_op(loc, "STORE_DEREF", 137, 1, 0, is_type="free")
  185. call_op(loc, "CALL_FUNCTION_VAR", 140, -2, 1) # #args + (#kwargs << 8)
  186. call_op(loc, "CALL_FUNCTION_KW", 141, -2, 1) # #args + (#kwargs << 8)
  187. call_op(loc, "CALL_FUNCTION_VAR_KW", 142, -3, 1) # #args + (#kwargs << 8)
  188. def_op(loc, "EXTENDED_ARG", 143)
  189. # fmt: on
  190. EXTENDED_ARG = 143
  191. def extended_format_BUILD_MAP_older(
  192. opc, instructions: list
  193. ) -> Tuple[str, Optional[int]]:
  194. arg_count = instructions[0].argval
  195. if arg_count == 0:
  196. # Note: caller generally handles this when the below isn't right.
  197. return "{}", instructions[0].offset
  198. arglist, _, i = get_arglist(instructions, 0, arg_count)
  199. # from trepan.api import debug; debug()
  200. if arglist is not None:
  201. assert isinstance(i, int)
  202. arg_pairs = [f"{arglist[i]}:{arglist[i+1]}" for i in range(len(arglist), 2)]
  203. args_str = ", ".join(arg_pairs)
  204. return "{" + args_str + "}", instructions[i].start_offset
  205. return "", None
  206. def extended_format_PRINT_ITEM(opc, instructions: list) -> Tuple[str, Optional[int]]:
  207. instr1 = instructions[1]
  208. print_arg = get_instruction_arg(instr1)
  209. return (
  210. f"print {print_arg},",
  211. instr1.start_offset,
  212. )
  213. def extended_format_SLICE_0(opc, instructions: list) -> Tuple[str, Optional[int]]:
  214. arglist, arg_count, i = get_arglist(instructions, 0, 1)
  215. if arg_count == 1 and arglist is not None:
  216. return f"{arglist[0]}[:]", instructions[0].start_offset
  217. return "", None
  218. def extended_format_SLICE_1(opc, instructions: list) -> Tuple[str, Optional[int]]:
  219. arglist, arg_count, i = get_arglist(instructions, 0, 2)
  220. if arg_count == 2 and arglist is not None:
  221. return f"{arglist[1]}[{arglist[0]}:]", instructions[i].start_offset
  222. return "", None
  223. def extended_format_SLICE_2(opc, instructions: list) -> Tuple[str, Optional[int]]:
  224. arglist, arg_count, i = get_arglist(instructions, 0, 2)
  225. if arg_count == 2 and i is not None and arglist is not None:
  226. return f"{arglist[1]}[:{arglist[0]}]", instructions[i].start_offset
  227. return "", None
  228. def extended_format_SLICE_3(opc, instructions: list) -> Tuple[str, Optional[int]]:
  229. arglist, arg_count, i = get_arglist(instructions, 0, 3)
  230. if arg_count == 3 and i is not None and arglist is not None:
  231. arglist = ["" if arg == "None" else arg for arg in arglist]
  232. return f"{arglist[2]}[{arglist[1]}:{arglist[0]}]", instructions[i].start_offset
  233. if instructions[0].argval == 0:
  234. # Degenerate case
  235. return "set()", instructions[0].start_offset
  236. return "", None
  237. def format_PRINT_NEWLINE(arg) -> str:
  238. return 'print "\\n"'
  239. update_arg_fmt_base2x = {
  240. **opcode_arg_fmt_base,
  241. **{
  242. "MAKE_FUNCTION": format_MAKE_FUNCTION_10_27,
  243. "PRINT_NEWLINE": format_PRINT_NEWLINE,
  244. },
  245. }
  246. opcode_extended_fmt_base2x = {
  247. **opcode_extended_fmt_base,
  248. **{
  249. # "BUILD_MAP": extended_format_BUILD_MAP_older,
  250. "PRINT_ITEM": extended_format_PRINT_ITEM,
  251. "SLICE+0": extended_format_SLICE_0,
  252. "SLICE+1": extended_format_SLICE_1,
  253. "SLICE+2": extended_format_SLICE_2,
  254. "SLICE+3": extended_format_SLICE_3,
  255. },
  256. }