Skip to content

Commit adde8c9

Browse files
author
rocky
committed
More formatting
* Add 3.11+ COPY formatting * Add ROT_THREE and ROT_FOUR * expand use of NULL_EXTENDED_OP
1 parent 10fec20 commit adde8c9

File tree

3 files changed

+48
-17
lines changed

3 files changed

+48
-17
lines changed

xdis/opcodes/format/basic.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ def format_RAISE_VARARGS_older(argc) -> str:
5858
return "exception, parameter, traceback"
5959
return ""
6060

61+
def format_ROT_FOUR(_: int) -> str:
62+
return "TOS, TOS1, TOS2, TOS3 = TOS1, TOS2, TOS3, TOS"
63+
64+
65+
def format_ROT_THREE(_: int) -> str:
66+
return "TOS, TOS1, TOS2 = TOS1, TOS2, TOS"
67+
68+
6169
def format_ROT_TWO(_: int) -> str:
6270
# We add a space at the end as a sentinal to use in get_instruction_tos_str()
6371
return "TOS, TOS1 = TOS1, TOS"
@@ -70,5 +78,7 @@ def format_ROT_TWO(_: int) -> str:
7078
"CALL_FUNCTION_VAR_KW": format_CALL_FUNCTION_pos_name_encoded,
7179
"EXTENDED_ARG": format_extended_arg,
7280
"RAISE_VARARGS": format_RAISE_VARARGS_older,
81+
"ROT_FOUR": format_ROT_FOUR,
82+
"ROT_THREE": format_ROT_THREE,
7383
"ROT_TWO": format_ROT_TWO,
7484
}

