Compare compiler versions

python
"""
Module containing main building blocks to parse assembly and draw CFGs.
"""
# from goto import with_goto
import itertools
from goto import with_goto
from pickle import NONE
from colour import Color
import re
import sys
import tempfile
from xml.sax import xmlreader
# from goto import goto, label
from graphviz import Digraph

# TODO: make this a command-line flag
VERBOSE = 0

def escape(instruction):
    """
    Escape used dot graph characters in given instruction so they will be
    displayed correctly.
    """
    instruction = instruction.replace('<', r'\<')
    instruction = instruction.replace('>', r'\>')
    instruction = instruction.replace('|', r'\|')
    instruction = instruction.replace('{', r'\{')
    instruction = instruction.replace('}', r'\}')
    instruction = instruction.replace(' ', ' ')
    return instruction

class BasicBlock:
    """
    Class to represent a node in CFG with straight lines of code without jump
    or calls instructions.
    """

    def __init__(self, key):
        self.key = key
        self.instructions = []
        self.jump_edge = None
        self.no_jump_edge = None
        self.form_fucntion = ""
    def set_form_function(self,function):
        self.form_fucntion = function

    def add_instruction(self, instruction):
        """
        Add instruction to this block.
        """
        self.instructions.append(instruction)

    def add_jump_edge(self, basic_block_key):
        """
        Add jump target block to this block.
        """
        if isinstance(basic_block_key, BasicBlock):
            self.jump_edge = basic_block_key.key
        else:
            self.jump_edge = basic_block_key

    def add_no_jump_edge(self, basic_block_key):
        """
        Add no jump target block to this block.
        """
        if isinstance(basic_block_key, BasicBlock):
            self.no_jump_edge = basic_block_key.key
        else:
            self.no_jump_edge = basic_block_key

    def get_label(self):
        """
        Return content of the block for dot graph.
        """
        # Left align in dot.
        label = r'\l'.join([escape(i.text) for i in self.instructions])
        # Left justify the last line too.
        label += r'\l'
        if self.jump_edge:
            if self.no_jump_edge:
                label += '|{<s0>No Jump|<s1>Jump}'
            else:
                label += '|{<s1>Jump}'
        return '{' + label + '}'

    def __str__(self):
        return '\n'.join([i.text for i in self.instructions])

    def __repr__(self):
        return '\n'.join([i.text for i in self.instructions])

def print_assembly(basic_blocks):
    """
    Debug function to print the assembly.
    """
    for basic_block in basic_blocks.values():
        print(basic_block)

def read_lines(file_path):
    """ Read lines from the file and return then as a list. """
    lines = []
    with open(file_path, 'r', encoding='utf8') as asm_file:
        lines = asm_file.readlines()
    return lines

# Common regexes
HEX_PATTERN = r'[0-9a-fA-F]+'
HEX_LONG_PATTERN = r'(?:0x0*)?' + HEX_PATTERN

class InputFormat:  # pylint: disable=too-few-public-methods
    """
    An enum which represents various supported input formats
    """
    GDB = 'GDB'
    OBJDUMP = 'OBJDUMP'

def parse_function_header(line):
    """
    Return function name of memory range from the given string line.

    Match lines for non-stripped binaries:
    'Dump of assembler code for function test_function:'
    lines for stripped binaries:
    'Dump of assembler code from 0x555555555faf to 0x555555557008:'
    and lines for obdjdump disassembly:
    '0000000000016bb0 <_obstack_allocated_p@@Base>:'
    """

    objdump_name_pattern = re.compile(fr'{HEX_PATTERN} <([a-zA-Z_0-9@.]+)>:')
    function_name = objdump_name_pattern.search(line)
    if function_name is not None:
        return InputFormat.OBJDUMP, function_name[1]

    function_name_pattern = re.compile(r'function (\w+):$')
    function_name = function_name_pattern.search(line)
    if function_name is not None:
        return InputFormat.GDB, function_name[1]

    memory_range_pattern = re.compile(fr'(?:Address range|from) ({HEX_LONG_PATTERN}) to ({HEX_LONG_PATTERN}):$')
    memory_range = memory_range_pattern.search(line)
    if memory_range is not None:
        return InputFormat.GDB, f'{memory_range[1]}-{memory_range[2]}'

    return None, None

class Address:
    """
    Represents location in program which may be absolute or relative
    """
    def __init__(self, abs_addr, base=None, offset=None):
        self.abs = abs_addr
        self.base = base
        self.offset = offset

    def is_absolute(self):
        return self.base is None

    def is_relative(self):
        return not self.is_absolute()

    def __str__(self):
        if self.offset is not None:
            return f'0x{self.abs:x} ({self.base}+{self.offset})'
        return f'0x{self.abs}'

    def merge(self, other):
        if self.abs is not None:
            assert self.abs is None or self.abs == other.abs
            self.abs = other.abs
        if self.base is not None:
            assert self.base is None or self.base == other.base
            self.base = other.base
        if self.offset is not None:
            assert self.offset is None or self.offset == other.offset
            self.offset = other.offset

class Encoding:
    """
    Represents a sequence of bytes used for instruction encoding
    e.g. the '31 c0' in
    '16bd3: 31 c0                   xor    %eax,%eax'
    """
    def __init__(self, bites):
        self.bites = bites

    def size(self):
        return len(self.bites)

    def __str__(self):
        return ' '.join(map(lambda b: f'{b:#x}', self.bites))

class X86TargetInfo:
    """
    Contains instruction info for X86-compatible targets.
    """

    def __init__(self):
        pass

    def comment(self):
        return '#'

    def is_call(self, instruction):
        # Various flavors of call:
        #   call   *0x26a16(%rip)
        #   call   0x555555555542
        #   addr32 call 0x55555558add0
        return 'call' in instruction.opcode

    def is_jump(self, instruction):
        # print(instruction)
        return instruction.opcode[0] == 'j'
    # def is_jump2(self, instruction):
    #     return instruction.opcode[0] == 'jal'

    def is_unconditional_jump(self, instruction):
        return instruction.opcode.startswith('jmp')

    def is_sink(self, instruction):
        """
        Is this an instruction which terminates function execution e.g. return?
        """
        return instruction.opcode.startswith('ret')

