'Construct the data dependence graph.
We track the following types of dependence:
- (Intra-IRSB) temporary variable dependencies
- Register dependencies
- Memory dependencies, although it\'s very limited. See below.
We track the following types of memory access:
- (Intra-functional) Stack read/write.
Trace changes of stack pointers inside a function, and the dereferences of stack pointers.
- (Inter-functional) Stack read/write.
- (Global) Static memory positions.
Keep a map of all accessible memory positions to their source statements per function. After that, we
traverse the CFG and link each pair of reads/writes together in the order of control-flow.
We do not track the following types of memory access
- Symbolic memory access
Well, they cannot be tracked under fastpath mode (which is the mode we are generating the CTF) anyways.'

def _construct(self):

    worklist = []
    worklist_set = set()
    for n in self._cfg.graph.nodes_iter():
        if (self._cfg.graph.in_degree(n) == 0):
            job = DDGJob(n, 0)
            self._worklist_append(job, worklist, worklist_set)
    live_defs_per_node = {}
    while worklist:
        ddg_job = worklist[0]
        (node, call_depth) = (ddg_job.cfg_node, ddg_job.call_depth)
        worklist = worklist[1:]
        worklist_set.remove(node)
        final_states = node.final_states
        if (node in live_defs_per_node):
            live_defs = live_defs_per_node[node]
        else:
            live_defs = LiveDefinitions()
            live_defs_per_node[node] = live_defs
        successing_nodes = self._cfg.graph.successors(node)
        for state in final_states:
            if ((state.history.jumpkind == 'Ijk_FakeRet') and (len(final_states) > 1)):
                continue
            new_call_depth = call_depth
            if (state.history.jumpkind == 'Ijk_Call'):
                new_call_depth += 1
            elif (state.history.jumpkind == 'Ijk_Ret'):
                new_call_depth -= 1
            if ((self._call_depth is not None) and (call_depth > self._call_depth)):
                l.debug('Do    not    trace    into    %s    due    to    the    call    depth    limit', state.ip)
                continue
            new_defs = self._track(state, live_defs, (node.irsb.statements if (node.irsb is not None) else None))
            changed = False
            for successing_node in successing_nodes:
                if (((state.history.jumpkind == 'Ijk_Call') or state.history.jumpkind.startswith('Ijk_Sys')) and (state.ip.symbolic or (successing_node.addr != state.se.any_int(state.ip)))):
                    filtered_defs = LiveDefinitions()
                    for (variable, locs) in new_defs.iteritems():
                        if isinstance(variable, SimRegisterVariable):
                            if (variable.reg in (self.project.arch.registers['eax'][0], self.project.arch.registers['ecx'][0], self.project.arch.registers['edx'][0])):
                                continue
                        filtered_defs.add_defs(variable, locs)
                    new_defs = filtered_defs
                if (successing_node in live_defs_per_node):
                    defs_for_next_node = live_defs_per_node[successing_node]
                else:
                    defs_for_next_node = LiveDefinitions()
                    live_defs_per_node[successing_node] = defs_for_next_node
                for (var, code_loc_set) in new_defs.iteritems():
                    l.debug('Adding    %d    new    defitions    for    variable    %s.', len(code_loc_set), var)
                    changed |= defs_for_next_node.add_defs(var, code_loc_set)
            if changed:
                if ((self._call_depth is None) or ((self._call_depth is not None) and (0 <= new_call_depth <= self._call_depth))):
                    for successing_node in successing_nodes:
                        nw = DDGJob(successing_node, new_call_depth)
                        self._worklist_append(nw, worklist, worklist_set)