xdis/opcodes/format/extended.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def extended_format_binary_op(
6060
arg1_start_offset, instructions, 1
6161
)
6262
if i is None:
63-
return "", None
63+
return NULL_EXTENDED_OP
6464
j = skip_cache(instructions, i + 1)
6565
stack_inst2 = instructions[j]
6666
if (
@@ -79,7 +79,7 @@ def extended_format_binary_op(
7979
return fmt_str % (arg2, arg1), start_offset
8080
else:
8181
return fmt_str % ("...", arg1), None
82-
return "", None
82+
return NULL_EXTENDED_OP
8383

8484

8585
def extended_format_infix_binary_op(
@@ -103,7 +103,7 @@ def extended_format_infix_binary_op(
103103
if arg1_start_offset is not None:
104104
i = get_instruction_index_from_offset(arg1_start_offset, instructions, 1)
105105
if i is None:
106-
return "", None
106+
return NULL_EXTENDED_OP
107107
j = i + 1
108108
# 3.11+ has CACHE instructions
109109
while instructions[j].opname == "CACHE":
@@ -129,7 +129,7 @@ def extended_format_infix_binary_op(
129129
return f"{arg2}{op_str}{arg1}", start_offset
130130
else:
131131
return f"...{op_str}{arg1}", None
132-
return "", None
132+
return NULL_EXTENDED_OP
133133

134134

135135
def extended_format_store_op(
@@ -142,7 +142,7 @@ def extended_format_store_op(
142142
# are more complicated, so let's not try to figure this out.
143143
# This kind of things is best left for a decompiler.
144144
if inst.is_jump_target:
145-
return "", None
145+
return NULL_EXTENDED_OP
146146

147147
prev_inst = instructions[1]
148148
start_offset = prev_inst.offset
@@ -198,7 +198,7 @@ def extended_format_ternary_op(
198198
if arg1_start_offset is not None:
199199
i = get_instruction_index_from_offset(arg1_start_offset, instructions, 1)
200200
if i is None:
201-
return "", None
201+
return NULL_EXTENDED_OP
202202
j = skip_cache(instructions, i + 1)
203203
stack_inst2 = instructions[j]
204204
if (
@@ -229,7 +229,7 @@ def extended_format_ternary_op(
229229
return fmt_str % (arg2, arg1, arg3), start_offset
230230
else:
231231
return fmt_str % ("...", "...", "..."), None
232-
return "", None
232+
return NULL_EXTENDED_OP
233233

234234

235235
def extended_format_STORE_SUBSCR(
@@ -251,7 +251,7 @@ def extended_format_unary_op(
251251
return fmt_str % stack_arg.tos_str, start_offset
252252
if stack_arg.opcode in opc.operator_set:
253253
return fmt_str % stack_arg.argrepr, start_offset
254-
return "", None
254+
return NULL_EXTENDED_OP
255255

256256

257257
def extended_format_ATTR(
@@ -271,7 +271,7 @@ def extended_format_ATTR(
271271
f"{base}.{instructions[0].argrepr}",
272272
instr1.start_offset,
273273
)
274-
return "", None
274+
return NULL_EXTENDED_OP
275275

276276

277277
def extended_format_BINARY_ADD(
@@ -372,7 +372,7 @@ def extended_format_build_tuple_or_list(
372372
return f"{left_delim}{args_str},{right_delim}", instructions[i].start_offset
373373
else:
374374
return f"{left_delim}{args_str}{right_delim}", instructions[i].start_offset
375-
return "", None
375+
return NULL_EXTENDED_OP
376376

377377

378378
def extended_format_BUILD_CONST_KEY_MAP(opc, instructions):
@@ -393,7 +393,7 @@ def extended_format_BUILD_CONST_KEY_MAP(opc, instructions):
393393
arg_pairs.append(f"{key_values[i]}: {arglist[i]}")
394394
args_str = ", ".join(arg_pairs)
395395
return "{" + args_str + "}", instructions[i].start_offset
396-
return "", None
396+
return NULL_EXTENDED_OP
397397

398398

399399
def extended_format_BUILD_LIST(
@@ -426,7 +426,7 @@ def extended_format_BUILD_SLICE(
426426
if instructions[0].argval == 0:
427427
# Degenerate case
428428
return "set()", instructions[0].start_offset
429-
return "", None
429+
return NULL_EXTENDED_OP
430430

431431

432432
def extended_format_BUILD_TUPLE(
@@ -479,7 +479,7 @@ def extended_format_CALL_FUNCTION(opc, instructions) -> Tuple[str, Optional[int]
479479
arglist, arg_count, i = get_arglist(instructions, 0, arg_count)
480480

481481
if arglist is None:
482-
return "", None
482+
return NULL_EXTENDED_OP
483483

484484
assert i is not None
485485
if i >= len(instructions) - 1:
@@ -791,9 +791,9 @@ def get_instruction_arg(inst: Instruction, argval=None) -> str:
791791
def get_instruction_tos_str(inst: Instruction) -> str:
792792
if inst.tos_str is not None:
793793
argval = inst.tos_str
794-
argval_without_push = re.match(r"^push\((.+)\) ", argval)
794+
argval_without_push = re.match(r"^(?:push|copy)\((.+)\) ", argval)
795795
if argval_without_push:
796-
# remove surrounding "push(...)" string
796+
# remove surrounding "push(...) or copy(...)" string
797797
argval = argval_without_push.group(1)
798798
else:
799799
argval = inst.argrepr

xdis/opcodes/opcode_311.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@
3636
store_op,
3737
update_pj3,
3838
)
39-
from xdis.opcodes.format.extended import extended_format_binary_op
39+
from xdis.opcodes.format.extended import (
40+
NULL_EXTENDED_OP,
41+
extended_format_binary_op,
42+
extended_format_unary_op,
43+
)
4044
from xdis.opcodes.opcode_310 import opcode_arg_fmt310, opcode_extended_fmt310
4145

4246
version_tuple = (3, 11)
@@ -245,6 +249,21 @@ def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]:
245249
return extended_format_binary_op(opc, instructions, f"%s {opname} %s")
246250

247251

252+
def extended_format_COPY_OP(
253+
opc, instructions: List[Instruction]
254+
) -> Tuple[str, Optional[int]]:
255+
"""Try to extract TOS value and show that surrounded in a "push() ".
256+
The trailing space at the used as a sentinal for `get_instruction_tos_str()`
257+
which tries to remove the push() part when the operand value string is needed.
258+
"""
259+
260+
# We add a space at the end as a sentinal to use in get_instruction_tos_str()
261+
if instructions[1].optype not in ["jrel", "jabs"]:
262+
return extended_format_unary_op(opc, instructions, "copy(%s) ")
263+
else:
264+
return NULL_EXTENDED_OP
265+
266+
248267
def extended_format_SWAP(
249268
opc, instructions: List[Instruction]
250269
) -> Tuple[str, Optional[int]]:
@@ -263,12 +282,13 @@ def extended_format_SWAP(
263282
i = swap_instr.argval
264283
# s = ""
265284

266-
if (i is None or not (0 < i < len(instructions))):
285+
if i is None or not (0 < i < len(instructions)):
267286
return "", None
268287

269288
# To be continued
270289
return "", None
271290

291+
272292
def format_BINARY_OP(arg: int) -> str:
273293
return _nb_ops[arg][1]
274294

@@ -294,6 +314,7 @@ def format_SWAP_OP(arg: int) -> str:
294314
**opcode_extended_fmt310,
295315
**{
296316
"BINARY_OP": extended_format_BINARY_OP,
317+
"COPY": extended_format_COPY_OP,
297318
},
298319
}
299320

0 commit comments

Comments
 (0)