Skip to content

Commit ce34c23

Browse files
author
rocky
committed
Make a pass over extended formatting...
There is plenty more to do, but this is a start.
1 parent 5247082 commit ce34c23

File tree

9 files changed

+244
-258
lines changed

9 files changed

+244
-258
lines changed

xdis/disasm.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -385,15 +385,20 @@ def disassemble_file(
385385
def _test():
386386
"""Simple test program to disassemble a file."""
387387
argc = len(sys.argv)
388-
if argc != 2:
389-
if argc == 1 and xdis.PYTHON3:
388+
if argc == 1:
389+
if xdis.PYTHON3:
390390
fn = __file__
391391
else:
392-
sys.stderr.write("usage: %s [-|CPython compiled file]\n" % __file__)
392+
sys.stderr.write(
393+
"usage: %s [-|CPython compiled file [format]]\n" % __file__
394+
)
393395
sys.exit(2)
396+
elif argc == 3:
397+
fn, asm_format = sys.argv[1:3]
398+
disassemble_file(fn, asm_format=asm_format)
394399
else:
395400
fn = sys.argv[1]
396-
disassemble_file(fn)
401+
disassemble_file(fn)
397402

398403

399404
if __name__ == "__main__":

xdis/opcodes/format/extended.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,13 @@ def extended_format_unary_op(
235235
return "", None
236236

237237

238-
def extended_format_ATTR(opc, instructions: list) -> Optional[Tuple[str, int]]:
238+
def extended_format_ATTR(opc, instructions: list) -> Tuple[str, Optional[int]]:
239239
if instructions[1].opcode in opc.NAME_OPS | opc.CONST_OPS | opc.LOCAL_OPS:
240240
return (
241241
f"{instructions[0].argrepr}.{instructions[1].argrepr}",
242242
instructions[1].offset,
243243
)
244-
return None
244+
return "", None
245245

246246

247247
def extended_format_BINARY_ADD(opc, instructions: list) -> Tuple[str, Optional[int]]:
@@ -365,7 +365,7 @@ def extended_format_COMPARE_OP(opc, instructions: list) -> Tuple[str, Optional[i
365365
)
366366

367367

368-
def extended_format_CALL_FUNCTION(opc, instructions):
368+
def extended_format_CALL_FUNCTION(opc, instructions) -> Tuple[str, Optional[int]]:
369369
"""call_function_inst should be a "CALL_FUNCTION" instruction. Look in
370370
`instructions` to see if we can find a method name. If not we'll
371371
return None.
@@ -575,7 +575,6 @@ def get_arglist(
575575
576576
"""
577577
arglist = []
578-
i = 0
579578
inst = None
580579
n = len(instructions) - 1
581580
while arg_count > 0 and i < n:

xdis/opcodes/opcode_311.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
1+
# (C) Copyright 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.
117
"""
218
CPython 3.11 bytecode opcodes
319
420
This is like Python 3.11's opcode.py with some classification
521
of stack usage and information for formatting instructions.
622
"""
723

8-
from typing import Optional
24+
from typing import Optional, Tuple
925

1026
import xdis.opcodes.opcode_310 as opcode_310
1127
from xdis.opcodes.base import (
@@ -209,7 +225,7 @@
209225
# fmt: on
210226

211227

212-
def extended_format_BINARY_OP(opc, instructions) -> Optional[str]:
228+
def extended_format_BINARY_OP(opc, instructions) -> Tuple[str, Optional[int]]:
213229
opname = _nb_ops[instructions[0].argval][1]
214230
if opname == "%":
215231
opname = "%%"
@@ -254,7 +270,7 @@ def format_BINARY_OP(arg) -> str:
254270
del opcode_extended_fmt311["BINARY_XOR"]
255271
del opcode_extended_fmt311["CALL_FUNCTION"]
256272
del opcode_extended_fmt311["CALL_FUNCTION_KW"]
257-
del opcode_extended_fmt311["CALL_METHOD"]
273+
# del opcode_extended_fmt311["CALL_METHOD"]
258274
del opcode_extended_fmt311["INPLACE_ADD"]
259275
del opcode_extended_fmt311["INPLACE_AND"]
260276
del opcode_extended_fmt311["INPLACE_FLOOR_DIVIDE"]

xdis/opcodes/opcode_36.py

Lines changed: 42 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
# (C) Copyright 2016-2017, 2019-2021, 2023 by Rocky Bernstein
1+
# (C) Copyright 2016-2017, 2019-2021, 2023-2024
2+
# by Rocky Bernstein
23
#
34
# This program is free software; you can redistribute it and/or
45
# modify it under the terms of the GNU General Public License
@@ -20,7 +21,7 @@
2021
of stack usage.
2122
"""
2223

23-
from typing import Tuple
24+
from typing import Optional, Tuple
2425

2526
import xdis.opcodes.opcode_35 as opcode_35
2627
from xdis.opcodes.base import (
@@ -231,34 +232,7 @@ def format_BUILD_MAP_UNPACK_WITH_CALL(count):
231232
# since they make use of the information there.
232233

233234

234-
def extended_format_CALL_METHOD(opc, instructions) -> str:
235-
"""Inst should be a "LOAD_METHOD" instruction. Looks in `instructions`
236-
to see if we can find a method name. If not we'll return "".
237-
238-
"""
239-
# From opcode description: Loads a method named co_names[namei] from the TOS object.
240-
# Sometimes the method name is in the stack arg positions back.
241-
call_method_inst = instructions[0]
242-
assert call_method_inst.opname == "CALL_METHOD"
243-
method_pos = call_method_inst.arg + 1
244-
assert len(instructions) >= method_pos
245-
s = ""
246-
for inst in instructions[1:method_pos]:
247-
# Make sure we are in the same basic block
248-
# and ... ?
249-
if inst.opname in ("CALL_METHOD",) or inst.is_jump_target:
250-
break
251-
pass
252-
else:
253-
if instructions[method_pos].opname == "LOAD_METHOD":
254-
s += "%s: " % instructions[method_pos].argrepr
255-
pass
256-
pass
257-
s += format_CALL_FUNCTION(call_method_inst.arg)
258-
return s
259-
260-
261-
def extended_format_CALL_FUNCTION36(opc, instructions):
235+
def extended_format_CALL_FUNCTION36(opc, instructions) -> Tuple[str, Optional[int]]:
262236
"""call_function_inst should be a "CALL_FUNCTION" instruction. Look in
263237
`instructions` to see if we can find a method name. If not we'll
264238
return None.
@@ -289,7 +263,7 @@ def extended_format_CALL_FUNCTION36(opc, instructions):
289263
return "", None
290264

291265

292-
def extended_format_CALL_FUNCTION_KW(opc, instructions):
266+
def extended_format_CALL_FUNCTION_KW(opc, instructions) -> Tuple[str, Optional[int]]:
293267
"""call_function_inst should be a "CALL_FUNCTION_KW" instruction. Look in
294268
`instructions` to see if we can find a method name. If not we'll
295269
return None.
@@ -298,41 +272,44 @@ def extended_format_CALL_FUNCTION_KW(opc, instructions):
298272
# From opcode description: argc indicates the total number of
299273
# positional and keyword arguments. Sometimes the function name
300274
# is in the stack arg positions back.
301-
call_function_inst = instructions[0]
302-
assert call_function_inst.opname == "CALL_FUNCTION_KW"
303-
function_pos = call_function_inst.arg
304-
assert len(instructions) >= function_pos + 1
305-
load_const = instructions[1]
306-
if load_const.opname == "LOAD_CONST" and isinstance(load_const.argval, tuple):
307-
function_pos += len(load_const.argval) + 1
308-
s = ""
309-
i = -1
310-
for i, inst in enumerate(instructions[2:]):
311-
if i == function_pos:
312-
break
313-
if inst.is_jump_target:
314-
i += 1
315-
break
316-
# Make sure we are in the same basic block
317-
# and ... ?
318-
opcode = inst.opcode
319-
if inst.optype in ("nargs", "vargs"):
320-
break
321-
if inst.optype != "name":
322-
function_pos += (oppop[opcode] - oppush[opcode]) + 1
323-
if inst.opname in ("CALL_FUNCTION", "CALL_FUNCTION_KW"):
324-
break
325-
pass
275+
# From opcode description: arg_count indicates the total number of
276+
# positional and keyword arguments.
326277

327-
if i == function_pos:
328-
if instructions[function_pos].opname in opc.NAME_OPS | opc.CONST_OPS:
329-
if instructions[function_pos].opname == "LOAD_ATTR":
330-
s += "."
331-
s += "%s() " % instructions[function_pos].argrepr
332-
pass
333-
pass
334-
s += format_CALL_FUNCTION(call_function_inst.arg)
335-
return s
278+
call_inst = instructions[0]
279+
arg_count = call_inst.argval
280+
keywords = instructions[1].argval
281+
s = ""
282+
283+
arglist, arg_count, i = get_arglist(instructions, 1, arg_count)
284+
285+
if arg_count != 0:
286+
return "", None
287+
288+
assert i is not None
289+
if i >= len(instructions) - 1:
290+
return "", None
291+
292+
fn_inst = instructions[i + 1]
293+
start_offset = instructions[i].start_offset
294+
if fn_inst.opcode in opc.operator_set:
295+
if instructions[1].opname == "MAKE_FUNCTION" and opc.version_tuple >= (3, 3):
296+
arglist[0] = instructions[2].argval
297+
298+
fn_name = fn_inst.tos_str if fn_inst.tos_str else fn_inst.argrepr
299+
# Note, 3.5 and 3.4 and before work slightly different with respect
300+
# to placement of keyword values, and order of arguments.
301+
arglist.reverse()
302+
for i in range(len(keywords)):
303+
j = -(i + 1)
304+
param_name = keywords[j]
305+
arglist[j] = f"{param_name}={arglist[j]}"
306+
307+
str_arglist = ", ".join(arglist)
308+
if len(str_arglist) > 30:
309+
str_arglist = str_arglist[:27] + "..."
310+
s = f"{fn_name}({str_arglist})"
311+
return s, start_offset
312+
return "", None
336313

337314

338315
opcode_arg_fmt = opcode_arg_fmt36 = {
@@ -355,7 +332,6 @@ def extended_format_CALL_FUNCTION_KW(opc, instructions):
355332
**{
356333
"CALL_FUNCTION_KW": extended_format_CALL_FUNCTION_KW,
357334
# "CALL_FUNCTION_VAR": extended_format_CALL_FUNCTION,
358-
"CALL_METHOD": extended_format_CALL_METHOD,
359335
"MAKE_FUNCTION": extended_format_MAKE_FUNCTION_36,
360336
"RAISE_VARARGS": extended_format_RAISE_VARARGS_older,
361337
"STORE_ATTR": extended_format_ATTR,

0 commit comments

Comments
 (0)