def as_paths(trace, path=None): assert type(trace) == list path = path or tuple() # self.find_offsets() trace = replace_f(trace, make_fands) for line in trace: if opcode(line) == "if": # assumes 'ifs' end trace cond, if_true, if_false = line[1], line[2], line[3] return as_paths(if_true, path + (cond,)) + as_paths( if_false, path + (is_zero(cond),) ) if opcode(line) == "LOOP": path += (("LOOP", line[2]),) return as_paths(line[1], path) path += (line,) # pprint_logic() return (list(path),)
def postprocess(self): try: self.stor_defs = sparser.rewrite_functions(self.functions) except Exception: # this is critical, because it causes full contract to display very # badly, and cannot be limited in scope to just one affected function logger.exception( "Storage postprocessing failed. This is very bad!") self.stor_defs = {} for func in self.functions: def replace_names(exp): if (m := match(exp, ("cd", ":int:idx"))) and m.idx in func.params: return ("param", func.params[m.idx][1]) return exp func.trace = replace_f(func.trace, replace_names)
def meta_fold_paths(paths): for_merge = [] for r in paths: assert type(r) in (tuple, list) if len(r) > 0: for_merge.append(r) output = fold_paths(for_merge) assert type(output) == list output = flatten( output ) # converts if-else statements into if statements, if possible output = cleanup_ors(output) output = make_ifs(output) output = merge_ifs(output) output = replace_f(output, unmake_fands) return output
array is when you add to a loc """ def add_to_arr(exp): if m := match(exp, ("add", ":left", ":right")): left, right = m.left, m.right if opcode(left) == "loc": right, left = left, right if opcode(right) == "loc": return ("array", left, right) return exp storages = replace_f(storages, add_to_arr) """ (s 256 0 (add 3 (mul 0.125 idx))) """ res = [] for s in storages: op, size, offset, idx = s assert op == "stor" if m := match(idx, ("add", ":e")): idx = m.e if opcode(idx) == "add" and get_loc(idx) is None:
def make_ast(trace): def store_to_set(line): if m := match(line, ("store", ":size", ":off", ":idx", ":val")): return ("set", ("stor", m.size, m.off, m.idx), m.val) else: return line def mask_storage(exp): if m := match(exp, ("stor", ":size", ":off", ":idx")): return ("mask_shl", m.size, 0, 0, exp) else: return exp trace = replace_lines(trace, store_to_set) trace = replace_f(trace, mask_storage) return trace def format_exp(exp): if type(exp) == str: return f'"{exp}"' if type(exp) == int: if exp > 10**6 and exp % 10**6 != 0: return hex(exp) else: return str(exp) elif type(exp) != list: return str(exp) else:
idx = m.idx if idx in self.params and self.params[idx][0] == "bool": return ("cd", idx) elif m := match(exp, ("mask_shl", ":size", 0, 0, ("cd", ":int:idx"))): size, idx = m.size, m.idx if idx in self.params: kind = self.params[idx][0] def_size = type_to_mask(kind) if size == def_size: return ("cd", idx) return exp return replace_f(trace, rem_masks) def make_names(self): new_name = self.name.split("(")[0] self.name = "{}({})".format( new_name, ", ".join( (p[0] + " " + p[1]) for p in self.params.values())) self.color_name = "{}({})".format( new_name, ", ".join((p[0] + " " + COLOR_GREEN + p[1] + ENDC) for p in self.params.values()), ) self.abi_name = "{}({})".format( new_name, ",".join(p[0] for p in self.params.values()))
for mask in stor_loc_to_masks[e_loc]: if not match(mask, ("type", 256, ("field", 0, ("stor", ("length", Any))))): assert (m := match(mask, ("type", Any, ("field", ":m_off", Any)))) if m.m_off != e_off: return exp return stor return exp for f in self.functions: f.ast = replace_f(f.ast, cleanup) def make_ast(self, trace): trace = folder.fold(trace) def store_to_set(line): if m := match(line, ("store", ":size", ":off", ":idx", ":val")): return ("set", ("stor", m.size, m.off, m.idx), m.val) else: return line def loc_to_name(exp): if m := match(exp, ("loc", ":int:num")): num = m.num if num < 1000: return ("name", "stor" + str(num), num)