'Graph traversal handler. It takes in a node or an edge, and create new functions or add nodes to existing
functions accordingly. Oh, it also create edges on the transition map of functions.
:param CFGNode src: Beginning of the edge, or a single node when dst is None.
:param CFGNode dst: Destination of the edge. For processing a single node, `dst` is None.
:param dict data: Edge data in the CFG. \'jumpkind\' should be there if it\'s not None.
:param dict blockaddr_to_function: A mapping between block addresses to Function instances.
:param angr.knowledge.FunctionManager known_functions: Already recovered functions.
:param list or None all_edges: All edges going out from src.
:return: None'

def _graph_traversal_handler(self, src, dst, data, blockaddr_to_function, known_functions, all_edges):

    src_addr = src.addr
    src_function = self._addr_to_function(src_addr, blockaddr_to_function, known_functions)
    if (src_addr not in src_function.block_addrs_set):
        n = self.get_any_node(src_addr)
        if (n is None):
            node = src_addr
        else:
            node = self._to_snippet(n)
        self.kb.functions._add_node(src_function.addr, node)
    if (data is None):
        return
    jumpkind = data['jumpkind']
    if (jumpkind == 'Ijk_Ret'):
        n = self.get_any_node(src_addr)
        if (n is None):
            from_node = src_addr
        else:
            from_node = self._to_snippet(n)
        self.kb.functions._add_return_from(src_function.addr, from_node, None)
    if (dst is None):
        return
    dst_addr = dst.addr
    ins_addr = data.get('ins_addr', None)
    stmt_idx = data.get('stmt_idx', None)
    if ((jumpkind == 'Ijk_Call') or jumpkind.startswith('Ijk_Sys')):
        is_syscall = jumpkind.startswith('Ijk_Sys')
        dst_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
        n = self.get_any_node(src_addr)
        if (n is None):
            src_node = src_addr
        else:
            src_node = self._to_snippet(n)
        fakeret_node = (None if (not all_edges) else self._one_fakeret_node(all_edges))
        fakeret_addr = (fakeret_node.addr if (fakeret_node is not None) else None)
        self.kb.functions._add_call_to(src_function.addr, src_node, dst_addr, fakeret_addr, syscall=is_syscall, ins_addr=ins_addr, stmt_idx=stmt_idx)
        if dst_function.returning:
            returning_target = (src.addr + src.size)
            if (returning_target not in blockaddr_to_function):
                if (returning_target not in known_functions):
                    blockaddr_to_function[returning_target] = src_function
                else:
                    self._addr_to_function(returning_target, blockaddr_to_function, known_functions)
            to_outside = (not (blockaddr_to_function[returning_target] is src_function))
            n = self.get_any_node(returning_target)
            if (n is None):
                returning_node = returning_target
            else:
                returning_node = self._to_snippet(n)
            self.kb.functions._add_fakeret_to(src_function.addr, src_node, returning_node, confirmed=True, to_outside=to_outside)
    elif (jumpkind == 'Ijk_Boring'):
        n = self.get_any_node(src_addr)
        if (n is None):
            src_node = src_addr
        else:
            src_node = self._to_snippet(n)
        n = self.get_any_node(dst_addr)
        if (n is None):
            dst_node = dst_addr
        else:
            dst_node = self._to_snippet(n)
        if (not self._addrs_belong_to_same_section(src_addr, dst_addr)):
            _ = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
        if ((dst_addr in known_functions) or ((dst_addr in blockaddr_to_function) and (blockaddr_to_function[dst_addr] is not src_function))):
            dst_function_addr = (blockaddr_to_function[dst_addr].addr if (dst_addr in blockaddr_to_function) else dst_addr)
            self.kb.functions._add_outside_transition_to(src_function.addr, src_node, dst_node, to_function_addr=dst_function_addr)
            _ = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
        else:
            if (dst_addr not in blockaddr_to_function):
                blockaddr_to_function[dst_addr] = src_function
            self.kb.functions._add_transition_to(src_function.addr, src_node, dst_node, ins_addr=ins_addr, stmt_idx=stmt_idx)
    elif (jumpkind == 'Ijk_FakeRet'):
        n = self.get_any_node(src_addr)
        if (n is None):
            src_node = src_addr
        else:
            src_node = self._to_snippet(n)
        n = self.get_any_node(dst_addr)
        if (n is None):
            dst_node = dst_addr
        else:
            dst_node = self._to_snippet(n)
        if (dst_addr not in blockaddr_to_function):
            if (dst_addr not in known_functions):
                blockaddr_to_function[dst_addr] = src_function
                target_function = src_function
            else:
                target_function = self._addr_to_function(dst_addr, blockaddr_to_function, known_functions)
        else:
            target_function = blockaddr_to_function[dst_addr]
        to_outside = (not (target_function is src_function))
        self.kb.functions._add_fakeret_to(src_function.addr, src_node, dst_node, confirmed=True, to_outside=to_outside, to_function_addr=target_function.addr)
    else:
        l.debug('Ignored    jumpkind    %s', jumpkind)
