Пример #1
0
def enumerate_basicblocks_edges(instructions):
    """
    Return a list of basicblock after
    statically parsing given instructions
    """

    basicblocks = list()
    edges = list()
    xrefs = enumerate_xref(instructions)
    # create the first block
    new_block = True

    for inst in instructions:
        if new_block:
            block = BasicBlock(start_offset=inst.offset,
                               start_instr=inst,
                               name='block_%x' % inst.offset)
            new_block = False

        # add current instruction to the basicblock
        block.instructions.append(inst)

        # next instruction in xrefs list
        if (inst.offset_end + 1) in xrefs:
            # absolute JUMP
            if inst.is_branch_unconditional:
                edges.append(
                    Edge(block.name, 'block_%x' % xref_of_instr(inst),
                         EDGE_UNCONDITIONAL))
            # conditionnal JUMPI / JUMPIF / ...
            elif inst.is_branch_conditional:
                edges.append(
                    Edge(block.name, 'block_%x' % xref_of_instr(inst),
                         EDGE_CONDITIONAL_TRUE))
                edges.append(
                    Edge(block.name, 'block_%x' % (inst.offset_end + 1),
                         EDGE_CONDITIONAL_FALSE))
            # Halt instruction : RETURN, STOP, RET, ...
            elif inst.is_halt:
                pass
            # just falls to the next instruction
            else:
                edges.append(
                    Edge(block.name, 'block_%x' % (inst.offset_end + 1),
                         EDGE_FALLTHROUGH))

            block.end_offset = inst.offset_end
            block.end_instr = inst
            basicblocks.append(block)
            new_block = True

    # add the last block
    basicblocks.append(block)
    edges = list(set(edges))

    return (basicblocks, edges)
Пример #2
0
    def get_functions_call_edges(self):

        nodes = list()
        edges = list()

        if not self.analyzer:
            self.analyzer = WasmModuleAnalyzer(self.module_bytecode)
        if not self.functions:
            self.functions = enum_func(self.module_bytecode)

        # create nodes
        for name, param_str, return_str in self.analyzer.func_prototypes:
            nodes.append(format_func_name(name, param_str, return_str))

        log.info('nodes: %s', nodes)

        # create edges
        tmp_edges = enum_func_call_edges(self.functions,
                                         len(self.analyzer.imports_func))

        # tmp_edges = [(node_from, node_to), (...), ...]
        for node_from, node_to in tmp_edges:
            # node_from
            name, param, ret = self.analyzer.func_prototypes[node_from]
            from_final = format_func_name(name, param, ret)
            # node_to
            name, param, ret = self.analyzer.func_prototypes[node_to]
            to_final = format_func_name(name, param, ret)
            edges.append(Edge(from_final, to_final, EDGE_CALL))
        log.info('edges: %s', edges)

        return (nodes, edges)
Пример #3
0
def enumerate_edges_statically(basicblocks):

    edges = list()

    for block in basicblocks:
        # JMP
        if block.is_unconditional:
            jmp_instr = block.end_instr
            edges.append(Edge(block.name, 'block_%x' % xref_of_instr(jmp_instr), EDGE_UNCONDITIONAL))

        # JMPIF, JMPIFNOT
        elif block.is_conditional:
            jmp_instr = block.end_instr
            edges.append(Edge(block.name, 'block_%x' % xref_of_instr(jmp_instr), EDGE_CONDITIONAL_TRUE))
            edges.append(Edge(block.name, 'block_%x' % (block.end_offset + 1), EDGE_CONDITIONAL_FALSE))

        elif block.is_fallthrough:
            edges.append(Edge(block.name, 'block_%x' % (block.end_offset + 1), EDGE_FALLTHROUGH))

    edges = list(set(edges))
    return edges