class riscvTargetInfo:
    """
    Contains instruction info for riscv-compatible targets.
    """

    def __init__(self):
        pass

    def comment(self):
        return '#'

    def is_call(self, instruction):
        # print(instruction)
        # Various flavors of call:
        #   call   *0x26a16(%rip)
        #   call   0x555555555542
        #   addr32 call 0x55555558add0
        return str(instruction.opcode) in ('call')\
            and instruction.opcode not in ('beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu','blez','bnez','beqz','bnec','bgtz','bgez','bltz','beqc')

    def is_jump(self, instruction):

        # print(instruction)
        return instruction.opcode in ('c.j','j', 'jle', 'jl', 'je', 'jne', 'jge','je','jal') and not self.is_call(instruction)
        # return instruction.opcode[0] == 'j'
        # def is_jump2(self, instruction):
        # return instruction.opcode[0] == 'jal'
    def is_branch(self, instruction):
        # print(instruction)
        # Various flavors of call:
        #   call   *0x26a16(%rip)
        #   call   0x555555555542
        #   addr32 call 0x55555558add0
        return instruction.opcode in ('beq', 'bne', 'blt', 'bge', 'bltu', 'bgeu','blez','bnez','beqz','bnec','bgtz','bgez','bltz','beqc')

    def is_compressbranch(self, instruction):
        # print(instruction)
        # Various flavors of call:
        #   call   *0x26a16(%rip)
        #   call   0x555555555542
        #   addr32 call 0x55555558add0
        return instruction.opcode in ('c.beq', 'c.bne', 'c.blt', 'c.bge', 'c.bltu', 'c.bgeu','c.blez','c.bnez','c.beqz','c.bnec')

    def is_unconditional_jump(self, instruction):

        return str(instruction.opcode) in ('jmp') 


    def is_sink(self, instruction):
        """
        Is this an instruction which terminates function execution e.g. return?
        """
        return  str(instruction.opcode) in ('ret') 

class ARMTargetInfo:
    """
    Contains instruction info for ARM-compatible targets.
    """

    def __init__(self):
        pass

    def comment(self):
        return ';'

    def is_call(self, instruction):
        # Various flavors of call:
        #   bl 0x19d90 <_IO_vtable_check>
        # Note that we should be careful to not mix it with conditional
        # branches like 'ble'.
        return instruction.opcode.startswith('bl') \
            and instruction.opcode not in ('blt', 'ble', 'bls')

    def is_jump(self, instruction):
        return instruction.opcode[0] == 'b' and not self.is_call(instruction)

    def is_unconditional_jump(self, instruction):
        return instruction.opcode == 'b'

    def is_sink(self, instruction):
        """
        Is this an instruction which terminates function execution e.g. return?
        Detect various flavors of return like
          bx lr
          pop {r2-r6,pc}
        Note that we do not consider conditional branches (e.g. 'bxle') to sink.
        """
        return re.search(r'\bpop\b.*\bpc\b', instruction.body) \
            or (instruction.opcode == 'bx' and instruction.ops[0] == 'lr') \
            or instruction.opcode == 'udf'

class Instruction:
    """
    Represents a single assembly instruction with it operands, location and
    optional branch target
    """
    def __init__(self, body, text, lineno, address, opcode, ops, target, imm, target_info):  # noqa
        self.body = body
        self.text = text
        self.lineno = lineno
        self.address = address
        self.opcode = opcode
        self.ops = ops
        self.target = target
        self.info = target_info
        self.form_fucntion =""

        if imm is not None and (self.is_jump() or self.is_call()):
            # print("test")
            # print(imm)
            if self.target is None:
                self.target = imm
            else:
                self.target.merge(imm)

    def set_form_function(self,form_fucntion):
        self.form_fucntion=form_fucntion

    def is_call(self):
        return self.info.is_call(self)

    def is_jump(self):
        return self.info.is_jump(self)

    def is_branch(self):
        return self.info.is_branch(self)

    def is_direct_jump(self):
        return self.is_jump() and re.match(fr'{HEX_LONG_PATTERN}', self.ops[0])

    def is_inst_jump(self):
        return self.is_jump() 

    def is_inst_branch(self):
        return self.is_branch() 

    def is_compressbranch(self):
        return self.info.is_compressbranch(self)

    def is_sink(self):
        return self.info.is_sink(self)

    def is_unconditional_jump(self):
        return self.info.is_unconditional_jump(self)

    def __str__(self):
        result = f'{self.address}: {self.opcode}'
        if self.ops:
            result += f' {self.ops}'
        return result

def parse_address(line):
    """
    Parses leading address of instruction
    """
    address_match = re.match(fr'^\s*(?:0x)?({HEX_PATTERN})\s*(?:<([+-][0-9]+)>)?:(.*)', line)
    if address_match is None:
        return None, line,None
    address = Address(int(address_match[1], 16), None, int(address_match[2]) if address_match[2] else None)
    return address, address_match[3],int(address_match[1], 16)

def split_nth(string, count):
    """
    Splits string to equally-sized chunks
    """
    return [string[i:i+count] for i in range(0, len(string), count)]

def parse_encoding(line):
    """
    Parses byte encoding of instruction for objdump disassemblies
    e.g. the '31 c0' in
    '16bd3: 31 c0                   xor    %eax,%eax'
    In addition to X86 supports ARM encoding styles:
    '4: e1a01000    mov r1, r0'
    '50:    f7ff fffe   bl  0 <__aeabi_dadd>'
    '54:    0002        movs    r2, r0'
    """
    # Encoding is separated from assembly mnemonic via tab
    # so we allow whitespace separators between bytes
    # to avoid accidentally matching the mnemonic.
    enc_match = re.match(r'^\s*((?:[0-9a-f]{2,8} +)+)(.*)', line)
    if enc_match is None:
        return None, line
    bites = []
    for chunk in enc_match[1].strip().split(' '):
        bites.extend(int(byte, 16) for byte in split_nth(chunk, 2))
    return Encoding(bites), enc_match[2]

def parse_body(line, target_info):
    """
    Parses instruction body (opcode and operands)
    """
    comment_symbol = target_info.comment()
    body_match = re.match(fr'^\s*([^{comment_symbol}<]+)(.*)', line)
    if body_match is None:
        return None, None, None, line
    body = body_match[1].strip()
    line = body_match[2]
    opcode_match = re.match(r'^(\S*)\s*(.*)', body)
    if opcode_match is None:
        return None, None, None, line
    opcode = opcode_match[1]
    ops = opcode_match[2].split(',') if opcode_match[2] else []
    return body, opcode, ops, line

def parse_target(line):
    """
    Parses optional instruction branch target hint
    """
    target_match = re.match(r'\s*<([a-zA-Z_@0-9.*$_]+)([+-]0x[0-9a-f]+|[+-][0-9]+)?>(.*)', line)
    if target_match is None:
        return None, line
    offset = target_match[2] or '+0'
    address = Address(None, target_match[1], int(offset, 0))
    return address, target_match[3]

