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 (exp ~ ('cd', int:idx)) and idx in func.params: return ('param', func.params[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
for m in mlist: if m ~ ('type', 256, ('field', 0, ('stor', ('length', _)))): continue if get_loc(m) == e_loc: assert m ~ ('type', _, ('field', :m_off, _)) if m_off != e_off: return exp else: return stor else: 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 line ~ ('store', :size, :off, :idx, :val): return ('set', ('stor', size, off, idx), val) else: return line def loc_to_name(exp): if exp ~ ('loc', int:num): if num < 1000: return ('name', 'stor' + str(num), num)
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 rem_masks(exp): if exp ~ ('bool', ('cd', int:idx)): if idx in self.params and \ self.params[idx][0] == 'bool': return ('cd', idx) elif exp ~ ('mask_shl', :size, 0, 0, ('cd', int: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())) def ast_length(self):
def make_ast(trace): def store_to_set(line): if line ~ ('store', :size, :off, :idx, :val): return ('set', ('stor', size, off, idx), val) else: return line def mask_storage(exp): if exp ~ ('stor', :size, :off, :idx): return ('mask_shl', 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)