同步操作将从 OpenHarmony-SIG/python 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
"""Disassembler of Python byte code into mnemonics."""import sysimport typesimport collectionsimport iofrom opcode import *from opcode import __all__ as _opcodes_all__all__ = ["code_info", "dis", "disassemble", "distb", "disco","findlinestarts", "findlabels", "show_code","get_instructions", "Instruction", "Bytecode"] + _opcodes_alldel _opcodes_all_have_code = (types.MethodType, types.FunctionType, types.CodeType,classmethod, staticmethod, type)FORMAT_VALUE = opmap['FORMAT_VALUE']FORMAT_VALUE_CONVERTERS = ((None, ''),(str, 'str'),(repr, 'repr'),(ascii, 'ascii'),)MAKE_FUNCTION = opmap['MAKE_FUNCTION']MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')def _try_compile(source, name):"""Attempts to compile the given source, first as an expression andthen as a statement if the first approach fails.Utility function to accept strings in functions that otherwiseexpect code objects"""try:c = compile(source, name, 'eval')except SyntaxError:c = compile(source, name, 'exec')return cdef dis(x=None, *, file=None, depth=None):"""Disassemble classes, methods, functions, and other compiled objects.With no argument, disassemble the last traceback.Compiled objects currently include generator objects, async generatorobjects, and coroutine objects, all of which store their code objectin a special attribute."""if x is None:distb(file=file)return# Extract functions from methods.if hasattr(x, '__func__'):x = x.__func__# Extract compiled code objects from...if hasattr(x, '__code__'): # ...a function, orx = x.__code__elif hasattr(x, 'gi_code'): #...a generator object, orx = x.gi_codeelif hasattr(x, 'ag_code'): #...an asynchronous generator object, orx = x.ag_codeelif hasattr(x, 'cr_code'): #...a coroutine.x = x.cr_code# Perform the disassembly.if hasattr(x, '__dict__'): # Class or moduleitems = sorted(x.__dict__.items())for name, x1 in items:if isinstance(x1, _have_code):print("Disassembly of %s:" % name, file=file)try:dis(x1, file=file, depth=depth)except TypeError as msg:print("Sorry:", msg, file=file)print(file=file)elif hasattr(x, 'co_code'): # Code object_disassemble_recursive(x, file=file, depth=depth)elif isinstance(x, (bytes, bytearray)): # Raw bytecode_disassemble_bytes(x, file=file)elif isinstance(x, str): # Source code_disassemble_str(x, file=file, depth=depth)else:raise TypeError("don't know how to disassemble %s objects" %type(x).__name__)def distb(tb=None, *, file=None):"""Disassemble a traceback (default: last traceback)."""if tb is None:try:tb = sys.last_tracebackexcept AttributeError:raise RuntimeError("no last traceback to disassemble") from Nonewhile tb.tb_next: tb = tb.tb_nextdisassemble(tb.tb_frame.f_code, tb.tb_lasti, file=file)# The inspect module interrogates this dictionary to build its# list of CO_* constants. It is also used by pretty_flags to# turn the co_flags field into a human readable list.COMPILER_FLAG_NAMES = {1: "OPTIMIZED",2: "NEWLOCALS",4: "VARARGS",8: "VARKEYWORDS",16: "NESTED",32: "GENERATOR",64: "NOFREE",128: "COROUTINE",256: "ITERABLE_COROUTINE",512: "ASYNC_GENERATOR",}def pretty_flags(flags):"""Return pretty representation of code flags."""names = []for i in range(32):flag = 1<<iif flags & flag:names.append(COMPILER_FLAG_NAMES.get(flag, hex(flag)))flags ^= flagif not flags:breakelse:names.append(hex(flags))return ", ".join(names)def _get_code_object(x):"""Helper to handle methods, compiled or raw code objects, and strings."""# Extract functions from methods.if hasattr(x, '__func__'):x = x.__func__# Extract compiled code objects from...if hasattr(x, '__code__'): # ...a function, orx = x.__code__elif hasattr(x, 'gi_code'): #...a generator object, orx = x.gi_codeelif hasattr(x, 'ag_code'): #...an asynchronous generator object, orx = x.ag_codeelif hasattr(x, 'cr_code'): #...a coroutine.x = x.cr_code# Handle source code.if isinstance(x, str):x = _try_compile(x, "<disassembly>")# By now, if we don't have a code object, we can't disassemble x.if hasattr(x, 'co_code'):return xraise TypeError("don't know how to disassemble %s objects" %type(x).__name__)def code_info(x):"""Formatted details of methods, functions, or code."""return _format_code_info(_get_code_object(x))def _format_code_info(co):lines = []lines.append("Name: %s" % co.co_name)lines.append("Filename: %s" % co.co_filename)lines.append("Argument count: %s" % co.co_argcount)lines.append("Positional-only arguments: %s" % co.co_posonlyargcount)lines.append("Kw-only arguments: %s" % co.co_kwonlyargcount)lines.append("Number of locals: %s" % co.co_nlocals)lines.append("Stack size: %s" % co.co_stacksize)lines.append("Flags: %s" % pretty_flags(co.co_flags))if co.co_consts:lines.append("Constants:")for i_c in enumerate(co.co_consts):lines.append("%4d: %r" % i_c)if co.co_names:lines.append("Names:")for i_n in enumerate(co.co_names):lines.append("%4d: %s" % i_n)if co.co_varnames:lines.append("Variable names:")for i_n in enumerate(co.co_varnames):lines.append("%4d: %s" % i_n)if co.co_freevars:lines.append("Free variables:")for i_n in enumerate(co.co_freevars):lines.append("%4d: %s" % i_n)if co.co_cellvars:lines.append("Cell variables:")for i_n in enumerate(co.co_cellvars):lines.append("%4d: %s" % i_n)return "\n".join(lines)def show_code(co, *, file=None):"""Print details of methods, functions, or code to *file*.If *file* is not provided, the output is printed on stdout."""print(code_info(co), file=file)_Instruction = collections.namedtuple("_Instruction","opname opcode arg argval argrepr offset starts_line is_jump_target")_Instruction.opname.__doc__ = "Human readable name for operation"_Instruction.opcode.__doc__ = "Numeric code for operation"_Instruction.arg.__doc__ = "Numeric argument to operation (if any), otherwise None"_Instruction.argval.__doc__ = "Resolved arg value (if known), otherwise same as arg"_Instruction.argrepr.__doc__ = "Human readable description of operation argument"_Instruction.offset.__doc__ = "Start index of operation within bytecode sequence"_Instruction.starts_line.__doc__ = "Line started by this opcode (if any), otherwise None"_Instruction.is_jump_target.__doc__ = "True if other code jumps to here, otherwise False"_OPNAME_WIDTH = 20_OPARG_WIDTH = 5class Instruction(_Instruction):"""Details for a bytecode operationDefined fields:opname - human readable name for operationopcode - numeric code for operationarg - numeric argument to operation (if any), otherwise Noneargval - resolved arg value (if known), otherwise same as argargrepr - human readable description of operation argumentoffset - start index of operation within bytecode sequencestarts_line - line started by this opcode (if any), otherwise Noneis_jump_target - True if other code jumps to here, otherwise False"""def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):"""Format instruction details for inclusion in disassembly output*lineno_width* sets the width of the line number field (0 omits it)*mark_as_current* inserts a '-->' marker arrow as part of the line*offset_width* sets the width of the instruction offset field"""fields = []# Column: Source code line numberif lineno_width:if self.starts_line is not None:lineno_fmt = "%%%dd" % lineno_widthfields.append(lineno_fmt % self.starts_line)else:fields.append(' ' * lineno_width)# Column: Current instruction indicatorif mark_as_current:fields.append('-->')else:fields.append(' ')# Column: Jump target markerif self.is_jump_target:fields.append('>>')else:fields.append(' ')# Column: Instruction offset from start of code sequencefields.append(repr(self.offset).rjust(offset_width))# Column: Opcode namefields.append(self.opname.ljust(_OPNAME_WIDTH))# Column: Opcode argumentif self.arg is not None:fields.append(repr(self.arg).rjust(_OPARG_WIDTH))# Column: Opcode argument detailsif self.argrepr:fields.append('(' + self.argrepr + ')')return ' '.join(fields).rstrip()def get_instructions(x, *, first_line=None):"""Iterator for the opcodes in methods, functions or codeGenerates a series of Instruction named tuples giving the details ofeach operations in the supplied code.If *first_line* is not None, it indicates the line number that shouldbe reported for the first source line in the disassembled code.Otherwise, the source line information (if any) is taken directly fromthe disassembled code object."""co = _get_code_object(x)cell_names = co.co_cellvars + co.co_freevarslinestarts = dict(findlinestarts(co))if first_line is not None:line_offset = first_line - co.co_firstlinenoelse:line_offset = 0return _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,co.co_consts, cell_names, linestarts,line_offset)def _get_const_info(const_index, const_list):"""Helper to get optional details about const referencesReturns the dereferenced constant and its repr if the constantlist is defined.Otherwise returns the constant index and its repr()."""argval = const_indexif const_list is not None:argval = const_list[const_index]return argval, repr(argval)def _get_name_info(name_index, name_list):"""Helper to get optional details about named referencesReturns the dereferenced name as both value and repr if the namelist is defined.Otherwise returns the name index and its repr()."""argval = name_indexif name_list is not None:argval = name_list[name_index]argrepr = argvalelse:argrepr = repr(argval)return argval, argreprdef _get_instructions_bytes(code, varnames=None, names=None, constants=None,cells=None, linestarts=None, line_offset=0):"""Iterate over the instructions in a bytecode string.Generates a sequence of Instruction namedtuples giving the details of eachopcode. Additional information about the code's runtime environment(e.g. variable names, constants) can be specified using optionalarguments."""labels = findlabels(code)starts_line = Nonefor offset, op, arg in _unpack_opargs(code):if linestarts is not None:starts_line = linestarts.get(offset, None)if starts_line is not None:starts_line += line_offsetis_jump_target = offset in labelsargval = Noneargrepr = ''if arg is not None:# Set argval to the dereferenced value of the argument when# available, and argrepr to the string representation of argval.# _disassemble_bytes needs the string repr of the# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.argval = argif op in hasconst:argval, argrepr = _get_const_info(arg, constants)elif op in hasname:argval, argrepr = _get_name_info(arg, names)elif op in hasjrel:argval = offset + 2 + argargrepr = "to " + repr(argval)elif op in haslocal:argval, argrepr = _get_name_info(arg, varnames)elif op in hascompare:argval = cmp_op[arg]argrepr = argvalelif op in hasfree:argval, argrepr = _get_name_info(arg, cells)elif op == FORMAT_VALUE:argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]argval = (argval, bool(arg & 0x4))if argval[1]:if argrepr:argrepr += ', 'argrepr += 'with format'elif op == MAKE_FUNCTION:argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)if arg & (1<<i))yield Instruction(opname[op], op,arg, argval, argrepr,offset, starts_line, is_jump_target)def disassemble(co, lasti=-1, *, file=None):"""Disassemble a code object."""cell_names = co.co_cellvars + co.co_freevarslinestarts = dict(findlinestarts(co))_disassemble_bytes(co.co_code, lasti, co.co_varnames, co.co_names,co.co_consts, cell_names, linestarts, file=file)def _disassemble_recursive(co, *, file=None, depth=None):disassemble(co, file=file)if depth is None or depth > 0:if depth is not None:depth = depth - 1for x in co.co_consts:if hasattr(x, 'co_code'):print(file=file)print("Disassembly of %r:" % (x,), file=file)_disassemble_recursive(x, file=file, depth=depth)def _disassemble_bytes(code, lasti=-1, varnames=None, names=None,constants=None, cells=None, linestarts=None,*, file=None, line_offset=0):# Omit the line number column entirely if we have no line number infoshow_lineno = linestarts is not Noneif show_lineno:maxlineno = max(linestarts.values()) + line_offsetif maxlineno >= 1000:lineno_width = len(str(maxlineno))else:lineno_width = 3else:lineno_width = 0maxoffset = len(code) - 2if maxoffset >= 10000:offset_width = len(str(maxoffset))else:offset_width = 4for instr in _get_instructions_bytes(code, varnames, names,constants, cells, linestarts,line_offset=line_offset):new_source_line = (show_lineno andinstr.starts_line is not None andinstr.offset > 0)if new_source_line:print(file=file)is_current_instr = instr.offset == lastiprint(instr._disassemble(lineno_width, is_current_instr, offset_width),file=file)def _disassemble_str(source, **kwargs):"""Compile the source string, then disassemble the code object."""_disassemble_recursive(_try_compile(source, '<dis>'), **kwargs)disco = disassemble # XXX For backwards compatibilitydef _unpack_opargs(code):extended_arg = 0for i in range(0, len(code), 2):op = code[i]if op >= HAVE_ARGUMENT:arg = code[i+1] | extended_argextended_arg = (arg << 8) if op == EXTENDED_ARG else 0else:arg = Noneyield (i, op, arg)def findlabels(code):"""Detect all offsets in a byte code which are jump targets.Return the list of offsets."""labels = []for offset, op, arg in _unpack_opargs(code):if arg is not None:if op in hasjrel:label = offset + 2 + argelif op in hasjabs:label = argelse:continueif label not in labels:labels.append(label)return labelsdef findlinestarts(code):"""Find the offsets in a byte code which are start of lines in the source.Generate pairs (offset, lineno) as described in Python/compile.c."""byte_increments = code.co_lnotab[0::2]line_increments = code.co_lnotab[1::2]bytecode_len = len(code.co_code)lastlineno = Nonelineno = code.co_firstlinenoaddr = 0for byte_incr, line_incr in zip(byte_increments, line_increments):if byte_incr:if lineno != lastlineno:yield (addr, lineno)lastlineno = linenoaddr += byte_incrif addr >= bytecode_len:# The rest of the lnotab byte offsets are past the end of# the bytecode, so the lines were optimized away.returnif line_incr >= 0x80:# line_increments is an array of 8-bit signed integersline_incr -= 0x100lineno += line_incrif lineno != lastlineno:yield (addr, lineno)class Bytecode:"""The bytecode operations of a piece of codeInstantiate this with a function, method, other compiled object, string ofcode, or a code object (as returned by compile()).Iterating over this yields the bytecode operations as Instruction instances."""def __init__(self, x, *, first_line=None, current_offset=None):self.codeobj = co = _get_code_object(x)if first_line is None:self.first_line = co.co_firstlinenoself._line_offset = 0else:self.first_line = first_lineself._line_offset = first_line - co.co_firstlinenoself._cell_names = co.co_cellvars + co.co_freevarsself._linestarts = dict(findlinestarts(co))self._original_object = xself.current_offset = current_offsetdef __iter__(self):co = self.codeobjreturn _get_instructions_bytes(co.co_code, co.co_varnames, co.co_names,co.co_consts, self._cell_names,self._linestarts,line_offset=self._line_offset)def __repr__(self):return "{}({!r})".format(self.__class__.__name__,self._original_object)@classmethoddef from_traceback(cls, tb):""" Construct a Bytecode from the given traceback """while tb.tb_next:tb = tb.tb_nextreturn cls(tb.tb_frame.f_code, current_offset=tb.tb_lasti)def info(self):"""Return formatted information about the code object."""return _format_code_info(self.codeobj)def dis(self):"""Return a formatted view of the bytecode operations."""co = self.codeobjif self.current_offset is not None:offset = self.current_offsetelse:offset = -1with io.StringIO() as output:_disassemble_bytes(co.co_code, varnames=co.co_varnames,names=co.co_names, constants=co.co_consts,cells=self._cell_names,linestarts=self._linestarts,line_offset=self._line_offset,file=output,lasti=offset)return output.getvalue()def _test():"""Simple test program to disassemble a file."""import argparseparser = argparse.ArgumentParser()parser.add_argument('infile', type=argparse.FileType('rb'), nargs='?', default='-')args = parser.parse_args()with args.infile as infile:source = infile.read()code = compile(source, args.infile.name, "exec")dis(code)if __name__ == "__main__":_test()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。