def parse_comment(line, target_info):
    """
    Parses optional instruction comment
    """
    comment_symbol = target_info.comment()
    comment_match = re.match(fr'^\s*{comment_symbol}\s*(.*)', line)
    if comment_match is None:
        return None, line
    comment = comment_match[1]
    imm_match = re.match(fr'^(?:0x)?({HEX_PATTERN})\s*(<.*>)?(.*)', comment)
    if imm_match is None:
        # If no imm was found, ignore the comment.
        # In particular this takes care of useless ARM comments like
        # '82:  46c0        nop         ; (mov r8, r8)'
        return None, ''
    abs_addr = int(imm_match[1], 16)
    if imm_match[2]:
        target, _ = parse_target(imm_match[2])
        target.abs = abs_addr
    else:
        target = Address(abs_addr)
    return target, imm_match[3]

source_code_index=1000000
def parse_line(line, lineno, function_name, fmt, target_info):
    """
    Parses a single line of assembly to create Instruction instance
    """

    line_back = line
    is_source_code = 0

    # Strip GDB prefix and leading whites
    if line.startswith('=> '):
        # Strip GDB marker
        line = line[3:]
    line = line.lstrip()
    line = line.rstrip()
    # org_address = re.match(fr'^\s*(?:0x)?({HEX_PATTERN})\s*(?:<([+-][0-9]+)>)?:(.*)', line)
    address, line,org_address = parse_address(line)
    if address is None:
        line = line_back
        is_source_code=1
        global source_code_index
        address = Address(source_code_index, None, None)
        source_code_index+=1
        # return None

    if fmt == InputFormat.OBJDUMP:
        encoding, line = parse_encoding(line)
        if not line:
            print(line)
            return encoding
    # print(str(org_address))

    if(org_address == None ):
        org_address=""
    if is_source_code == 1 :
        line = str((org_address))+"#"+str(line_back)
    if is_source_code == 1 :
        original_line = "debug"+line
    else:
        original_line = str(hex(org_address))+""+line
    body, opcode, ops, line = parse_body(line, target_info)
    if opcode is None:
        if(is_source_code!=1):
            return None

    target, line = parse_target(line)
    print(parse_target(line))

    imm, line = parse_comment(line, target_info)
    # if is_source_code == 1 :
    #     line = line_back
    # print(line)
    if(is_source_code!=1):
        if line:
            # Expecting complete parse
            return None
    # Set base symbol for relative addresses
    if address.base is None:
        address.base = function_name
    if target is not None and target.base is None:
        target.base = function_name

    return Instruction(body, original_line.strip(), lineno, address, opcode, ops, target, imm, target_info)

class JumpTable:
    """
    Holds info about branch sources and destinations in asm function.
    """

    def __init__(self, instructions):
        # Address where the jump begins and value which address
        # to jump to. This also includes calls.

        self.abs_sources = {}
        self.rel_sources = {}

        # Addresses where jumps end inside the current function.
        self.abs_destinations = set()
        self.rel_destinations = set()

        # Iterate over the lines and collect jump targets and branching points.
        for inst in instructions:
            if inst is None or not inst.is_direct_jump() and  not inst.is_inst_jump() \
                and  not inst.is_inst_branch() and not inst.is_compressbranch():
                continue

            # print(inst)
            # print("=====================")
            self.abs_sources[inst.address.abs] = inst.target
            self.abs_destinations.add(inst.target.abs)

            self.rel_sources[inst.address.offset] = inst.target
            self.rel_destinations.add(inst.target.offset)

    def is_destination(self, address):
        if address.abs is not None:
            return address.abs in self.abs_destinations
        if address.offset is not None:
            return address.offset in self.rel_destinations
        return False

    def get_target(self, address):
        if address.abs is not None:
            return self.abs_sources.get(address.abs)
        if address.offset is not None:
            return self.rel_sources.get(address.offset)
        return None

