def _create_program(f, namespaces=None, constants=None, namespace=None): """ f must be a callable. namespaces must be a sequence. Each element must be a module, or the string '<math.h>'. constants must be dictionary of name, value pairs for constants that will be used in the function. (XXX It should be possible for this to be done automatically...) """ if namespaces is None: namespaces = [] if constants is None: constants = {} program_table = [] # num_func_pushes = 0 # num_data_pushes = 0 bc = dis.Bytecode(f) if namespace is not None: # This initial loop is just a test of an idea. It doesn't # yet have any effect on what follows afterwards. found_names = [] current_name = None for pc, instruction in enumerate(bc): if instruction.opname == 'LOAD_GLOBAL': if current_name is not None: found_names.append(current_name) current_name = [instruction.argval] elif instruction.opname == 'LOAD_ATTR': assert current_name is not None current_name.append(instruction.argval) elif instruction.opname in ['LOAD_METHOD', 'LOAD_FUNCTION']: current_name.append(instruction.argval) found_names.append(current_name) current_name = None else: if current_name is not None: found_names.append(current_name) current_name = None print("Found these names:") print(found_names) found_objects = [] for found_name in found_names: top = found_name[0] if top not in namespace: if top not in c99math: raise NameError('name %r is not defined' % top) if len(found_name) > 1: raise AttributeError(f'C99 math function {top} has no ' f'attribute {found_name[2]}') obj = ('<math.h>', top) else: obj = namespace[top] attrs = found_name[1:][::-1] while attrs: attr = attrs.pop() obj = getattr(obj, attr) found_objects.append(obj) print("Found objects:", found_objects) for pc, instruction in enumerate(bc): # instruction is a *Python* bytecode instruction (as represented by # dis.Bytecode(f)). if instruction.opname in py_binary_opnames: program_table.append( (op.name_to_code[instruction.opname[7:]], 0, 0.0)) elif instruction.opname in ['UNARY_POSITIVE', 'UNARY_NEGATIVE']: program_table.append((op.name_to_code[instruction.opname], 0, 0.0)) elif instruction.opname == 'LOAD_GLOBAL': if instruction.argval in constants: program_table.append( (op.PUSH_CONSTANT, 0, constants[instruction.argval])) else: # Anything else global is expected to be a function. funcname = instruction.argval found = False # Find the function. for namespace in namespaces: # Special case check for <math.h> if namespace == '<math.h>': # Rename to corresponding name in C99 math.h funcname2 = { 'minimum': 'fmin', 'maximum': 'fmax', 'min': 'fmin', 'max': 'fmax', 'arctan2': 'atan2' }.get(funcname, funcname) if funcname2 in c99math_d: mathfuncindex, nargs = c99math_d[funcname2] if nargs == 1: program_table.append( (op.PUSH_FUNCTION, mathfuncindex, 0.0)) found = True break elif nargs == 2: program_table.append( (op.PUSH_FUNCTION, mathfuncindex, 0.0)) found = True break elif nargs == 3: program_table.append( (op.PUSH_FUNCTION, mathfuncindex, 0.0)) found = True break else: raise RuntimeError('functions with more than ' '3 args not handled yet.') else: continue else: assert isinstance(namespace, types.ModuleType) func = getattr(namespace, funcname) if func is None: continue if not isinstance(func, np.ufunc): raise RuntimeError('%r is not a ufunc.' % funcname) if func.nout != 1: raise RuntimeError("nout != 1 for " f"{instruction.opname}") sigstr_d = 'd' * func.nin + '->d' if sigstr_d not in func.types: raise RuntimeError(f"{funcname} does not have a " f"loop for {sigstr_d}") # This won't work--currently only handle <math.h>. program_table.append((op.PUSH_FUNCTION, func, funcname, namespace.__name__)) found = True if not found: raise NameError('name %r is not defined.' % funcname) elif instruction.opname == 'LOAD_CONST': program_table.append( (op.PUSH_CONSTANT, 0, float(instruction.argval))) elif instruction.opname == 'LOAD_FAST': program_table.append((op.PUSH_LOCAL, instruction.arg, 0.0)) elif instruction.opname == 'STORE_FAST': program_table.append((op.STORE_LOCAL, instruction.arg, 0.0)) elif instruction.opname == 'CALL_FUNCTION': program_table.append((op.CALL_FUNCTION, instruction.argval, 0.0)) elif instruction.opname == 'COMPARE_OP': if instruction.argval == '<': program_table.append((op.COMPARE_LT, 0, 0.0)) elif instruction.argval == '<=': program_table.append((op.COMPARE_LE, 0, 0.0)) elif instruction.argval == '>': program_table.append((op.COMPARE_GT, 0, 0.0)) elif instruction.argval == '>=': program_table.append((op.COMPARE_GE, 0, 0.0)) elif instruction.argval == '==': program_table.append((op.COMPARE_EQ, 0, 0.0)) elif instruction.argval == '!=': program_table.append((op.COMPARE_NE, 0, 0.0)) else: raise RuntimeError('unknown comparison operator ' f'{instruction.argval}') elif instruction.opname == 'JUMP_FORWARD': # Python's JUMP_FORWARD is a relative jump. Convert that # to a ufunkify absolute jump. offset = instruction.arg // 2 + 1 program_table.append((op.JUMP, pc + offset, 0.0)) elif instruction.opname == 'POP_JUMP_IF_FALSE': dest = instruction.argval // 2 program_table.append((op.JUMP_IF_FALSE, dest, 0.0)) elif instruction.opname == 'POP_JUMP_IF_TRUE': dest = instruction.argval // 2 program_table.append((op.JUMP_IF_TRUE, dest, 0.0)) elif instruction.opname == 'RETURN_VALUE': program_table.append((op.RETURN, 0, 0.0)) elif instruction.opname == 'STORE_FAST': program_table.append((op.STORE_LOCAL, 0, 0.0)) else: raise RuntimeError('unhandled op %r' % instruction.opname) program_table = np.array(program_table, dtype=program_dtype) return program_table
def collect_try_except_info(co, use_func_first_line=False): if not hasattr(co, 'co_lnotab'): return [] if use_func_first_line: firstlineno = co.co_firstlineno else: firstlineno = 0 try_except_info_lst = [] stack_in_setup = [] if sys.version_info[0] < 3: iter_in = _iter_as_bytecode_as_instructions_py2(co) else: iter_in = dis.Bytecode(co) iter_in = list(iter_in) op_offset_to_line = dict(dis.findlinestarts(co)) bytecode_to_instruction = {} for instruction in iter_in: bytecode_to_instruction[instruction.offset] = instruction if iter_in: for instruction in iter_in: curr_op_name = instruction.opname if curr_op_name == 'SETUP_EXCEPT': try_except_info = TryExceptInfo( _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True)) try_except_info.except_bytecode_offset = instruction.argval try_except_info.except_line = _get_line( op_offset_to_line, try_except_info.except_bytecode_offset, firstlineno, ) stack_in_setup.append(try_except_info) elif curr_op_name == 'SETUP_FINALLY': # We need to collect try..finally blocks too to make sure that # the stack_in_setup we're using to collect info is correct. try_except_info = TryExceptInfo(_get_line(op_offset_to_line, instruction.offset, firstlineno, search=True), is_finally=True) stack_in_setup.append(try_except_info) elif curr_op_name == 'RAISE_VARARGS': # We want to know about reraises and returns inside of except blocks (unfortunately # a raise appears to the debugger as a return, so, we may need to differentiate). if instruction.argval == 0: for info in stack_in_setup: info.raise_lines_in_except.append( _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True)) elif curr_op_name == 'END_FINALLY': # The except block also ends with 'END_FINALLY'. stack_in_setup[ -1].except_end_bytecode_offset = instruction.offset stack_in_setup[-1].except_end_line = _get_line( op_offset_to_line, instruction.offset, firstlineno, search=True) if not stack_in_setup[-1].is_finally: # Don't add try..finally blocks. try_except_info_lst.append(stack_in_setup[-1]) del stack_in_setup[-1] while stack_in_setup: # On Py3 the END_FINALLY may not be there (so, the end of the function is also the end # of the stack). stack_in_setup[-1].except_end_bytecode_offset = instruction.offset stack_in_setup[-1].except_end_line = _get_line(op_offset_to_line, instruction.offset, firstlineno, search=True) if not stack_in_setup[-1].is_finally: # Don't add try..finally blocks. try_except_info_lst.append(stack_in_setup[-1]) del stack_in_setup[-1] return try_except_info_lst
(8, (0, 9, 2)), # 2 bytes magic number, \r\n, 4 bytes UNIX timestamp (12, (3, 6)), # added 4 bytes file size # bytes 4-8 are flags, meaning of 9-16 depends on what flags are set # bit 0 not set: 9-12 timestamp, 13-16 file size # bit 0 set: 9-16 file hash (SipHash-2-4, k0 = 4 bytes of the file, k1 = 0) (16, (3, 7)), # inserted 4 bytes bit flag field at 4-8 # future version may add more bytes still, at which point we can extend # this table. It is correct for Python versions up to 3.9 ] header_size = next(s for s, v in reversed(header_sizes) if sys.version_info >= v) if _opt == "-py": _file = _files[1] code = open(_file, "r") bytecode = dis.Bytecode(code.read()) code.close() for instruction in bytecode: print(instruction.opname, instruction.argval) elif _opt == "-pyc": _file = _files[1] file = open(_file, "rb") bytecode = file.read(header_size) code = marshal.load(file) file.close() bytecode = dis.Bytecode(code) for instruction in bytecode: print(instruction.opname, instruction.argval)
import dis import socket def func(): sock = socket.socket() v = 20 print(v) print(dis.dis(func)) ds = dis.Bytecode(func) for i in ds: if i.opname == 'LOAD_ATTR' and i.argval == 'socket': print('we found socket') # SQL # Таблица (отношение) # Поле (столбец) # Ключи (первичный, внешний) # Связи между таблицами # Один к одному # Один ко многим # Многие ко многим # Транзакция # CREATE TABLE # ALTER TABLE # DROP TABLE # SELECT
def python_disassemble(code_text: str): """Disassemble the python code_text. This is a wrapper for `dis.dis`""" import dis return dis.Bytecode(code_text).dis()
def test_iteration(self): for obj in [_f, _C(1).__init__, "a=1", _f.__code__]: with self.subTest(obj=obj): via_object = list(dis.Bytecode(obj)) via_generator = list(dis.get_instructions(obj)) self.assertEqual(via_object, via_generator)
def test_info(self): self.maxDiff = 1000 for x, expected in CodeInfoTests.test_pairs: b = dis.Bytecode(x) self.assertRegex(b.info(), expected)
def print_py(filename): check_file_format(filename, '.py') bytecode = dis.Bytecode(open(filename).read()) for instr in bytecode: print("{} {}".format(instr.opname, instr.argrepr))
def print_str(code_string): compiled = compile(code_string, '<string>', 'exec') bytecode = dis.Bytecode(compiled) for instr in bytecode: print("{} {}".format(instr.opname, instr.argrepr))
def get_bytecode(filename): with open(filename) as f: code = ast.parse(f.read()) bytecode = dis.Bytecode(compile(code, '<string>', 'exec')).dis() return bytecode
def GetFID(f): try: result = str(list(dis.Bytecode(f))) except: result = str(f) return hash(result)
pprint.pprint({a:type(getattr(mod,a)) for a in dir(mod)}) foo = OCCT.BRepAlgoAPI.BRepAlgoAPI_BooleanOperation() reader = STEPControl_Reader() foo = reader.OneShape foo = OCCT.gp.gp_Vec.__init__ pprint.pprint({a:repr(getattr(foo,a)) for a in dir(foo)}) print(str(OCCT.gp.gp_Vec.__init__.__name__)) print(OCCT.gp.gp_Vec({})) print(OCCT.BRepBuilderAPI.BRepBuilderAPI_MakeFace(6)) ''' import dis g = 7 transitive_dependency = 6 print(repr(str(dis.Bytecode(pprint.pprint).dis()))) print(type(globals())) import pyocct_system from pyocct_system import * print(sys.argv) initialize_system(globals()) def dependency_function(): transitive_dependency pass @run_if_changed def test():
x: int y: int @dataclasses.dataclass class Pair: left: Point right: Point def use(x: int, y: int): left = Point(x, y) right = Point(x + 10, y) pair = Pair(left, right) print( statistics.median( [pair.left.x, pair.left.y, pair.right.x, pair.right.y])) dis.dis(use) # print(dis.opmap) for instruction in dis.Bytecode(use): # LOAD_GLOBAL 0 が Pointを指すってどうやってわかるんだろ? # 0 LOAD_GLOBAL 0 (Point) # 2 LOAD_FAST 0 (x) # 2 LOAD_FAST 1 (y) print("@", instruction.starts_line, instruction.opcode, instruction.opname, instruction.arg, instruction.argval, instruction.argrepr)
def findvar(x, end): print(" \\Checking for var. \"" + x + "\"") for j in range(len(vars)): if vars[j][0] == x: print(" \\Found var. \"" + x + "\"") return j print(" \\Could not find var. \"" + x + "\" " + end, end=(len(end) < 1) * "\n") return -1 if len(sys.argv) > 2: inF, out = open(sys.argv[1], "r").read(), [] i, m, d, n = 0, 0, [i for i in dis.Bytecode(inF)], inF.split("\n") while i < len(d): if d[i].starts_line != None and args != []: print("line: " + str(m) + " | " + n[m] + "\n" + str(pre) + "\n") args = [] m += 1 print(d[i]) if d[i].opname == "LOAD_CONST": if not ("SUBSCR" in d[i + 1].opname): print("\\Found LOAD_CONST") if d[i].argval == None: print(" \\Can't set argument to \"None\".") if d[i].is_jump_target == True: args.append(["jmp", d[i].argval]) else:
def test_source_line_in_disassembly(self): actual = dis.Bytecode(simple).dis()[:3] expected = '{:>3}'.format(simple.__code__.co_firstlineno) self.assertEqual(actual, expected) actual = dis.Bytecode(simple, first_line=350).dis()[:3] self.assertEqual(actual, '350')
def print_bytecode(source): bc = dis.Bytecode(source) for x in bc: print_row([x.opname, x.argrepr])
def test_instantiation(self): for obj in [_f, _C(1).__init__, 'a=1', _f.__code__]: with self.subTest(obj=obj): b = dis.Bytecode(obj) self.assertIsInstance(b.codeobj, types.CodeType) self.assertRaises(TypeError, dis.Bytecode, object())
# Python 字节码反汇编器 # https://docs.python.org/zh-cn/3/library/dis.html import dis def myfunc(alist): return len(alist) # 显示 myfunc() 的反汇编 dis.dis(myfunc) print("------------") bytecode = dis.Bytecode(myfunc) print(bytecode.dis()) for instr in bytecode: print(instr.opname) print(dis.opname) print(dis.opmap)
def test_explicit_first_line(self): actual = dis.Bytecode(outer, first_line=expected_outer_line) self.assertEqual(list(actual), expected_opinfo_outer)
def bytecodesnippet(): # Input to receive code snippet from user source_py = input('Enter code snippet!') # Method to generate bytecode print(dis.Bytecode(source_py).dis())
def test_disassembled(self): actual = dis.Bytecode(_f).dis() self.assertEqual(actual, dis_f)
def disassemble_built_in(self, co, classname=None, code_objects={}): # Container for tokens tokens = [] customize = {} self.code = array('B', co.co_code) self.build_lines_data(co) self.build_prev_op() # Get jump targets # Format: {target offset: [jump offsets]} jump_targets = self.find_jump_targets() bytecode = dis.Bytecode(co) # self.lines contains (block,addrLastInstr) if classname: classname = '_' + classname.lstrip('_') + '__' def unmangle(name): if name.startswith(classname) and name[-2:] != '__': return name[len(classname) - 2:] return name # free = [ unmangle(name) for name in (co.co_cellvars + co.co_freevars) ] # names = [ unmangle(name) for name in co.co_names ] # varnames = [ unmangle(name) for name in co.co_varnames ] else: # free = co.co_cellvars + co.co_freevars # names = co.co_names # varnames = co.co_varnames pass # Scan for assertions. Later we will # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT' for those # assertions self.load_asserts = set() bs = list(bytecode) n = len(bs) for i in range(n): inst = bs[i] if inst.opname == 'POP_JUMP_IF_TRUE' and i + 1 < n: next_inst = bs[i + 1] if (next_inst.opname == 'LOAD_GLOBAL' and next_inst.argval == 'AssertionError'): self.load_asserts.add(next_inst.offset) for inst in bytecode: if inst.offset in jump_targets: jump_idx = 0 for jump_offset in jump_targets[inst.offset]: tokens.append( Token('COME_FROM', None, repr(jump_offset), offset='%s_%s' % (inst.offset, jump_idx))) jump_idx += 1 pass pass pattr = inst.argrepr opname = inst.opname if opname in ['LOAD_CONST']: const = inst.argval if iscode(const): if const.co_name == '<lambda>': opname = 'LOAD_LAMBDA' elif const.co_name == '<genexpr>': opname = 'LOAD_GENEXPR' elif const.co_name == '<dictcomp>': opname = 'LOAD_DICTCOMP' elif const.co_name == '<setcomp>': opname = 'LOAD_SETCOMP' elif const.co_name == '<listcomp>': opname = 'LOAD_LISTCOMP' # verify() uses 'pattr' for comparison, since 'attr' # now holds Code(const) and thus can not be used # for comparison (todo: think about changing this) # pattr = 'code_object @ 0x%x %s->%s' %\ # (id(const), const.co_filename, const.co_name) pattr = '<code_object ' + const.co_name + '>' else: pattr = const pass elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE', 'UNPACK_SEQUENCE', 'MAKE_FUNCTION', 'MAKE_CLOSURE', 'DUP_TOPX', 'RAISE_VARARGS'): # if opname == 'BUILD_TUPLE' and \ # self.code[self.prev[offset]] == LOAD_CLOSURE: # continue # else: # op_name = '%s_%d' % (op_name, oparg) # if opname != BUILD_SLICE: # customize[op_name] = oparg opname = '%s_%d' % (opname, inst.argval) if inst.opname != 'BUILD_SLICE': customize[opname] = inst.argval elif opname == 'JUMP_ABSOLUTE': pattr = inst.argval target = self.get_target(inst.offset) if target < inst.offset: if (inst.offset in self.stmts and self.code[inst.offset + 3] not in (END_FINALLY, POP_BLOCK) and offset not in self.not_continue): opname = 'CONTINUE' else: opname = 'JUMP_BACK' elif inst.offset in self.load_asserts: opname = 'LOAD_ASSERT' tokens.append( Token( type_=opname, attr=inst.argval, pattr=pattr, offset=inst.offset, linestart=inst.starts_line, )) pass return tokens, {}
import dis def hello_world(): print('Hello World') hello_world() # dis.dis(hello_world) print('Byte Code') string = dis.Bytecode(hello_world) for x in string: print(x)
if symbol not in code.co_names: # name's not there, can't possibly be an assignment return None name_idx = list(code.co_names).index(symbol) STORE_NAME = 90 STORE_GLOBAL = 97 LOAD_CONST = 100 const = default <<<<<<< HEAD for byte_code in Bytecode(code): ======= for byte_code in dis.Bytecode(code): >>>>>>> 7e5c5fbd6c824de4d4c2b62da3f7cae87d462119 op = byte_code.opcode arg = byte_code.arg if op == LOAD_CONST: const = code.co_consts[arg] elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL): return const else: const = default def _update_globals(): """ Patch the globals to remove the objects not available on some platforms.
def bytecodesnippet(): source_py = input('Enter code snippet! ') print(dis.Bytecode(source_py).dis())
assert bool(matcher_pattern.match(ObjectPattern)) # assert bool(matcher_pattern.match(ObjectMultiPattern)) if hasattr(re, 'Pattern'): assert bool(matcher_pattern.match(re.Pattern)) if __name__ == '__main__': print(pyopm) import dis # test_start_end_block() print('== test_object_pattern_basic') test_object_pattern_basic() print('== test_object_special_cases') test_object_pattern_special_cases() # d = dis.Bytecode(test_object_pattern_context_handler) print(d.dis()) print('names GLOBAL : ', d.codeobj.co_names) print('varnames FAST : ', d.codeobj.co_varnames) print('cellvars CLOSURE: ', d.codeobj.co_cellvars) print('freevars DEREF : ', d.codeobj.co_freevars) # print('== test_object_context_handler') test_object_pattern_context_handler() print('== test_object_multi_pattern') test_basic_object_multi_pattern() print('== test_str_repr') test_str_repr() print('== test_context_handler') test_context_handler() print('== test_meta_match')
def __get_bytecode(self, filename): if os.path.exists(filename): func = open(filename).read() bytecode = dis.Bytecode(func) return bytecode
def find_the_secret(f): return dis.Bytecode(f).dis()[92:124]
def method_complexity(method: Callable) -> float: """Estimate complexity of a method by counting bytecode instructions""" bytecode = dis.Bytecode(method).dis() return len([line for line in bytecode.splitlines() if line])
def fromfunction(cls, source_lines, f): """Construct a code package from the source code of an entire module and a code object of a function defined within that module. """ return cls(f.co_name, source_lines, dis.Bytecode(f))