(self)
Starting from the start_node, explore the entire VFG, and perform the following:
        - Generate def-use chains for all registers and memory addresses using a worklist
Starting from the start_node, explore the entire VFG, and perform the following:
        - Generate def-use chains for all registers and memory addresses using a worklist
Starting from the start_node explore the entire VFG and perform the following : - Generate def - use chains for all registers and memory addresses using a worklist
def _explore(self):
        """
        Starting from the start_node, explore the entire VFG, and perform the following:
        - Generate def-use chains for all registers and memory addresses using a worklist
        """

        # TODO: The worklist algorithm can definitely use some optimizations. It is a future work.

        # The worklist holds individual VFGNodes that comes from the VFG
        # Initialize the worklist with all nodes in VFG
        worklist = list(self._vfg.graph.nodes())
        # Set up a set of worklist for fast inclusion test
        worklist_set = set(worklist)

        # A dict storing defs set
        # variable -> locations
        live_defs_per_node = { }

        while worklist:
            # Pop out a node
            node = worklist[0]
            worklist_set.remove(node)
            worklist = worklist[ 1 : ]

            # Grab all final states. There are usually more than one (one state for each successor), and we gotta
            # process all of them
            final_states = node.final_states

            if node in live_defs_per_node:
                live_defs = live_defs_per_node[node]
            else:
                live_defs = { }
                live_defs_per_node[node] = live_defs

            successing_nodes = self._vfg.graph.successors(node)
            for state in final_states:
                if state.history.jumpkind == 'Ijk_FakeRet' and len(final_states) > 1:
                    # Skip fakerets if there are other control flow transitions available
                    continue

                # TODO: Match the jumpkind
                # TODO: Support cases where IP is undecidable
                corresponding_successors = [ n for n in successing_nodes if n.addr == state.solver.eval(state.ip) ]
                if not corresponding_successors:
                    continue
                successing_node = corresponding_successors[0]

                new_defs = self._track(state, live_defs)

                if successing_node in live_defs_per_node:
                    defs_for_next_node = live_defs_per_node[successing_node]
                else:
                    defs_for_next_node = { }
                    live_defs_per_node[successing_node] = defs_for_next_node

                changed = False
                for var, code_loc_set in new_defs.items():
                    if var not in defs_for_next_node:
                        defs_for_next_node[var] = code_loc_set
                        changed = True

                    else:
                        for code_loc in code_loc_set:
                            if code_loc not in defs_for_next_node[var]:
                                defs_for_next_node[var].add(code_loc)
                                changed = True

                if changed:
                    # Put all reachable successors back to our worklist again
                    if successing_node not in worklist_set:
                        worklist.append(successing_node)
                        worklist_set.add(successing_node)
                    all_successors_dict = networkx.dfs_successors(self._vfg.graph, source=successing_node)
                    for successors in all_successors_dict.values():
                        for s in successors:
                            if s not in worklist_set:
                                worklist.append(s)
                                worklist_set.add(s)
def _explore ( self ) : # TODO: The worklist algorithm can definitely use some optimizations. It is a future work. # The worklist holds individual VFGNodes that comes from the VFG # Initialize the worklist with all nodes in VFG worklist = list ( self . _vfg . graph . nodes ( ) ) # Set up a set of worklist for fast inclusion test worklist_set = set ( worklist ) # A dict storing defs set # variable -> locations live_defs_per_node = { } while worklist : # Pop out a node node = worklist [ 0 ] worklist_set . remove ( node ) worklist = worklist [ 1 : ] # Grab all final states. There are usually more than one (one state for each successor), and we gotta # process all of them final_states = node . final_states if node in live_defs_per_node : live_defs = live_defs_per_node [ node ] else : live_defs = { } live_defs_per_node [ node ] = live_defs successing_nodes = self . _vfg . graph . successors ( node ) for state in final_states : if state . history . jumpkind == 'Ijk_FakeRet' and len ( final_states ) > 1 : # Skip fakerets if there are other control flow transitions available continue # TODO: Match the jumpkind # TODO: Support cases where IP is undecidable corresponding_successors = [ n for n in successing_nodes if n . addr == state . solver . eval ( state . ip ) ] if not corresponding_successors : continue successing_node = corresponding_successors [ 0 ] new_defs = self . _track ( state , live_defs ) if successing_node in live_defs_per_node : defs_for_next_node = live_defs_per_node [ successing_node ] else : defs_for_next_node = { } live_defs_per_node [ successing_node ] = defs_for_next_node changed = False for var , code_loc_set in new_defs . items ( ) : if var not in defs_for_next_node : defs_for_next_node [ var ] = code_loc_set changed = True else : for code_loc in code_loc_set : if code_loc not in defs_for_next_node [ var ] : defs_for_next_node [ var ] . add ( code_loc ) changed = True if changed : # Put all reachable successors back to our worklist again if successing_node not in worklist_set : worklist . append ( successing_node ) worklist_set . add ( successing_node ) all_successors_dict = networkx . dfs_successors ( self . _vfg . graph , source = successing_node ) for successors in all_successors_dict . values ( ) : for s in successors : if s not in worklist_set : worklist . append ( s ) worklist_set . add ( s )