Пример #4
0
    def emulate(self, state=EthereumVMstate(), depth=0):

        #  create fake stack for test
        state.symbolic_stack = list(range(1000))

        # get current instruction
        instr = self.reverse_instructions[state.pc]

        # create the first basicblock of this branch
        # print('%d : %s' % (instr.offset, instr.name))
        self.current_basicblock = self.basicblock_per_instr[instr.offset]

        # beginning of a function
        if instr in self.functions_start_instr:
            # retrive matching function
            self.current_function = next(
                filter(lambda f: f.start_instr == instr, self.functions))
            self.ssa_counter = 0
            logging.info("[+] Entering function:" +
                         self.current_function.prefered_name + ' at ' +
                         str(hex(self.current_function.start_offset)))

        # associate function to basicblock
        self.current_basicblock.function_name = self.current_function.prefered_name
        # associate basicblock to function
        self.current_function.basicblocks.append(self.current_basicblock)

        # halt variable use to catch end branch
        halt = False
        while not halt:

            # get current instruction
            instr = self.reverse_instructions[state.pc]

            # handle fall-thrown due to JUMPDEST
            if instr.name == 'JUMPDEST':
                # doesn't match new block that start with JUMPDEST
                if self.current_basicblock.start_offset != instr.offset:
                    self.edges.append(
                        Edge(self.current_basicblock.name,
                             'block_%x' % instr.offset, EDGE_FALLTHROUGH))

            # get current basicblock
            self.current_basicblock = self.basicblock_per_instr[instr.offset]

            # add this instruction to his functions
            self.current_function.instructions.append(instr)

            # Save instruction and state
            state.instr = instr
            self.states[self.states_total] = state
            state = copy.deepcopy(state)
            self.states_total += 1
            state.pc += 1

            # execute single instruction
            halt = self.emulate_one_instruction(instr, state, depth)
            state.instructions_visited.append(instr.offset)

        logging.info("[X] Returning from basicblock %s" %
                     self.current_basicblock.name)

        # automatic remove doublon edges
        self.edges = list(set(self.edges))
