static void get_xrefs_to_vtbl()
{
	ea_t cur_vt_ea = vtbl_t_list[current_line_pos].ea_begin;
	for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr))
	{
		qstring name;
		get_func_name2(&name, addr);

		xref_addr.push_back(addr);

		qstring tmp;
		tmp.cat_sprnt(" 0x%x:  %s", addr, name);
		xref_list.push_back(tmp);
	}
}
inline bool func_name_has_prefix(qstring &prefix, ea_t startEA) {
	qstring func_name;
	
	if (prefix.length() <= 0)
		return false;
	
	if (get_func_name2(&func_name, startEA) == 0)
		return false;
	
	if (func_name.length() <= 0)
		return false;
	
	if (func_name.find(prefix.c_str(), 0) != 0)
		return false;
	
	return true;
}
bool idaapi dump_funcs_ctree(void *ud, qstring &crypto_prefix) 
{
	logmsg(DEBUG, "dump_funcs_ctree entered\n");

	std::map<ea_t, ctree_dump_line> data_to_dump;

	// enumerate through all the functions in the idb file
	bool heuristic_flag;
	size_t count = 0, heur_count = 0, crypto_count = 0;
	size_t total_func_qty = get_func_qty();
	for (size_t i = 0 ; i < total_func_qty ; i ++) {
		heuristic_flag = 0;
		
		func_t *function = getn_func(i);
		if (function != NULL) {
			bool crypto_flag = func_name_has_prefix(crypto_prefix, function->startEA);
			
			// skip libs that are not marked as crypto
			if ( ((function->flags & FUNC_LIB) != 0) && !crypto_flag )
				continue;
			
			// From this point on, we have a function outside of lib or a crypto one
			
			// Ignore functions less than MIN_FUNC_SIZE_DUMP bytes
			if ( ((function->endEA - function->startEA) < MIN_FUNC_SIZE_DUMP) && !crypto_flag )
				continue;
			
			// If function is bigger than MIN_HEURISTIC_FUNC_SIZE_DUMP, mark as being triggered by the heuristic
			if (function->endEA - function->startEA > MIN_HEURISTIC_FUNC_SIZE_DUMP)
				heuristic_flag = 1;
				
			// dump up to N_CRYPTO_FUNCS_TO_DUMP crypto functions
			// dump up to N_HEUR_FUNCS_TO_DUMP heuristic functions
			// at least N_FUNCS_TO_DUMP functions will be dumped
			if ((count < N_FUNCS_TO_DUMP) || (crypto_flag && (crypto_count < N_CRYPTO_FUNCS_TO_DUMP)) || (heuristic_flag && (heur_count < N_HEUR_FUNCS_TO_DUMP))) {
				hexrays_failure_t hf;
				cfuncptr_t cfunc = decompile(function, &hf);

				logmsg(DEBUG, "\nafter decompile()\n");
				if (cfunc != NULL) {
					ctree_dumper_t ctree_dumper;
					ctree_dumper.apply_to(&cfunc->body, NULL);
					
					ctree_dump_line func_dump;
					func_dump.ctree_dump = ctree_dumper.ctree_dump;
					func_dump.ctree_for_hash = ctree_dumper.ctree_for_hash;

					func_dump.func_depth = -1;

					func_dump.func_start = function->startEA;
					func_dump.func_end = function->endEA;

					qstring func_name;
					if (get_func_name2(&func_name, function->startEA) != 0) {
						if (func_name.length() > 0) {
							func_dump.func_name = func_name;
						}
					}
					
					func_parent_iterator_t fpi(function);
					for (ea_t addr = get_first_cref_to(function->startEA); addr != BADADDR; addr = get_next_cref_to(function->startEA, addr)) {
						func_t *referer = get_func(addr);
						if (referer != NULL) {
							func_dump.referres.push_back(referer->startEA);
						}
					}
					
					func_dump.heuristic_flag = heuristic_flag; // 0 or 1 depending on code above
					if (heuristic_flag)
						heur_count++;

					if (crypto_flag)
						crypto_count++;
					
					count++;
					
					data_to_dump[function->startEA] = func_dump;
				}
			}
		}
	}
	
	dump_ctrees_in_file(data_to_dump, crypto_prefix);

	return true;
}
bool idaapi extract_all_types(void *ud)
{
	logmsg(DEBUG, "extract_types()");

	// find vtables in the binary
	search_objects(false);

	qvector <VTBL_info_t>::iterator vtbl_iter;

	std::map<ea_t, VTBL_info_t> vtbl_map;
	for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++)
		vtbl_map[(*vtbl_iter).ea_begin] = (*vtbl_iter);

	int file_id = create_open_file("types.txt");
	if (file_id != BADADDR) {
		int struct_no = 0;

		for (vtbl_iter = vtbl_t_list.begin(); vtbl_iter != vtbl_t_list.end(); vtbl_iter++) {
			qstring info_msg;
			info_msg.cat_sprnt("Processing vtable %s\n", (*vtbl_iter).vtbl_name.c_str());
			logmsg(DEBUG, info_msg.c_str());

			qstring type_name;
			type_name.sprnt("struc_2_%d", struct_no);

			ea_t cur_vt_ea = (*vtbl_iter).ea_begin;
			int struct_subno = 0;

			qvector <qstring> types_to_merge;
			for (ea_t addr = get_first_dref_to(cur_vt_ea); addr != BADADDR; addr = get_next_dref_to(cur_vt_ea, addr)) {
				qstring name;
				get_func_name2(&name, addr);



				qstring info_msg1;
				info_msg1.cat_sprnt("\t%s", name.c_str());
				logmsg(DEBUG, info_msg1.c_str());

				func_t *pfn = get_func(addr);
				if (pfn != NULL) {
					hexrays_failure_t hf;
					cfuncptr_t cfunc = decompile(pfn, &hf);
					if (cfunc != NULL) {
						qstring var_name;
						info_msg.clear();

						if (find_var(cfunc, (*vtbl_iter).vtbl_name, var_name)) {
							info_msg.cat_sprnt(" : %s\n", var_name.c_str());
							logmsg(DEBUG, info_msg.c_str());

							qstring sub_type_name = type_name;
							sub_type_name.cat_sprnt("_%d", struct_subno);
							struct_subno++;

							if (reconstruct_type(cfunc, var_name, sub_type_name)) {
								if (check_subtype((*vtbl_iter), sub_type_name)) {
									types_to_merge.push_back(sub_type_name);
								}
							}
						}
						else {
							info_msg.cat_sprnt(" : none\n", var_name.c_str());
							logmsg(DEBUG, info_msg.c_str());
						}
					}
				}
			}

			struct_no++;

			merge_types(types_to_merge, type_name);
			dump_type_info(file_id, (*vtbl_iter), type_name, vtbl_map);
		}

		qclose(file_id);
	}

	return true;
}