def _set(self, dst, src): """ Special cases: * if dst is an ExprSlice, expand it to affect the full Expression * if dst already known, sources are merged """ if dst.size != src.size: raise RuntimeError("sanitycheck: args must have same size! %s" % ([(str(arg), arg.size) for arg in [dst, src]])) if isinstance(dst, m2_expr.ExprSlice): # Complete the source with missing slice parts new_dst = dst.arg rest = [(m2_expr.ExprSlice(dst.arg, r[0], r[1]), r[0], r[1]) for r in dst.slice_rest()] all_a = [(src, dst.start, dst.stop)] + rest all_a.sort(key=lambda x: x[1]) args = [expr for (expr, _, _) in all_a] new_src = m2_expr.ExprCompose(*args) else: new_dst, new_src = dst, src if new_dst in self._assigns and isinstance(new_src, m2_expr.ExprCompose): if not isinstance(self[new_dst], m2_expr.ExprCompose): # prev_RAX = 0x1122334455667788 # input_RAX[0:8] = 0x89 # final_RAX -> ? (assignment are in parallel) raise RuntimeError("Concurent access on same bit not allowed") # Consider slice grouping expr_list = [(new_dst, new_src), (new_dst, self[new_dst])] # Find collision e_colision = reduce(lambda x, y: x.union(y), (self.get_modified_slice(dst, src) for (dst, src) in expr_list), set()) # Sort interval collision known_intervals = sorted([(x[1], x[2]) for x in e_colision]) for i, (_, stop) in enumerate(known_intervals[:-1]): if stop > known_intervals[i + 1][0]: raise RuntimeError( "Concurent access on same bit not allowed") # Fill with missing data missing_i = get_missing_interval(known_intervals, 0, new_dst.size) remaining = ((m2_expr.ExprSlice(new_dst, *interval), interval[0], interval[1]) for interval in missing_i) # Build the merging expression args = list(e_colision.union(remaining)) args.sort(key=lambda x: x[1]) starts = [start for (_, start, _) in args] assert len(set(starts)) == len(starts) args = [expr for (expr, _, _) in args] new_src = m2_expr.ExprCompose(*args) self._assigns[new_dst] = new_src
def __setitem__(self, dst, src): """ Special cases: * if dst is an ExprSlice, expand it to affect the full Expression * if dst already known, sources are merged """ if dst.size != src.size: raise RuntimeError( "sanitycheck: args must have same size! %s" % ([(str(arg), arg.size) for arg in [dst, src]])) if isinstance(dst, m2_expr.ExprSlice): # Complete the source with missing slice parts new_dst = dst.arg rest = [(m2_expr.ExprSlice(dst.arg, r[0], r[1]), r[0], r[1]) for r in dst.slice_rest()] all_a = [(src, dst.start, dst.stop)] + rest all_a.sort(key=lambda x: x[1]) new_src = m2_expr.ExprCompose(all_a) else: new_dst, new_src = dst, src if new_dst in self and isinstance(new_src, m2_expr.ExprCompose): if not isinstance(self[new_dst], m2_expr.ExprCompose): # prev_RAX = 0x1122334455667788 # input_RAX[0:8] = 0x89 # final_RAX -> ? (assignment are in parallel) raise RuntimeError("Concurent access on same bit not allowed") # Consider slice grouping expr_list = [(new_dst, new_src), (new_dst, self[new_dst])] # Find collision e_colision = reduce(lambda x, y: x.union(y), (self.get_modified_slice(dst, src) for (dst, src) in expr_list), set()) # Sort interval collision known_intervals = sorted([(x[1], x[2]) for x in e_colision]) for i, (_, stop) in enumerate(known_intervals[:-1]): if stop > known_intervals[i + 1][0]: raise RuntimeError( "Concurent access on same bit not allowed") # Fill with missing data missing_i = get_missing_interval(known_intervals, 0, new_dst.size) remaining = ((m2_expr.ExprSlice(new_dst, *interval), interval[0], interval[1]) for interval in missing_i) # Build the merging expression new_src = m2_expr.ExprCompose(e_colision.union(remaining)) super(AssignBlock, self).__setitem__(new_dst, new_src)
def merge_multi_affect(self, affect_list): """ If multiple affection to a same ExprId are present in @affect_list, merge them (in place). For instance, XCGH AH, AL semantic is [ RAX = {RAX[0:8],0,8, RAX[0:8],8,16, RAX[16:64],16,64} RAX = {RAX[8:16],0,8, RAX[8:64],8,64} ] This function will update @affect_list to replace previous ExprAff by [ RAX = {RAX[8:16],0,8, RAX[0:8],8,16, RAX[16:64],16,64} ] """ # Extract side effect effect = {} for expr in affect_list: effect[expr.dst] = effect.get(expr.dst, []) + [expr] # Find candidates for dst, expr_list in effect.items(): if len(expr_list) <= 1: continue # Only treat ExprCompose list if any(map(lambda e: not(isinstance(e.src, m2_expr.ExprCompose)), expr_list)): continue # Find collision e_colision = reduce(lambda x, y: x.union(y), (e.get_modified_slice() for e in expr_list), set()) # Sort interval collision known_intervals = sorted([(x[1], x[2]) for x in e_colision]) # Fill with missing data missing_i = get_missing_interval(known_intervals, 0, dst.size) remaining = ((m2_expr.ExprSlice(dst, *interval), interval[0], interval[1]) for interval in missing_i) # Build the merging expression slices = sorted(e_colision.union(remaining), key=lambda x: x[1]) final_dst = m2_expr.ExprCompose(slices) # Remove unused expression for expr in expr_list: affect_list.remove(expr) # Add the merged one affect_list.append(m2_expr.ExprAff(dst, final_dst))
def merge_multi_affect(self, affect_list): """ If multiple affection to a same ExprId are present in @affect_list, merge them (in place). For instance, XCGH AH, AL semantic is [ RAX = {RAX[0:8],0,8, RAX[0:8],8,16, RAX[16:64],16,64} RAX = {RAX[8:16],0,8, RAX[8:64],8,64} ] This function will update @affect_list to replace previous ExprAff by [ RAX = {RAX[8:16],0,8, RAX[0:8],8,16, RAX[16:64],16,64} ] """ # Extract side effect effect = {} for expr in affect_list: effect[expr.dst] = effect.get(expr.dst, []) + [expr] # Find candidates for dst, expr_list in effect.items(): if len(expr_list) <= 1: continue # Only treat ExprCompose list if any(map(lambda e: not(isinstance(e.src, m2_expr.ExprCompose)), expr_list)): continue # Find collision e_colision = reduce(lambda x, y: x.union(y), (e.get_modified_slice() for e in expr_list), set()) # Sort interval collision known_intervals = sorted([(x[1], x[2]) for x in e_colision]) # Fill with missing data missing_i = get_missing_interval(known_intervals, 0, dst.size) remaining = ((m2_expr.ExprSlice(dst, *interval), interval[0], interval[1]) for interval in missing_i) # Build the merging expression slices = sorted(e_colision.union(remaining), key=lambda x: x[1]) final_dst = m2_expr.ExprCompose(slices) # Remove unused expression for expr in expr_list: affect_list.remove(expr) # Add the merged one affect_list.append(m2_expr.ExprAff(dst, final_dst))