def parse_lines(lines, skip_calls, target_name):  # noqa pylint: disable=unused-argument
    print("arch : "+target_name)
    if target_name == 'x86':
        target_info = X86TargetInfo()
    elif target_name == 'riscv':
        target_info = riscvTargetInfo()
    elif target_name == 'arm':
        target_info = ARMTargetInfo()
    else:
        print(f'Unsupported platform {target_name}')
        sys.exit(1)

    instructions = []
    current_function_name = current_format = None
    for num, line in enumerate(lines, 1):
        fmt, function_name = parse_function_header(line)
        if function_name is not None:
            # assert current_function_name is None, 'we handle only one function for now'
            print(function_name)
            if VERBOSE:
                print(f'New function {function_name} (format {fmt})')
            current_function_name = function_name
            current_format = fmt
            continue
        instruction_or_encoding = parse_line(line, num, current_function_name, current_format, target_info)

        print(instruction_or_encoding)
        # instruction_or_encoding.set_form_function(current_function_name)
        if isinstance(instruction_or_encoding, Encoding):
            # Partial encoding for previous instruction, skip it
            continue
        if instruction_or_encoding is not None:
            instructions.append(instruction_or_encoding)
            continue

        if line.startswith('End of assembler dump') or not line:
            continue

        if line.strip() == '':
            continue

        # if(line == None):
        #     continue
        print(f'Unexpected assembly at line {num}:\n  {line}')
        sys.exit(1)

    # Infer target address for jump instructions
    for instruction in instructions:
        print(instruction)
        print(instruction.is_inst_jump())
        print(instruction.is_inst_branch())

        if (instruction.target is None or instruction.target.abs is None) \
                and instruction.is_direct_jump():
            if instruction.target is None:
                instruction.target = Address(0)
            instruction.target.abs = int(instruction.ops[0], 16)
        if (instruction.target is None or instruction.target.abs is None) \
                and instruction.is_inst_jump():
            if instruction.target is None:
                instruction.target = Address(0)
            instruction.target.abs = int(instruction.ops[1], 16)
        if (instruction.target is None or instruction.target.abs is None) \
                and instruction.is_inst_branch():
            if instruction.target is None:
                instruction.target = Address(0)
            if(instruction.opcode in ('beqz','bnez','blez','bgez','bltz','bgtz')):
                instruction.target.abs = int(instruction.ops[1], 16)
            elif(instruction.opcode in('beq', 'bne', 'blt', 'bge','bgeu','bltu','beqc','bnec')):
                instruction.target.abs = int(instruction.ops[2], 16)
            # print( "wqeeee")
        if (instruction.target is None or instruction.target.abs is None) \
                and instruction.is_compressbranch():
            if instruction.target is None:
                instruction.target = Address(0)
            if(instruction.opcode in ('c.blez','c.bnez','c.beqz')):
                instruction.target.abs = int(instruction.ops[1], 16)
            else:
                instruction.target.abs = int(instruction.ops[2], 16)
            # print(instruction_or_encoding)
    # elif

    # Infer relative addresses (for objdump or stripped gdb)
    start_address = instructions[0].address.abs
    end_address = instructions[-1].address.abs
    for instruction in instructions:
        for address in (instruction.address, instruction.target):
            if address is not None \
                    and address.offset is None \
                    and start_address <= address.abs <= end_address:
                address.offset = address.abs - start_address
                # print(address.offset)

    if VERBOSE:
        print('Instructions:')
        for instruction in instructions:
            if instruction is not None:
                print(f'  {instruction}')

    jump_table = JumpTable(instructions)

    if VERBOSE:
        print('Absolute destinations:')
        for dst in jump_table.abs_destinations:
            print(f'  {dst:#x}')
        print('Relative destinations:')
        for dst in jump_table.rel_destinations:
            print(f'  {dst}')
        print('Absolute branches:')
        for src, dst in jump_table.abs_sources.items():
            print(f'  {src:#x} -> {dst}')
        print('Relative branches:')
        for src, dst in jump_table.rel_sources.items():
            print(f'  {src} -> {dst}')

    # Now iterate over the assembly again and split it to basic blocks using
    # the branching information from earlier.
    basic_blocks = {}
    current_basic_block = None
    previous_jump_block = None
    for line, instruction in zip(lines, instructions):
        if instruction is None:
            continue

        # Current offset/address inside the function.
        program_point = instruction.address
        jump_point = jump_table.get_target(program_point)
        is_unconditional = instruction.is_unconditional_jump()

        if current_basic_block is None:
            current_basic_block = BasicBlock(program_point.abs)
            basic_blocks[current_basic_block.key] = current_basic_block
            # Previous basic block ended in jump instruction. Add the basic
            # block what follows if the jump was not taken.
            if previous_jump_block is not None:
                previous_jump_block.add_no_jump_edge(current_basic_block)
                previous_jump_block = None
        elif jump_table.is_destination(program_point):
            temp_block = current_basic_block
            current_basic_block = BasicBlock(program_point.abs)
            basic_blocks[current_basic_block.key] = current_basic_block
            temp_block.add_no_jump_edge(current_basic_block)

        current_basic_block.add_instruction(instruction)

        if jump_point is not None:
            current_basic_block.add_jump_edge(jump_point.abs)
            previous_jump_block = None if is_unconditional else current_basic_block
            current_basic_block = None
        elif instruction.is_sink():
            previous_jump_block = current_basic_block = None

    if previous_jump_block is not None:
        # If last instruction of the function is jump/call, then add dummy
        # block to designate end of the function.
        end_block = BasicBlock('end_of_function')
        dummy_instruction = Instruction('', 'end of function', 0, None, None, [], None, None, target_info)
        dummy_instruction.set_form_function(current_function_name)
        end_block.add_instruction(dummy_instruction)
        previous_jump_block.add_no_jump_edge(end_block.key)
        basic_blocks[end_block.key] = end_block

    return current_function_name, basic_blocks

# def draw_cfg(function_name, basic_blocks,function_name2, basic_blocks2, view):
#     dot = Digraph(name=function_name, comment=function_name, engine='dot')
#     dot.attr('graph', label=function_name)
#     for address, basic_block in basic_blocks.items():
#         key = str(address)
#         dot.node(key, shape='record', label=basic_block.get_label())
#     for basic_block in basic_blocks.values():
#         if basic_block.jump_edge:
#             if basic_block.no_jump_edge is not None:
#                 dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
#             dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
#         elif basic_block.no_jump_edge:
#             dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))

# Serach

# Driver Code
print("Following is the Depth-First Search")
# graph['a'] =[]
# print(graph)
# graph['a'] =['q']
# print(graph)
# graph['a'].append('w')
# print(graph)
# dfs(visited, graph, 'a')
# Using a Python dictionary to act as an adjacency list
graph = {
    # key:[value,value2],...
}
visited = set() # Set to keep track of visited nodes of graph.
v=[]
t=[]
find_block=0
def dfs(visited, graph, node,search,avoid):  #function for dfs 
    if node not in visited and node:
        print (node)
        # v.append(node)
        if(search == node): 
            print("find")
            find_block = int(node)
            for x in v:
                t.append(x)
            return
        v.append(node)
        visited.add(node)
        if node in graph and node not in avoid:
            for neighbour in graph[node]:
                v.append(neighbour)
                dfs(visited, graph, neighbour,search,avoid)

colors = ['#33FFA8','blue','red','purple']

def replaceline(infile, outfile):
    infopen = open(infile, 'r', encoding="utf-8")
    outfopen = open(outfile, 'w', encoding="utf-8")

    lines = infopen.readlines()
    for line in lines:
        if line.split():
            outfopen.writelines(str(line).replace(">debug", " fill='"'red'"'>"))
        else:
            outfopen.writelines("")

    infopen.close()
    outfopen.close()

def replaceline_0(infile, outfile):
    infopen = open(infile, 'r', encoding="utf-8")
    outfopen = open(outfile, 'w', encoding="utf-8")

    lines = infopen.readlines()
    for line in lines:
        if line.split():
            outfopen.writelines(str(line).replace("fill="+'"'+"#000000"+'"', ""))
        else:
            outfopen.writelines("")

    infopen.close()
    outfopen.close()

def redundant(infile, outfile):
    infopen = open(infile, 'r', encoding="utf-8")
    outfopen = open(outfile, 'w', encoding="utf-8")

    lines = infopen.readlines()
    for line in lines:
        if line.split():
            outfopen.writelines(str(line).replace(">diff", " fill='"'red'"'>"))
        else:
            outfopen.writelines("")

    infopen.close()
    outfopen.close()
