def gen_function(self): ''' returns tuple of: 1) list functions (we can have several functions in case we need to levels of hashing) 2) the operands lookup function (generates the key) ''' action_codegen = actions_codegen.actions_codegen_t(self.cvg.tuple2rule, self.cvg.default_action, self.cvg.strings_dict) self.cvg.action_codegen = action_codegen if self.cvg.no_constraints(): fo = self._gen_empty_function(self.fname) return [fo], None phash = ild_phash.gen_hash(self.cvg) if phash == None: genutil.die("Failed to find perfect hash for %s" % self.fname) if verbosity.vfuncgen(): self.cvg.log.write("%s" % phash) fos, operand_lu_fo = phash.gen_find_fos(self.fname) return fos, operand_lu_fo
def gen_ph_fos(agi, cdict_by_map_opcode, log_fn, ptrn_dict, vv): """ Returns a tuple (phash_lu, phash_fo_list, op_lu_list) * phash_lu: is a traditional 2D dict by (map, opcode) to a hash function name. * phash_fo_list: is a list of all phash function objects created (we might have fos that are not in lookup table - when we have 2-level hash functions). * op_lu_list: is a list for all the operands lookup functions Also writes log file for debugging. """ maps = ild_info.get_maps(agi) log_f = open(log_fn, 'w') cnames = set() # only for logging stats = { '0. #map-opcodes': 0, '1. #entries': 0, '2. #hentries': 0, '3. #hashes': 0, '4. #min_hashes': 0, '5. #cdict_size_1_to_10': 0, '6. #cdict_size_10_to_20': 0, '7. #cdict_size_20_to_100': 0, '8. #cdict_size_at_least_100': 0 } lu_fo_list = [] op_lu_map = {} # fn name -> fn obj phash_lu = {} # map, opcode -> fn name for insn_map in maps: phash_lu[insn_map] = {} zeros = 0 for opcode in range(0, 256): opcode = hex(opcode) cdict = cdict_by_map_opcode[insn_map][opcode] if cdict: stats['0. #map-opcodes'] += 1 stats['1. #entries'] += len(cdict.tuple2rule) cnames = cnames.union(set(cdict.cnames)) _log(log_f,'XYZ VV: {} MAP:{} OPCODE:{}:\n{}\n'.format( vv, insn_map, opcode, cdict)) phash = ild_phash.gen_hash(cdict) if phash: _log(log_f,"%s" % phash) phash_id = 'map%s_opcode%s_vv%d' % (insn_map, opcode, vv) fname = "%s_%s" % (_find_fn_pfx,phash_id) (fo_list, op_lu_fo) = phash.gen_find_fos(fname) lu_fo_list.extend(fo_list) #hold only one instance of each function if op_lu_fo: if op_lu_fo.function_name not in op_lu_map: op_lu_map[op_lu_fo.function_name] = op_lu_fo for fo in fo_list: _log(log_f,'//find function:\n') _log(log_f,fo.emit()) _log(log_f,'-----------------------------\n') #FIXME: assumption: L2 function is last in the list #maybe return dict or tuple to make a distinction between #L2 and L1 functions? phlu_fn = lu_fo_list[-1] phash_lu[insn_map][opcode] = phlu_fn.function_name phash.update_stats(stats) else: _log(log_f,'---NOPHASH-----\n') msg = "Failed to gen phash for map %s opcode %s" ildutil.ild_err(msg % (insn_map, opcode)) else: phash_lu[insn_map][opcode] = '(xed3_find_func_t)0' zeros = zeros + 1 if zeros == 256: # all zero... shortcut to avoid scanning maps for "all-zeros" _log(log_f, "ZEROING phash_lu for map {} vv {}\n".format(insn_map, vv)) phash_lu[insn_map] = None _log(log_f,"cnames: %s\n" %cnames) for key in sorted(stats.keys()): _log(log_f,"%s %s\n" % (key,stats[key])) log_f.close() return phash_lu, lu_fo_list, list(op_lu_map.values())