Пример #5
0
    def ssa_stack_memory_storage_flow_instruction(self, instr, state, depth):

        halt = False
        op = instr.name

        if op == 'POP':
            # SSA STACK
            s0 = state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name)

        elif op in ['MLOAD', 'SLOAD']:
            # SSA STACK
            s0 = state.ssa_stack.pop()
            instr.ssa = SSA(new_assignement=self.ssa_counter,
                            method_name=instr.name,
                            args=[s0])
            state.ssa_stack.append(instr)
            self.ssa_counter += 1

        elif op in ['MSTORE', 'MSTORE8', 'SSTORE']:
            # SSA STACK
            s0, s1 = state.ssa_stack.pop(), state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name, args=[s0, s1])

        elif op == 'JUMP':
            # SSA STACK
            push_instr = state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name, args=[push_instr])

            # get instruction with this value as offset
            if push_instr.ssa.is_constant:
                #jump_addr = int.from_bytes(push_instr.operand, byteorder='big')
                jump_addr = push_instr.operand_interpretation
                # get instruction with this value as offset
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))
            else:
                # try to resolve the SSA repr
                jump_addr = self.ssaoptimizer.resolve_instr_ssa(push_instr)
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))
                if not jump_addr:
                    logging.warning('JUMP DYNAMIC TODO')
                    logging.warning('[X] push_instr %x: %s ' %
                                    (push_instr.offset, push_instr.name))
                    logging.warning('[X] push_instr.ssa %s' %
                                    push_instr.ssa.format())
                    list_args = [
                        arg.ssa.format() for arg in push_instr.ssa.args
                    ]
                    logging.warning('[X] push_instr.ssa %s' % list_args)
                    return True

            # depth of 1 - prevent looping
            #if (depth < self.max_depth):
            if target.name != "JUMPDEST":
                logging.info('[X] Bad JUMP to 0x%x' % jump_addr)
                return True

            if target.offset not in state.instructions_visited:
                logging.info('[X] follow JUMP branch offset 0x%x' %
                             target.offset)
                new_state = copy.deepcopy(state)
                new_state.pc = self.instructions.index(target)

                # follow the JUMP
                self.edges.append(
                    Edge(self.current_basicblock.name,
                         'block_%x' % target.offset, EDGE_UNCONDITIONAL))
                self.emulate(new_state, depth=depth + 1)

                halt = True

            else:
                #logging.info('[X] Max depth reached, skipping JUMP 0x%x' % jump_addr)
                self.edges.append(
                    Edge(self.current_basicblock.name,
                         'block_%x' % target.offset, EDGE_UNCONDITIONAL))
                logging.info('[X] Loop detected, skipping JUMP 0x%x' %
                             jump_addr)
                halt = True

            self.current_basicblock = self.basicblock_per_instr[instr.offset]

        elif op == 'JUMPI':
            # SSA STACK
            push_instr, condition = state.ssa_stack.pop(), state.ssa_stack.pop(
            )
            instr.ssa = SSA(method_name=instr.name,
                            args=[push_instr, condition])

            logging.info('[X] follow JUMPI default branch offset 0x%x' %
                         (instr.offset_end + 1))
            new_state = copy.deepcopy(state)
            self.edges.append(
                Edge(self.current_basicblock.name,
                     'block_%x' % (instr.offset_end + 1),
                     EDGE_CONDITIONAL_FALSE))
            self.emulate(new_state, depth=depth + 1)
            self.current_basicblock = self.basicblock_per_instr[instr.offset]

            # get instruction with this value as offset
            if push_instr.ssa.is_constant:
                #jump_addr = int.from_bytes(push_instr.operand, byteorder='big')
                jump_addr = push_instr.operand_interpretation
                # get instruction with this value as offset
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))
            else:
                # try to resolve the SSA repr
                jump_addr = self.ssaoptimizer.resolve_instr_ssa(push_instr)
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))
                if not jump_addr:
                    logging.warning('JUMP DYNAMIC TODO')
                    logging.warning('[X] push_instr %x: %s ' %
                                    (push_instr.offset, push_instr.name))
                    logging.warning('[X] push_instr.ssa %s' %
                                    push_instr.ssa.format())
                    list_args = [
                        arg.ssa.format() for arg in push_instr.ssa.args
                    ]
                    logging.warning('[X] push_instr.ssa %s' % list_args)
                    return True

            if target.name != "JUMPDEST":
                logging.info('[X] Bad JUMP to 0x%x' % jump_addr)
                return True

            if target.offset not in state.instructions_visited:
                # condition are True
                logging.info('[X] follow JUMPI branch offset 0x%x' %
                             (target.offset))
                new_state = copy.deepcopy(state)
                new_state.pc = self.instructions.index(target)

                # follow the JUMPI
                self.edges.append(
                    Edge(self.current_basicblock.name,
                         'block_%x' % target.offset, EDGE_CONDITIONAL_TRUE))
                self.emulate(new_state, depth=depth + 1)

            else:
                self.edges.append(
                    Edge(self.current_basicblock.name,
                         'block_%x' % target.offset, EDGE_CONDITIONAL_TRUE))
                logging.warning('[X] Loop detected, skipping JUMP 0x%x' %
                                jump_addr)
                logging.warning('[X] push_instr.ssa %s' %
                                push_instr.ssa.format())
                halt = True
            halt = True

        elif op in ['PC', 'MSIZE', 'GAS']:
            # SSA STACK
            instr.ssa = SSA(new_assignement=self.ssa_counter,
                            method_name=instr.name)
            state.ssa_stack.append(instr)
            self.ssa_counter += 1

        elif op == 'JUMPDEST':
            # SSA STACK
            instr.ssa = SSA(method_name=instr.name)

        return halt
