def disco_loop(opc, version, queue, real_out, dup_lines=False, asm_format="classic"): """Disassembles a queue of code objects. If we discover another code object which will be found in co_consts, we add the new code to the list. Note that the order of code discovery is in the order of first encountered which is not amenable for the format used by a disassembler where code objects should be defined before using them in other functions. However this is not recursive and will overall lead to less memory consumption at run time. """ while len(queue) > 0: co = queue.popleft() if co.co_name not in ("<module>", "?"): real_out.write("\n" + format_code_info(co, version) + "\n") bytecode = Bytecode(co, opc, dup_lines=dup_lines) real_out.write(bytecode.dis(asm_format=asm_format) + "\n") for c in co.co_consts: if iscode(c): queue.append(c) pass pass
def disco( bytecode_version, co, timestamp, out=sys.stdout, is_pypy=False, magic_int=None, source_size=None, sip_hash=None, asm_format="classic", show_bytes=False, dup_lines=False, alternate_opmap=None, ): """ diassembles and deparses a given code block 'co' """ assert iscode(co) show_module_header( bytecode_version, co, timestamp, out, is_pypy, magic_int, source_size, sip_hash, header=True, show_filename=False, ) # store final output stream for case of error real_out = out or sys.stdout if co.co_filename and asm_format != "xasm": real_out.write(format_code_info(co, bytecode_version) + "\n") pass opc = get_opcode(bytecode_version, is_pypy, alternate_opmap) if asm_format == "xasm": disco_loop_asm_format(opc, bytecode_version, co, real_out, {}, set([])) else: queue = deque([co]) disco_loop(opc, bytecode_version, queue, real_out, asm_format=asm_format, dup_lines=True)
def disco_loop_asm_format(opc, version, co, real_out, fn_name_map, all_fns): """Produces disassembly in a format more conducive to automatic assembly by producing inner modules before they are used by outer ones. Since this is recusive, we'll use more stack space at runtime. """ co = codeType2Portable(co) co_name = co.co_name mapped_name = fn_name_map.get(co_name, co_name) new_consts = [] for c in co.co_consts: if iscode(c): if isinstance(c, types.CodeType): c_compat = codeType2Portable(c) else: c_compat = c disco_loop_asm_format(opc, version, c_compat, real_out, fn_name_map, all_fns) m = re.match(".* object <(.+)> at", str(c)) if m: basename = m.group(1) if basename != "module": mapped_name = code_uniquify(basename, c.co_code) c_compat.co_name = mapped_name c_compat.freeze() new_consts.append(c_compat) else: new_consts.append(c) pass co.co_consts = new_consts m = re.match("^<(.+)>$", co.co_name) if m or co_name in all_fns: if co_name in all_fns: basename = co_name else: basename = m.group(1) if basename != "module": mapped_name = code_uniquify(basename, co.co_code) co_name = mapped_name assert mapped_name not in fn_name_map fn_name_map[mapped_name] = basename co.co_name = mapped_name pass elif co_name in fn_name_map: # FIXME: better would be a hash of the co_code mapped_name = code_uniquify(co_name, co.co_code) fn_name_map[mapped_name] = co_name co.co_name = mapped_name pass co = co.freeze() all_fns.add(co_name) if co.co_name != "<module>" or co.co_filename: real_out.write("\n" + format_code_info(co, version, mapped_name) + "\n") bytecode = Bytecode(co, opc, dup_lines=True) real_out.write(bytecode.dis(asm_format="asm") + "\n")
def info(self): """Return formatted information about the code object.""" return format_code_info(self.codeobj, self.opc.version)