source_record={

}
source_color={

}
nowcolor= 0
precolor=0
# color = list(np.random.choice(range(256), size=3))
def draw_cfg(function_name,get_print_list, view):
    dot=None
    green = Color("green")
    colors = list(green.range_to(Color("red"),1000))
    dot = Digraph(name=function_name, comment=function_name, engine='dot')
    # dot.graph_attr['rankdir'] = 'LR'
    dot.attr('graph', label=function_name)
    find = []
    for get_child in get_print_list:
        for address, basic_block in get_child[1].items():
            key = str(address)
            graph[key] =[]
        for basic_block in  get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
                graph[str(basic_block.key)].append(str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
            # disable for Serach
            # for i in basic_block.instructions:
            #     basic_block.set_form_function(i.form_fucntion)
            for i in basic_block.instructions:
                # (i.text.replace("debug#", "")).replace(" ", "")
                # print(str(i.text))
                if(str(i.text).find("debug")) >=0:
                    filter_str = (i.text.replace("debug#", "")).replace(" ", "")
                    if(  filter_str in source_record) : 
                        source_record[filter_str].append(str(basic_block.key))
                    else :
                        source_record[filter_str]=[]
                        source_record[filter_str].append(str(basic_block.key))
                    if(filter_str not in source_color):
                        global nowcolor
                        nowcolor+=1
                        source_color[basic_block.key]= colors[nowcolor]
                    else:
                        source_color[basic_block.key]= colors[nowcolor]

                    # if( basic_block.key in source_record2 ):
                    #     source_record2[basic_block.key].append()
                # else:
                #     print(str(i.text))
            print("==============")
            tmp =[i.text for i in basic_block.instructions]
            print(tmp)
            for x in tmp:
                if "dwq" in x:
                        print([i.text for i in basic_block.instructions])
                        find.append(str(basic_block.key))
    # for x in source_record:
    #     print(x)
    #     print (source_record[x])
    # return 
    # for x in source_color:
    #     print(x)
    #     print (source_color[x])
    # return 
    print("Following is the Depth-First Search")
    print(find)
    print(graph)
    # visited.add('722')
    for y in find:
        dfs(visited, graph,'1000000', str(y),graph[find[0]])
    print("path")
    print(t)
    print(find)
    # print(graph[find[0]])

    # print(colors[1])
    newt=['1000000']
    find_off =0
    find_close=0
    # print(get_print_list)
    index = 0
    # for get_child in get_print_list:
    #     for address, basic_block in get_child[1].items():
    #         key = str(address)
    #         # dot.node(key, shape='record', label=basic_block.get_label())
    #         newkey =""
    #         for x in source_color:
    #             if(key.find(str(x))):
    #                 newkey =key

    #         if(int (newkey) in source_color):
    #             dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[int (newkey)]))
    #             precolor= int (newkey)
    #         else:
    #             dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[precolor]))

    #     for basic_block in get_child[1].values():
    #         if basic_block.jump_edge:
    #             if basic_block.no_jump_edge is not None:
    #                 dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
    #             dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
    #         elif basic_block.no_jump_edge:
    #             dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))


    for get_child in get_print_list:
        for basic_block in  get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:

                    if str(basic_block.no_jump_edge) in t and find_off==0:
                        # print(basic_block.no_jump_edge)
                        if( str(basic_block.no_jump_edge) in find):
                            find_off= 1
                        if(basic_block.no_jump_edge != "end_of_function"):
                            if( find_block < int(basic_block.no_jump_edge)):
                                dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge),color=colors[1])
                            else:
                                dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))    
                        newt.append(str(basic_block.no_jump_edge))
                    else :
                        dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))

                if str(basic_block.jump_edge) in t  and find_off==0:     

                    if(basic_block.jump_edge != "end_of_function"):
                        if( find_block < int(basic_block.jump_edge)):
                            if( int(basic_block.key) == int(basic_block.jump_edge) ):
                                dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge),color=colors[3])
                            else:
                                if ( find_off==0):
                                    dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge),color=colors[2])
                                else:
                                    dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))
                            if( str(basic_block.jump_edge) in find):
                                find_off= 1
                        newt.append(str(basic_block.jump_edge))
                    else:
                        dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))

                else:
                    dot.edge(f'{basic_block.key}:s1', str(basic_block.jump_edge))

            elif basic_block.no_jump_edge:

                if str(basic_block.no_jump_edge) in t  and find_off==0:
                    if(basic_block.no_jump_edge != "end_of_function"):
                        if( str(basic_block.no_jump_edge) in find):
                            find_off= 1
                        if( find_block < int(basic_block.no_jump_edge)):
                            dot.edge(str(basic_block.key), str(basic_block.no_jump_edge),color=colors[1])
                        else:
                            dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))
                        newt.append(str(basic_block.no_jump_edge))
                else:
                    dot.edge(str(basic_block.key), str(basic_block.no_jump_edge))

            if(basic_block.jump_edge != "end_of_function" or basic_block.no_jump_edge != "end_of_function"):
                if( str(basic_block.jump_edge) == find or str(basic_block.no_jump_edge) == find):
                    find_off= 1

        for address, basic_block in get_child[1].items():
            key = str(address)
            graph[key] =[]

            # if key in newt and find_close==0 :
            #     dot.node(key, shape='record', label=basic_block.get_label(),  style="filled",fillcolor=colors[0])
            # else:
            # global nowcolor
            # nowcolor+=4
            # print(nowcolor)
            newkey =""
            for x in source_color:
                if(key.find(str(x))):
                    newkey =key
                    # print (newkey)
            # print(source_color[(newkey)])
            # return 
            # dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")
            # if(int (newkey) in source_color):
            #     dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[int (newkey)]))
            #     precolor= int (newkey)
            # else:
            #     dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[precolor]))

            if key in newt and find_close==0 :
                dot.node(key, shape='record', label=basic_block.get_label(),  style="filled",fillcolor=colors[0])
            else:
                dot.node(key, shape='record', label=basic_block.get_label())
            if(len(find)> 0):
                if( key == find[0]):
                    find_close= 1

            # else:
            #     print(basic_block.form_fucntion)
        index +=1

    # if(find_off== 0):
    #     print ("no find")
    # print(nowcolor)
    if view:
        dot.format = 'gv'
        with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
            # dot.view(filename.name)
            print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
    else:
        dot.format = 'svg'
        dot.render(filename=function_name, cleanup=True)
        print(f'Saved CFG to a file {function_name}.{dot.format}')
        # print(f'{function_name}.{dot.format}')
        replaceline_0(f'{function_name}.{dot.format}', f'back{function_name}.{dot.format}')
        replaceline(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        print(f'Saved new CFG to a file new{function_name}.{dot.format}')

source_record={

}
source_color={

}
nowcolor= 0
precolor=0
# color = list(np.random.choice(range(256), size=3))
def draw_cfg2(function_name,get_print_list, view):
    dot=None
    dot2=None
    index =0
    green = Color("green")
    colors = list(green.range_to(Color("blue"),170))
    dot = Digraph(name=function_name, comment=function_name, engine='dot')
    dot2 = Digraph(name=function_name, comment=function_name, engine='dot')
    # dot.graph_attr['rankdir'] = 'LR'
    dot.attr('graph', label=function_name)
    dot2.attr('graph', label=function_name)
    find = []
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)
            graph[key] =[]
        for basic_block in  get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
                graph[str(basic_block.key)].append(str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
            # disable for Serach
            # for i in basic_block.instructions:
            #     basic_block.set_form_function(i.form_fucntion)
            for i in basic_block.instructions:
                # (i.text.replace("debug#", "")).replace(" ", "")
                # print(str(i.text))

                if(str(i.text).find("debug")) >=0:
                    filter_str = (i.text.replace("debug#", "")).replace(" ", "")
                    if(  filter_str in source_record) : 
                        source_record[filter_str].append(str(basic_block.key))
                        # source_color[filter_str]= source_color[filter_str]
                    else :

                        global nowcolor
                        nowcolor+=1
                        source_record[filter_str]=[]
                        source_record[filter_str].append(str(basic_block.key))
                        source_color[filter_str]= colors[nowcolor]
                    # if(filter_str not in source_color):
                    #     global nowcolor
                    #     nowcolor+=2
                    #     source_color[basic_block.key]= colors[nowcolor]


                    # else:
                    #     source_color[basic_block.key]= colors[nowcolor]

                    # if( basic_block.key in source_record2 ):
                    #     source_record2[basic_block.key].append()
                # else:
                #     print(str(i.text))
        # index+=1       
    # for x in source_record:
    #     print(x)
    #     print (source_record[x])
    # return 
    # for x in source_color:
    #     print(x)
    #     print (source_color[x])
    # return 
    index =0
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)
            # dot.node(key, shape='record', label=basic_block.get_label())
            newkey =""
            # for x in source_color:
            #     if(key.find(str(x))):
            #         newkey =key
            global precolor
            for x in source_record:
                if key  in source_record[x] :
                    newkey =x
                    print(newkey)
                    print(source_record[x] )
                    # if key.find(str(y)):
                    #     newkey =y
                    #     print(source_record[x] )
                        # break
            # print(str (newkey) in source_color)
            if(index == 0):
                if(newkey != "end_of_function"):
                    if(str (newkey) in source_color):
                        dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[str (newkey)]))
                        precolor= str (newkey)
                    else:
                        # print(precolor)
                        # if(precolor):
                        #     
                        dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")
                # else:
                #     dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[precolor]))
            else:

                if(newkey != "end_of_function"):
                    if(str (newkey) in source_color):
                        dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str(source_color[str (newkey)]))
                        precolor= str (newkey)
                    else:
                        # if(precolor):
                        dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")

        for basic_block in get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    if(index==0):
                        dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                    else:
                        dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
        index+=1
        precolor=0
    for x in source_record:
        print(x)
        print (source_record[x])
    if view:
        dot.format = 'gv'
        with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
            # dot.view(filename.name)
            print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
    else:
        dot.format = 'svg'
        dot.render(filename=function_name, cleanup=True)
        print(f'Saved CFG to a file {function_name}.{dot.format}')
        # print(f'{function_name}.{dot.format}')
        replaceline_0(f'{function_name}.{dot.format}', f'back{function_name}.{dot.format}')
        replaceline(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        print(f'Saved new CFG to a file new{function_name}.{dot.format}')

        dot2.format = 'svg'
        dot2.render(filename=function_name+'2', cleanup=True)
        print(f'Saved CFG to a file {function_name}2.{dot2.format}')
        # print(f'{function_name}.{dot.format}')
        replaceline_0(f'{function_name}2.{dot2.format}', f'back{function_name}2.{dot2.format}')
        replaceline(f'back{function_name}2.{dot2.format}', f'new2{function_name}.{dot2.format}')
        print(f'Saved new CFG to a file new2{function_name}.{dot2.format}')

# basicblock recod
basicblock_mapping={

}
# find basicblock 
diff_basicblock =[

]
# same compiler differ

def draw_cfg3(function_name,get_print_list, view):
    dot=None
    dot2=None
    index =0
    green = Color("green")
    colors = list(green.range_to(Color("blue"),170))
    dot = Digraph(name=function_name, comment=function_name, engine='dot')
    dot2 = Digraph(name=function_name, comment=function_name, engine='dot')
    # dot.graph_attr['rankdir'] = 'LR'
    dot.attr('graph', label=function_name)
    dot2.attr('graph', label=function_name)
    find = []
    #candidates
    candidates=[]

    # secand input count
    index =0
    # secand input basicblock count
    bb_index=0
    best_basic_block=0
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)
            graph[key] =[]
        for basic_block in  get_child[1].values():

            basic_block_bakeup=bb_index
            basic_block_error = 0
            same_block=0
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
                graph[str(basic_block.key)].append(str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))

            if index == 0:
                for i in basic_block.instructions:
                    if(  str(bb_index) in basicblock_mapping) : 
                        basicblock_mapping[str(bb_index)].append(i)
                    else :
                        basicblock_mapping[str(bb_index)]=[]
                        basicblock_mapping[str(bb_index)].append(i)
            else:
                # for i in basic_block.instructions:
                #     if(str(i.text).find("debug")) <0:
                #         print(i.text)
                # print(bb_index)
                while(1):
                    oor=0
                    ins_count_per = 0
                    inst_count=0
                    process_inst=[]
                    for i in basic_block.instructions:
                        inst_count+=1
                        if(str(bb_index) in basicblock_mapping):
                            find =0
                            for x in basicblock_mapping[str(bb_index)]:
                                if(str(i.text).find("debug")) >=0:
                                    if(str(x.text).find("debug")) >=0 :
                                        if str(i.text).find(str(x.text)) >=0:
                                            find=1
                                            process_inst.append(x)
                                            break       
                                else:
                                    if(x not in process_inst):
                                        if i.opcode == x.opcode and len(x.ops) == len(i.ops):
                                            xlen = len(x.ops)
                                            ylen =  len(i.ops)
                                            if (ylen == xlen ):
                                                find=1
                                                process_inst.append(x)
                                                break

                            if(find ==1) :
                                ins_count_per+=1
                        else:
                            print("out of range")
                            print(bb_index)
                            oor=1

                    if(oor== 0):
                        if(inst_count == 0 )  :      
                            break

                    if(inst_count >0 and float(ins_count_per/inst_count) >=0.5) : 
                        if([bb_index,float(ins_count_per/inst_count)] not in candidates ):
                            candidates.append([bb_index,float(ins_count_per/inst_count)])
                        print("======== new")
                        print("same block")
                        print(inst_count)
                        print(ins_count_per)
                        print("======== new")
                        same_block+=1
                        bb_index-=1
                        if(same_block>=20):
                            break

                        # break
                    else:
                        print("maybe not same block")

                        print("========")
                        print(bb_index)
                        print(inst_count)
                        print(ins_count_per)
                        print(basic_block_error)
                        print("========")


                        if(basic_block_error<=5 ):
                            bb_index+=1
                            basic_block_error+=1

                        elif (basic_block_error>5 and basic_block_error<=10 ):
                            bb_index-=1
                            basic_block_error+=1

                        if(basic_block_error ==5 or basic_block_error ==10):
                            bb_index=basic_block_bakeup
                        if(basic_block_error >=10):
                            print("no find same bb")
                            # diff_basicblock.append(str(basic_block.key))
                            break
            if index == 1:
                max = 0
                max_bb =0
                for x in candidates:
                    if(x[1] >= max ):
                        max = x[1]
                        max_bb= x[0]
                        print(max_bb)
                print (candidates)
                candidates=[]
                print (max_bb)
                # for x in basicblock_mapping[str(max_bb)]:
                #     print(x)
                print("hello")
                # if(str(max_bb) in diff_basicblock):
                #     diff_basicblock.remove(str(max_bb))
                inst_count =0
                process_inst=[]
                prev_x=""
                for i in basic_block.instructions:
                    print("t"+i.text)
                    if(str(max_bb) in basicblock_mapping):
                        inst2_count=0
                        find =0

                        for x in basicblock_mapping[str(max_bb)]:
                            checked=1        
                            if(str(i.text).find("debug")) >=0:
                                if(str(x.text).find("debug")) >=0 :
                                        if str(i.text).find(str(x.text)) >=0:
                                            find=1
                                            inst2_count+=1
                                            # prev_x= x.text
                                            process_inst.append(x)
                                            break
                                        print("d"+x.text)
                            else:
                                if(str(x.text).find("debug")) <0:
                                    if(x not in process_inst):
                                        print("c"+x.text)
                                        if (i.opcode == x.opcode and len(x.ops) ==len(i.ops)  ):
                                            xlen = len(x.ops)
                                            ylen = len(i.ops)        
                                            if (ylen == xlen ):
                                                find=1
                                                print("ok")
                                                process_inst.append(x)
                                                prev_x= x.text
                                                inst2_count+=1
                                                break

                                        print("c"+x.text)


                        if(find==0):
                            if(str(i.text).find("debug")) <0:
                                if(str(i.text).find("diff")<0 ):
                                    print(i.text)
                                    print("no ok")
                                    i.text="diff(diff):"+i.text+"<=========" + str(prev_x) +" order error."            
                                    diff_basicblock.append(str(basic_block.key))
                    inst_count +=1
            print("========")        

            bb_index=basic_block_bakeup
            bb_index+=1
        if index == 0:
            for x in range(len(basicblock_mapping)+20) :
                # print(x)
                if(  str(x) not  in basicblock_mapping) : 
                    basicblock_mapping[str(x)]=[]


        index+=1   
        bb_index=0
    # for x in diff_basicblock:
    #     print(x)
    # return 
    # for x in range(len(basicblock_mapping)) :
    #     print(x)
    #     for y in basicblock_mapping[str(x)]:
    #         print(y)
    # return 
    # secand input count
    index =0
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)            
            newkey =""

            if(index == 0):
                dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")
            else:    
                if(key in diff_basicblock):
                    dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str("#28fca0"))
                    precolor= str (newkey)
                else:
                    dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")

        for basic_block in get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    if(index==0):
                        dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                    else:
                        dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
        index+=1
        precolor=0

    if view:
        dot.format = 'gv'
        with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
            # dot.view(filename.name)
            print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
    else:
        dot.format = 'svg'
        dot.render(filename=function_name, cleanup=True)
        print(f'Saved CFG to a file {function_name}.{dot.format}')
        replaceline_0(f'{function_name}.{dot.format}', f'back{function_name}.{dot.format}')
        redundant(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        # replaceline(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        print(f'Saved new CFG to a file new{function_name}.{dot.format}')

        dot2.format = 'svg'
        dot2.render(filename=function_name+'2', cleanup=True)
        print(f'Saved CFG to a file {function_name}2.{dot2.format}')
        replaceline_0(f'{function_name}2.{dot2.format}', f'back{function_name}2.{dot2.format}')
        redundant(f'back{function_name}2.{dot2.format}', f'new2{function_name}.{dot2.format}')
        # replaceline(f'back{function_name}2.{dot2.format}', f'new2{function_name}.{dot2.format}')
        print(f'Saved new CFG to a file new2{function_name}.{dot2.format}')

核心

python
# basicblock recod
basicblock_mapping={

}
# find basicblock 
diff_basicblock =[

]
# same compiler differ

def draw_cfg3(function_name,get_print_list, view):
    dot=None
    dot2=None
    index =0
    green = Color("green")
    colors = list(green.range_to(Color("blue"),170))
    dot = Digraph(name=function_name, comment=function_name, engine='dot')
    dot2 = Digraph(name=function_name, comment=function_name, engine='dot')
    # dot.graph_attr['rankdir'] = 'LR'
    dot.attr('graph', label=function_name)
    dot2.attr('graph', label=function_name)
    find = []
    #candidates
    candidates=[]

    # secand input count
    index =0
    # secand input basicblock count
    bb_index=0
    best_basic_block=0
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)
            graph[key] =[]
        for basic_block in  get_child[1].values():

            basic_block_bakeup=bb_index
            basic_block_error = 0
            same_block=0
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))
                graph[str(basic_block.key)].append(str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                graph[str(basic_block.key)].append(str(basic_block.no_jump_edge))

            if index == 0:
                for i in basic_block.instructions:
                    if(  str(bb_index) in basicblock_mapping) : 
                        basicblock_mapping[str(bb_index)].append(i)
                    else :
                        basicblock_mapping[str(bb_index)]=[]
                        basicblock_mapping[str(bb_index)].append(i)
            else:
                # for i in basic_block.instructions:
                #     if(str(i.text).find("debug")) <0:
                #         print(i.text)
                # print(bb_index)
                while(1):
                    oor=0
                    ins_count_per = 0
                    inst_count=0
                    process_inst=[]
                    for i in basic_block.instructions:
                        inst_count+=1
                        if(str(bb_index) in basicblock_mapping):
                            find =0
                            for x in basicblock_mapping[str(bb_index)]:
                                if(str(i.text).find("debug")) >=0:
                                    if(str(x.text).find("debug")) >=0 :
                                        if str(i.text).find(str(x.text)) >=0:
                                            find=1
                                            process_inst.append(x)
                                            break       
                                else:
                                    if(x not in process_inst):
                                        if i.opcode == x.opcode and len(x.ops) == len(i.ops):
                                            xlen = len(x.ops)
                                            ylen =  len(i.ops)
                                            if (ylen == xlen ):
                                                find=1
                                                process_inst.append(x)
                                                break

                            if(find ==1) :
                                ins_count_per+=1
                        else:
                            print("out of range")
                            print(bb_index)
                            oor=1

                    if(oor== 0):
                        if(inst_count == 0 )  :      
                            break

                    if(inst_count >0 and float(ins_count_per/inst_count) >=0.5) : 
                        if([bb_index,float(ins_count_per/inst_count)] not in candidates ):
                            candidates.append([bb_index,float(ins_count_per/inst_count)])
                        print("======== new")
                        print("same block")
                        print(inst_count)
                        print(ins_count_per)
                        print("======== new")
                        same_block+=1
                        bb_index-=1
                        if(same_block>=20):
                            break

                        # break
                    else:
                        print("maybe not same block")

                        print("========")
                        print(bb_index)
                        print(inst_count)
                        print(ins_count_per)
                        print(basic_block_error)
                        print("========")


                        if(basic_block_error<=5 ):
                            bb_index+=1
                            basic_block_error+=1

                        elif (basic_block_error>5 and basic_block_error<=10 ):
                            bb_index-=1
                            basic_block_error+=1

                        if(basic_block_error ==5 or basic_block_error ==10):
                            bb_index=basic_block_bakeup
                        if(basic_block_error >=10):
                            print("no find same bb")
                            # diff_basicblock.append(str(basic_block.key))
                            break
            if index == 1:
                max = 0
                max_bb =0
                for x in candidates:
                    if(x[1] >= max ):
                        max = x[1]
                        max_bb= x[0]
                        print(max_bb)
                print (candidates)
                candidates=[]
                print (max_bb)
                # for x in basicblock_mapping[str(max_bb)]:
                #     print(x)
                print("hello")
                # if(str(max_bb) in diff_basicblock):
                #     diff_basicblock.remove(str(max_bb))
                inst_count =0
                process_inst=[]
                prev_x=""
                for i in basic_block.instructions:
                    print("t"+i.text)
                    if(str(max_bb) in basicblock_mapping):
                        inst2_count=0
                        find =0

                        for x in basicblock_mapping[str(max_bb)]:
                            checked=1        
                            if(str(i.text).find("debug")) >=0:
                                if(str(x.text).find("debug")) >=0 :
                                        if str(i.text).find(str(x.text)) >=0:
                                            find=1
                                            inst2_count+=1
                                            # prev_x= x.text
                                            process_inst.append(x)
                                            break
                                        print("d"+x.text)
                            else:
                                if(str(x.text).find("debug")) <0:
                                    if(x not in process_inst):
                                        print("c"+x.text)
                                        if (i.opcode == x.opcode and len(x.ops) ==len(i.ops)  ):
                                            xlen = len(x.ops)
                                            ylen = len(i.ops)        
                                            if (ylen == xlen ):
                                                find=1
                                                print("ok")
                                                process_inst.append(x)
                                                prev_x= x.text
                                                inst2_count+=1
                                                break

                                        print("c"+x.text)


                        if(find==0):
                            if(str(i.text).find("debug")) <0:
                                if(str(i.text).find("diff")<0 ):
                                    print(i.text)
                                    print("no ok")
                                    i.text="diff(diff):"+i.text+"<=========" + str(prev_x) +" order error."            
                                    diff_basicblock.append(str(basic_block.key))
                    inst_count +=1
            print("========")        

            bb_index=basic_block_bakeup
            bb_index+=1
        if index == 0:
            for x in range(len(basicblock_mapping)+20) :
                # print(x)
                if(  str(x) not  in basicblock_mapping) : 
                    basicblock_mapping[str(x)]=[]


        index+=1   
        bb_index=0
    # for x in diff_basicblock:
    #     print(x)
    # return 
    # for x in range(len(basicblock_mapping)) :
    #     print(x)
    #     for y in basicblock_mapping[str(x)]:
    #         print(y)
    # return 
    # secand input count
    index =0
    for get_child in get_print_list:

        for address, basic_block in get_child[1].items():
            key = str(address)            
            newkey =""

            if(index == 0):
                dot.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")
            else:    
                if(key in diff_basicblock):
                    dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor=str("#28fca0"))
                    precolor= str (newkey)
                else:
                    dot2.node(key, shape='record', label=basic_block.get_label(),style="filled",fillcolor="white")

        for basic_block in get_child[1].values():
            if basic_block.jump_edge:
                if basic_block.no_jump_edge is not None:
                    if(index==0):
                        dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                    else:
                        dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.jump_edge))
            elif basic_block.no_jump_edge:
                if(index==0):
                    dot.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
                else:
                    dot2.edge(f'{basic_block.key}:s0', str(basic_block.no_jump_edge))
        index+=1
        precolor=0

    if view:
        dot.format = 'gv'
        with tempfile.NamedTemporaryFile(mode='w+b', prefix=function_name) as filename:
            # dot.view(filename.name)
            print(f'Opening a file {filename.name}.{dot.format} with default viewer. Don\'t forget to delete it later.')
    else:
        dot.format = 'svg'
        dot.render(filename=function_name, cleanup=True)
        print(f'Saved CFG to a file {function_name}.{dot.format}')
        replaceline_0(f'{function_name}.{dot.format}', f'back{function_name}.{dot.format}')
        redundant(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        # replaceline(f'back{function_name}.{dot.format}', f'new{function_name}.{dot.format}')
        print(f'Saved new CFG to a file new{function_name}.{dot.format}')

        dot2.format = 'svg'
        dot2.render(filename=function_name+'2', cleanup=True)
        print(f'Saved CFG to a file {function_name}2.{dot2.format}')
        replaceline_0(f'{function_name}2.{dot2.format}', f'back{function_name}2.{dot2.format}')
        redundant(f'back{function_name}2.{dot2.format}', f'new2{function_name}.{dot2.format}')
        # replaceline(f'back{function_name}2.{dot2.format}', f'new2{function_name}.{dot2.format}')
        print(f'Saved new CFG to a file new2{function_name}.{dot2.format}')

a.asm a2.asm https://gist.github.com/x213212/96bd63ef5df0ee3caebc3ee127dd0299 給定兩個asm 尋找相同模糊區間,假日稍微改了一下,遇到一些相同compiler 版本,有+option 而導致code gen 不同,要找出,asm不同的地方,對我來說實在非常的麻煩,cfg3可以大致的對區間進行模糊搜尋以找出不同的basic block 或者特殊inst

搜尋模糊區間匹配改用 匹配的inst/總basic inst算出比值,也新增了候選人basic block 名單找出 候選人中最相似的basic block 進行判斷, 至於檢測Unrooling loop區間,給予某個basic block 倒是可以用key value 累積inst 然後mod2取餘數,一樣inst過半的情況下進行Unrooling loop 檢測,大概把當前inst 取餘數由上到下統計到剩餘的inst就可以為這個basic block register進行再分組,有空再來實驗.