'If an argument passed from the stack (i.e. dword ptr [ebp+4h]) is saved to a local variable on the stack at the
beginning of the function, and this local variable was never modified anywhere in this function, and no pointer
of any stack variable is saved in any register, then we can replace all references to this local variable to
that argument instead.
:param function:
:param networkx.MultiDiGraph data_graph:
:return:'

def _redundant_stack_variable_removal(self, function, data_graph):

    stack_ptrs = []
    sp_offset = self.project.arch.registers['esp'][0]
    bp_offset = self.project.arch.registers['ebp'][0]
    for n in data_graph.nodes_iter():
        if (isinstance(n.variable, SimRegisterVariable) and (n.variable.reg in (sp_offset, bp_offset))):
            stack_ptrs.append(n)
    for stack_ptr in stack_ptrs:
        out_edges = data_graph.out_edges(stack_ptr, data=True)
        for (_, dst, data) in out_edges:
            if (('type' in data) and (data['type'] == 'kill')):
                continue
            if (isinstance(dst.variable, SimRegisterVariable) and (dst.variable.reg < 40) and (dst.variable.reg not in (sp_offset, bp_offset))):
                l.debug('Function    %s    does    not    satisfy    requirements    of    redundant    stack    variable    removal.', repr(function))
                return
    argument_variables = []
    for n in data_graph.nodes_iter():
        if (isinstance(n.variable, SimStackVariable) and (n.variable.base == 'bp') and (n.variable.offset >= 0)):
            argument_variables.append(n)
    if (not argument_variables):
        return
    argument_to_local = {}
    argument_register_as_retval = set()
    for argument_variable in argument_variables:
        successors0 = data_graph.successors(argument_variable)
        if (not successors0):
            continue
        if (len(successors0) != 1):
            continue
        if isinstance(successors0[0].variable, SimRegisterVariable):
            out_edges = data_graph.out_edges(successors0[0], data=True)
            successors1 = [s for (_, s, data) in out_edges if (('type' not in data) or (data['type'] != 'kill'))]
            if (len(successors1) == 1):
                successor1 = successors1[0]
                if isinstance(successor1.variable, SimStackVariable):
                    if (((successor1.variable.base == 'sp') and (successor1.variable.offset > 0)) or ((successor1.variable.base == 'bp') and (successor1.variable.offset < 0))):
                        argument_to_local[argument_variable] = successor1
            if (successors0[0].variable.reg == self.project.arch.registers['eax'][0]):
                killers = [s for (_, s, data) in out_edges if (('type' in data) and (data['type'] == 'kill'))]
                if (not killers):
                    argument_register_as_retval.add(argument_variable)
        else:
            import ipdb
            ipdb.set_trace()
    redundant_stack_variables = []
    for (argument, local_var) in argument_to_local.iteritems():
        out_edges = data_graph.out_edges(local_var, data=True)
        consuming_locs = []
        for (_, consumer, data) in out_edges:
            consuming_locs.append(consumer.location)
            if (('type' in data) and (data['type'] == 'kill')):
                break
        else:
            rsv = RedundantStackVariable(argument, local_var, consuming_locs)
            if (argument in argument_register_as_retval):
                rsv.argument_register_as_retval = True
            redundant_stack_variables.append(rsv)
    self.redundant_stack_variables.extend(redundant_stack_variables)