Пример #6
0
def enum_blocks_edges(function_id, instructions):

    """
    Return a list of basicblock after
    statically parsing given instructions
    """

    basicblocks = list()
    edges = list()

    branches = []
    xrefs = []

    intent = 0
    blocks_tmp = []
    blocks_list = []
    # remove last instruction that is 'end' for the funtion
    tt = instructions[:-1]
    for index, inst in enumerate(tt):

        if inst.is_block_terminator:
            start, name = blocks_tmp.pop()
            blocks_list.append((intent, start, inst.offset_end, name))
            intent -= 1
        if inst.is_block_starter:  # in ['block', 'loop']:
            blocks_tmp.append((inst.offset, inst.name))
            intent += 1
        if inst.is_branch:
            branches.append((intent, inst))

    blocks_list = sorted(blocks_list, key=lambda tup: tup[1])

    for depth, inst in branches:
        d2 = int(inst.operand_interpretation.split(' ')[1])
        rep = next(((i, s, e, n) for i, s, e, n in blocks_list if (i == (depth - d2) and s < inst.offset and e > inst.offset_end)), None)
        if rep:
            i, start, end, name = rep
            if name == 'loop':
                value = start  # else name == 'block'
            elif name == 'block':
                value = end
            else:
                value = None
            inst.xref = value
            xrefs.append(value)

    # remove "block" instruction - not usefull graphicaly
    # instructions = [x for x in instructions if x.name not in ['block', 'loop']]

    # enumerate blocks

    new_block = True

    for index, inst in enumerate(instructions):

        # creation of a block
        if new_block:
            block = BasicBlock(inst.offset,
                               inst,
                               name=format_bb_name(function_id, inst.offset))
            new_block = False

        # add current instruction to the basicblock
        block.instructions.append(inst)

        # next instruction is a jump target
        if index < (len(instructions) - 1) and \
           instructions[index + 1].offset in xrefs:
            new_block = True
        # absolute jump - br
        elif inst.is_branch_unconditional:
            new_block = True
        # conditionnal jump - br_if
        elif inst.is_branch_conditional:
            new_block = True
        # end of a block
        elif index < (len(instructions) - 1) and \
                inst.name in ['end']:  # is_block_terminator
            new_block = True
        elif index < (len(instructions) - 1) and \
                instructions[index + 1].name == 'else':  # is_block_terminator
            new_block = True
        # start of a block
        elif index < (len(instructions) - 1) and \
                instructions[index + 1].is_block_starter:
            new_block = True
        # last instruction of the bytecode
        elif inst.offset == instructions[-1].offset:
            new_block = True

        if new_block:
            block.end_offset = inst.offset_end
            block.end_instr = inst
            basicblocks.append(block)
            new_block = True

    # TODO: detect and remove end instruction that end loop

    # enumerate edges
    for index, block in enumerate(basicblocks):
        # get the last instruction
        inst = block.end_instr

        # unconditional jump - br
        if inst.is_branch_unconditional:
            edges.append(Edge(block.name, format_bb_name(function_id, inst.xref), EDGE_UNCONDITIONAL))
        # conditionnal jump - br_if
        elif inst.is_branch_conditional:
            if inst.name == 'if':
                edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_CONDITIONAL_TRUE))
                # if 'else' in [i.name for i in basicblocks[index + 1].instructions]:
                #    edges.append(Edge(block.name, format_bb_name(function_id, basicblocks[index + 2].start_instr.offset), EDGE_CONDITIONAL_FALSE))
                edges.append(Edge(block.name, format_bb_name(function_id, basicblocks[index + 2].start_instr.offset), EDGE_CONDITIONAL_FALSE)) 
            else:
                edges.append(Edge(block.name, format_bb_name(function_id, inst.xref), EDGE_CONDITIONAL_TRUE))
                edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_CONDITIONAL_FALSE))
        elif inst.offset != instructions[-1].offset:
            # EDGE_FALLTHROUGH
            edges.append(Edge(block.name, format_bb_name(function_id, inst.offset_end + 1), EDGE_FALLTHROUGH))

    # prevent duplicate edges
    edges = list(set(edges))
    return basicblocks, edges
Пример #7
0
def enumerate_basicblocks_edges(function_id, instructions):
    """
    Return a list of basicblock after
    statically parsing given instructions
    """

    basicblocks = list()
    edges = list()
    labels = []

    intent = 0
    # find label first
    for index, inst in enumerate(instructions):
        if inst.is_block_starter:
            if inst.name in ['block', 'loop']:
                intent += 1
        elif inst.name in ['end']:
            if intent > 0:
                intent -= 1
                #tmp_labels.append({'intent': intent,
                #                   'offset': inst.offset_end})
                labels.append(inst.offset_end)
    # print(function_id)
    # print(labels)
    '''
    #e = [{'intent': 0, 'offset': 15}, {'intent': 1, 'offset': 17}, {'intent': 0, 'offset': 56}]
    tmp_list = []
    for index, x in enumerate(tmp_labels):
        if x.get('intent') == 0:
            labels += tmp_list[::-1]
            tmp_list = []
        tmp_list.append(x.get('offset'))
    labels += tmp_list[::-1]
    print(labels)
    '''

    # remove "block" instruction - not usefull graphicaly
    instructions = [x for x in instructions if x.name not in ['block', 'loop']]
    # create the first block
    new_block = False
    end_block = False
    block = BasicBlock(instructions[0].offset,
                       instructions[0],
                       name=format_bb_name(function_id,
                                           instructions[0].offset))

    for index, inst in enumerate(instructions):
        if new_block:
            block = BasicBlock(inst.offset,
                               inst,
                               name=format_bb_name(function_id, inst.offset))
            new_block = False

        # add current instruction to the basicblock
        block.instructions.append(inst)

        # absolute jump - br
        # br is *always* followed by end instruction
        if inst.is_branch_unconditional:
            end_block = True
            jump_offset = int(inst.operand_interpretation.split(' ')[1])
            if instructions[index + 1].name == 'end':
                end_block = False
            edges.append(
                Edge(block.name,
                     format_bb_name(function_id, labels[jump_offset] + 1),
                     EDGE_UNCONDITIONAL))

        # conditionnal jump - br_if
        elif inst.is_branch_conditional:
            end_block = True
            jump_offset = int(inst.operand_interpretation.split(' ')[1])
            edges.append(
                Edge(block.name,
                     format_bb_name(function_id, labels[jump_offset] + 1),
                     EDGE_CONDITIONAL_TRUE))
            edges.append(
                Edge(
                    block.name,
                    format_bb_name(function_id,
                                   instructions[index + 1].offset),
                    EDGE_CONDITIONAL_FALSE))

        # end of a block
        elif index < (len(instructions) - 1) and \
                inst.name in ['end', 'else']:  # is_block_terminator
            end_block = True
            if not instructions[index - 1].is_branch_unconditional:
                edges.append(
                    Edge(
                        block.name,
                        format_bb_name(function_id,
                                       instructions[index + 1].offset),
                        EDGE_FALLTHROUGH))

        # start of a block
        elif index < (len(instructions) - 1) and \
                instructions[index + 1].is_block_starter:
            end_block = True
            edges.append(
                Edge(
                    block.name,
                    format_bb_name(function_id,
                                   instructions[index + 1].offset),
                    EDGE_FALLTHROUGH))

        # last instruction of the entire bytecode
        elif inst == instructions[-1]:
            end_block = True

        if end_block:
            block.end_offset = inst.offset_end
            block.end_instr = inst
            basicblocks.append(block)
            new_block = True
            end_block = False

    edges = list(set(edges))
    return basicblocks, edges
Пример #8
0
    def ssa_stack_memory_storage_flow_instruction(self, instr, state, depth):

        halt = False
        op = instr.name

        if op == 'POP':
            # SSA STACK
            s0 = state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name)

        elif op in ['MLOAD', 'SLOAD']:
            # SSA STACK
            s0 = state.ssa_stack.pop()
            instr.ssa = SSA(new_assignement=self.ssa_counter,
                            method_name=instr.name,
                            args=[s0])
            state.ssa_stack.append(instr)
            self.ssa_counter += 1

        elif op in ['MSTORE', 'MSTORE8', 'SSTORE']:
            # SSA STACK
            s0, s1 = state.ssa_stack.pop(), state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name, args=[s0, s1])

        elif op == 'JUMP':
            # SSA STACK
            push_instr = state.ssa_stack.pop()
            instr.ssa = SSA(method_name=instr.name, args=[push_instr])

            # get instruction with this value as offset
            if push_instr.ssa.is_constant:
                jump_addr = int.from_bytes(push_instr.operand, byteorder='big')

                # get instruction with this value as offset
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))

                # depth of 1 - prevent looping
                #if (depth < self.max_depth):
                if target.name == "JUMPDEST":
                    if target.offset not in state.instructions_visited:
                        #if (depth < self.max_depth):
                        logging.info('[X] follow JUMP branch offset 0x%x' %
                                     target.offset)
                        new_state = copy.deepcopy(state)
                        new_state.pc = self.instructions.index(target)

                        # follow the JUMP
                        self.edges.append(
                            Edge(self.current_basicblock.name,
                                 'block_%x' % target.offset,
                                 EDGE_UNCONDITIONAL))
                        self.emulate(new_state, depth=depth + 1)

                        halt = True

                    else:
                        #logging.info('[X] Max depth reached, skipping JUMP 0x%x' % jump_addr)
                        self.edges.append(
                            Edge(self.current_basicblock.name,
                                 'block_%x' % target.offset,
                                 EDGE_UNCONDITIONAL))
                        logging.info('[X] Loop detected, skipping JUMP 0x%x' %
                                     jump_addr)
                        halt = True
                else:
                    logging.info('[X] Bad JUMP to 0x%x' % jump_addr)
                    # modif current basicblock because jump is not valid
                    self.current_basicblock.type = 'terminal'
                    halt = True
            else:
                logging.warning('JUMP DYNAMIC TODO')
                logging.warning('[X] push_instr %s push_instr %x' %
                                (push_instr.name, push_instr.offset))
                #raise Exception('JUMP DYNAMIC TODO')

            self.current_basicblock = self.basicblock_per_instr[instr.offset]

        elif op == 'JUMPI':
            # SSA STACK
            push_instr, condition = state.ssa_stack.pop(), state.ssa_stack.pop(
            )
            instr.ssa = SSA(method_name=instr.name,
                            args=[push_instr, condition])

            # depth of 1 - prevent looping
            #if (depth < self.max_depth):
            #if (instr.offset_end + 1) not in state.instructions_visited:
            logging.info('[X] follow JUMPI default branch offset 0x%x' %
                         (instr.offset_end + 1))
            new_state = copy.deepcopy(state)
            self.edges.append(
                Edge(self.current_basicblock.name,
                     'block_%x' % (instr.offset_end + 1),
                     EDGE_CONDITIONAL_FALSE))
            self.emulate(new_state, depth=depth + 1)
            self.current_basicblock = self.basicblock_per_instr[instr.offset]

            # get instruction with this value as offset
            #push_instr = next(filter(lambda element: element.offset == jump_addr, self.instructions))
            if push_instr.ssa.is_constant:
                jump_addr = int.from_bytes(push_instr.operand, byteorder='big')
                # get instruction with this value as offset
                target = next(
                    filter(lambda element: element.offset == jump_addr,
                           self.instructions))

                if target.name == "JUMPDEST":
                    if target.offset not in state.instructions_visited:
                        # condition are True
                        # and target not in state.instructions_visited:
                        logging.info('[X] follow JUMPI branch offset 0x%x' %
                                     (target.offset))
                        new_state = copy.deepcopy(state)
                        new_state.pc = self.instructions.index(target)

                        # follow the JUMPI
                        self.edges.append(
                            Edge(self.current_basicblock.name,
                                 'block_%x' % target.offset,
                                 EDGE_CONDITIONAL_TRUE))
                        self.emulate(new_state, depth=depth + 1)

                    else:
                        self.edges.append(
                            Edge(self.current_basicblock.name,
                                 'block_%x' % target.offset,
                                 EDGE_CONDITIONAL_TRUE))
                        logging.info('[X] Loop detected, skipping JUMP 0x%x' %
                                     jump_addr)
                        halt = True
                else:

                    logging.info('[X] Bad JUMP to 0x%x' % jump_addr)
                    self.current_basicblock.type = 'terminal'
            else:
                # tricks to exit properly this function
                #depth = self.max_depth
                logging.warning('JUMP DYNAMIC TODO')
                logging.warning('[X] push_instr %s push_instr %x' %
                                (push_instr.name, push_instr.offset))
                #raise Exception('JUMP DYNAMIC TODO')

            halt = True

        elif op in ['PC', 'MSIZE', 'GAS']:
            # SSA STACK
            instr.ssa = SSA(new_assignement=self.ssa_counter,
                            method_name=instr.name)
            state.ssa_stack.append(instr)
            self.ssa_counter += 1

        elif op == 'JUMPDEST':
            # SSA STACK
            instr.ssa = SSA(method_name=instr.name)

        return halt