static int __core_analysis_fcn(RzCore *core, ut64 at, ut64 from, int reftype, int depth) {
	if (depth < 0) {
		//		printf ("Too deep for 0x%08"PFMT64x"\n", at);
		//		rz_sys_backtrace ();
		return false;
	}
	int has_next = rz_config_get_i(core->config, "analysis.hasnext");
	RzAnalysisHint *hint = NULL;
	int i, nexti = 0;
	ut64 *next = NULL;
	int fcnlen;
	RzAnalysisFunction *fcn = rz_analysis_function_new(core->analysis);
	const char *fcnpfx = rz_config_get(core->config, "analysis.fcnprefix");
	if (!fcnpfx) {
		fcnpfx = "fcn";
	}
	if (!fcn) {
		eprintf("Error: new (fcn)\n");
		return false;
	}
	fcn->cc = rz_str_constpool_get(&core->analysis->constpool, rz_analysis_cc_default(core->analysis));
	rz_warn_if_fail(!core->analysis->sdb_cc->path || fcn->cc);
	hint = rz_analysis_hint_get(core->analysis, at);
	if (hint && hint->bits == 16) {
		// expand 16bit for function
		fcn->bits = 16;
	} else {
		fcn->bits = core->analysis->bits;
	}
	fcn->addr = at;
	fcn->name = getFunctionName(core, at);

	if (!fcn->name) {
		fcn->name = rz_str_newf("%s.%08" PFMT64x, fcnpfx, at);
	}
	rz_analysis_fcn_invalidate_read_ahead_cache();
	do {
		RzFlagItem *f;
		ut64 delta = rz_analysis_function_linear_size(fcn);
		if (!rz_io_is_valid_offset(core->io, at + delta, !core->analysis->opt.noncode)) {
			goto error;
		}
		if (rz_cons_is_breaked()) {
			break;
		}
		fcnlen = rz_analysis_fcn(core->analysis, fcn, at + delta, core->analysis->opt.bb_max_size, reftype);
		if (core->analysis->opt.searchstringrefs) {
			rz_analysis_set_stringrefs(core, fcn);
		}
		if (fcnlen == 0) {
			if (core->analysis->verbose) {
				eprintf("Analyzed function size is 0 at 0x%08" PFMT64x "\n", at + delta);
			}
			goto error;
		}
		if (fcnlen < 0) {
			switch (fcnlen) {
			case RZ_ANALYSIS_RET_ERROR:
			case RZ_ANALYSIS_RET_NEW:
			case RZ_ANALYSIS_RET_DUP:
			case RZ_ANALYSIS_RET_END:
				break;
			default:
				eprintf("Oops. Negative fcnsize at 0x%08" PFMT64x " (%d)\n", at, fcnlen);
				continue;
			}
		}
		f = rz_core_flag_get_by_spaces(core->flags, fcn->addr);
		set_fcn_name_from_flag(fcn, f, fcnpfx);

		if (fcnlen == RZ_ANALYSIS_RET_ERROR ||
			(fcnlen == RZ_ANALYSIS_RET_END && !rz_analysis_function_realsize(fcn))) { /* Error analyzing function */
			if (core->analysis->opt.followbrokenfcnsrefs) {
				rz_analysis_analyze_fcn_refs(core, fcn, depth);
			}
			goto error;
		} else if (fcnlen == RZ_ANALYSIS_RET_END) { /* Function analysis complete */
			f = rz_core_flag_get_by_spaces(core->flags, fcn->addr);
			if (f && f->name && strncmp(f->name, "sect", 4)) { /* Check if it's already flagged */
				char *new_name = strdup(f->name);
				if (is_entry_flag(f)) {
					RzListIter *iter;
					RzBinSymbol *sym;
					const RzList *syms = rz_bin_get_symbols(core->bin);
					ut64 baddr = rz_config_get_i(core->config, "bin.baddr");
					rz_list_foreach (syms, iter, sym) {
						if ((sym->paddr + baddr) == fcn->addr && !strcmp(sym->type, RZ_BIN_TYPE_FUNC_STR)) {
							free(new_name);
							new_name = rz_str_newf("sym.%s", sym->name);
							break;
						}
					}
				}
				free(fcn->name);
				fcn->name = new_name;
			} else {
				RZ_FREE(fcn->name);
				const char *fcnpfx = rz_analysis_fcntype_tostring(fcn->type);
				if (!fcnpfx || !*fcnpfx || !strcmp(fcnpfx, "fcn")) {
					fcnpfx = rz_config_get(core->config, "analysis.fcnprefix");
				}
				fcn->name = rz_str_newf("%s.%08" PFMT64x, fcnpfx, fcn->addr);
				autoname_imp_trampoline(core, fcn);
				/* Add flag */
				rz_flag_space_push(core->flags, RZ_FLAGS_FS_FUNCTIONS);
				rz_flag_set(core->flags, fcn->name, fcn->addr, rz_analysis_function_linear_size(fcn));
				rz_flag_space_pop(core->flags);
			}

			/* New function: Add initial xref */
			if (from != UT64_MAX) {
				rz_analysis_xrefs_set(core->analysis, from, fcn->addr, reftype);
			}
			// XXX: this is wrong. See CID 1134565
			rz_analysis_add_function(core->analysis, fcn);
			if (has_next) {
				ut64 addr = rz_analysis_function_max_addr(fcn);
				RzIOMap *map = rz_io_map_get(core->io, addr);
				// only get next if found on an executable section
				if (!map || (map && map->perm & RZ_PERM_X)) {
					for (i = 0; i < nexti; i++) {
						if (next[i] == addr) {
							break;
						}
					}
					if (i == nexti) {
						ut64 at = rz_analysis_function_max_addr(fcn);
						while (true) {
							ut64 size;
							RzAnalysisMetaItem *mi = rz_meta_get_at(core->analysis, at, RZ_META_TYPE_ANY, &size);
							if (!mi) {
								break;
							}
							at += size;
						}
						// TODO: ensure next address is function after padding (nop or trap or wat)
						// XXX noisy for test cases because we want to clear the stderr
						rz_cons_clear_line(1);
						loganalysis(fcn->addr, at, 10000 - depth);
						next = next_append(next, &nexti, at);
					}
				}
			}
			if (!rz_analysis_analyze_fcn_refs(core, fcn, depth)) {
				goto error;
			}
		}
	} while (fcnlen != RZ_ANALYSIS_RET_END);
	rz_list_free(core->analysis->leaddrs);
	core->analysis->leaddrs = NULL;
	if (has_next) {
		for (i = 0; i < nexti; i++) {
			if (!next[i] || rz_analysis_get_fcn_in(core->analysis, next[i], 0)) {
				continue;
			}
			rz_core_analysis_fcn(core, next[i], from, 0, depth - 1);
		}
		free(next);
	}
	if (core->analysis->cur && core->analysis->cur->arch && !strcmp(core->analysis->cur->arch, "x86")) {
		rz_analysis_function_check_bp_use(fcn);
		if (fcn && !fcn->bp_frame) {
			rz_analysis_function_delete_vars_by_kind(fcn, RZ_ANALYSIS_VAR_KIND_BPV);
		}
	}
	rz_analysis_hint_free(hint);
	return true;

error:
	rz_list_free(core->analysis->leaddrs);
	core->analysis->leaddrs = NULL;
	// ugly hack to free fcn
	if (fcn) {
		if (!rz_analysis_function_realsize(fcn) || fcn->addr == UT64_MAX) {
			rz_analysis_function_free(fcn);
			fcn = NULL;
		} else {
			// TODO: mark this function as not properly analyzed
			if (!fcn->name) {
				// XXX dupped code.
				fcn->name = rz_str_newf(
					"%s.%08" PFMT64x,
					rz_analysis_fcntype_tostring(fcn->type),
					at);
				/* Add flag */
				rz_flag_space_push(core->flags, RZ_FLAGS_FS_FUNCTIONS);
				rz_flag_set(core->flags, fcn->name, at, rz_analysis_function_linear_size(fcn));
				rz_flag_space_pop(core->flags);
			}
			rz_analysis_add_function(core->analysis, fcn);
		}
		if (fcn && has_next) {
			ut64 newaddr = rz_analysis_function_max_addr(fcn);
			RzIOMap *map = rz_io_map_get(core->io, newaddr);
			if (!map || (map && (map->perm & RZ_PERM_X))) {
				next = next_append(next, &nexti, newaddr);
				for (i = 0; i < nexti; i++) {
					if (!next[i]) {
						continue;
					}
					rz_core_analysis_fcn(core, next[i], next[i], 0, depth - 1);
				}
				free(next);
			}
		}
	}
	if (fcn && core->analysis->cur && core->analysis->cur->arch && !strcmp(core->analysis->cur->arch, "x86")) {
		rz_analysis_function_check_bp_use(fcn);
		if (!fcn->bp_frame) {
			rz_analysis_function_delete_vars_by_kind(fcn, RZ_ANALYSIS_VAR_KIND_BPV);
		}
	}
	rz_analysis_hint_free(hint);
	return false;
}
static int __core_analysis_fcn(RzCore *core, ut64 at, ut64 from, int reftype, int depth) {
	if (depth < 0) {
		 
		 
		return false;
	}
	int has_next = rz_config_get_i(core->config, "analysis.hasnext");
	RzAnalysisHint *hint = NULL;
	int i, nexti = 0;
	ut64 *next = NULL;
	int fcnlen;
	RzAnalysisFunction *fcn = rz_analysis_function_new(core->analysis);
	const char *fcnpfx = rz_config_get(core->config, "analysis.fcnprefix");
	if (!fcnpfx) {
		fcnpfx = "fcn";
	}
	if (!fcn) {
		eprintf("Error: new (fcn)\n");
		return false;
	}
	fcn->cc = rz_str_constpool_get(&core->analysis->constpool, rz_analysis_cc_default(core->analysis));
	rz_warn_if_fail(!core->analysis->sdb_cc->path || fcn->cc);
	hint = rz_analysis_hint_get(core->analysis, at);
	if (hint && hint->bits == 16) {
		 
		fcn->bits = 16;
	} else {
		fcn->bits = core->analysis->bits;
	}
	fcn->addr = at;
	fcn->name = getFunctionName(core, at);

	if (!fcn->name) {
		fcn->name = rz_str_newf("%s.%08" PFMT64x, fcnpfx, at);
	}
	rz_analysis_fcn_invalidate_read_ahead_cache();
	do {
		RzFlagItem *f;
		ut64 delta = rz_analysis_function_linear_size(fcn);
		if (!rz_io_is_valid_offset(core->io, at + delta, !core->analysis->opt.noncode)) {
			goto error;
		}
		if (rz_cons_is_breaked()) {
			break;
		}
		fcnlen = rz_analysis_fcn(core->analysis, fcn, at + delta, core->analysis->opt.bb_max_size, reftype);
		if (core->analysis->opt.searchstringrefs) {
			rz_analysis_set_stringrefs(core, fcn);
		}
		if (fcnlen == 0) {
			if (core->analysis->verbose) {
				eprintf("Analyzed function size is 0 at 0x%08" PFMT64x "\n", at + delta);
			}
			goto error;
		}
		if (fcnlen < 0) {
			switch (fcnlen) {
			case RZ_ANALYSIS_RET_ERROR:
			case RZ_ANALYSIS_RET_NEW:
			case RZ_ANALYSIS_RET_DUP:
			case RZ_ANALYSIS_RET_END:
				break;
			default:
				eprintf("Oops. Negative fcnsize at 0x%08" PFMT64x " (%d)\n", at, fcnlen);
				continue;
			}
		}
		f = rz_core_flag_get_by_spaces(core->flags, fcn->addr);
		set_fcn_name_from_flag(fcn, f, fcnpfx);

		if (fcnlen == RZ_ANALYSIS_RET_ERROR ||
			(fcnlen == RZ_ANALYSIS_RET_END && !rz_analysis_function_realsize(fcn))) {  
			if (core->analysis->opt.followbrokenfcnsrefs) {
				rz_analysis_analyze_fcn_refs(core, fcn, depth);
			}
			goto error;
		} else if (fcnlen == RZ_ANALYSIS_RET_END) {  
			f = rz_core_flag_get_by_spaces(core->flags, fcn->addr);
			if (f && f->name && strncmp(f->name, "sect", 4)) {  
				char *new_name = strdup(f->name);
				if (is_entry_flag(f)) {
					RzListIter *iter;
					RzBinSymbol *sym;
					const RzList *syms = rz_bin_get_symbols(core->bin);
					ut64 baddr = rz_config_get_i(core->config, "bin.baddr");
					rz_list_foreach (syms, iter, sym) {
						if ((sym->paddr + baddr) == fcn->addr && !strcmp(sym->type, RZ_BIN_TYPE_FUNC_STR)) {
							free(new_name);
							new_name = rz_str_newf("sym.%s", sym->name);
							break;
						}
					}
				}
				free(fcn->name);
				fcn->name = new_name;
			} else {
				RZ_FREE(fcn->name);
				const char *fcnpfx = rz_analysis_fcntype_tostring(fcn->type);
				if (!fcnpfx || !*fcnpfx || !strcmp(fcnpfx, "fcn")) {
					fcnpfx = rz_config_get(core->config, "analysis.fcnprefix");
				}
				fcn->name = rz_str_newf("%s.%08" PFMT64x, fcnpfx, fcn->addr);
				autoname_imp_trampoline(core, fcn);
				 
				rz_flag_space_push(core->flags, RZ_FLAGS_FS_FUNCTIONS);
				rz_flag_set(core->flags, fcn->name, fcn->addr, rz_analysis_function_linear_size(fcn));
				rz_flag_space_pop(core->flags);
			}

			 
			if (from != UT64_MAX) {
				rz_analysis_xrefs_set(core->analysis, from, fcn->addr, reftype);
			}
			 
			rz_analysis_add_function(core->analysis, fcn);
			if (has_next) {
				ut64 addr = rz_analysis_function_max_addr(fcn);
				RzIOMap *map = rz_io_map_get(core->io, addr);
				 
				if (!map || (map && map->perm & RZ_PERM_X)) {
					for (i = 0; i < nexti; i++) {
						if (next[i] == addr) {
							break;
						}
					}
					if (i == nexti) {
						ut64 at = rz_analysis_function_max_addr(fcn);
						while (true) {
							ut64 size;
							RzAnalysisMetaItem *mi = rz_meta_get_at(core->analysis, at, RZ_META_TYPE_ANY, &size);
							if (!mi) {
								break;
							}
							at += size;
						}
						 
						 
						rz_cons_clear_line(1);
						loganalysis(fcn->addr, at, 10000 - depth);
						next = next_append(next, &nexti, at);
					}
				}
			}
			if (!rz_analysis_analyze_fcn_refs(core, fcn, depth)) {
				goto error;
			}
		}
	} while (fcnlen != RZ_ANALYSIS_RET_END);
	rz_list_free(core->analysis->leaddrs);
	core->analysis->leaddrs = NULL;
	if (has_next) {
		for (i = 0; i < nexti; i++) {
			if (!next[i] || rz_analysis_get_fcn_in(core->analysis, next[i], 0)) {
				continue;
			}
			rz_core_analysis_fcn(core, next[i], from, 0, depth - 1);
		}
		free(next);
	}
	if (core->analysis->cur && core->analysis->cur->arch && !strcmp(core->analysis->cur->arch, "x86")) {
		rz_analysis_function_check_bp_use(fcn);
		if (fcn && !fcn->bp_frame) {
			rz_analysis_function_delete_vars_by_kind(fcn, RZ_ANALYSIS_VAR_KIND_BPV);
		}
	}
	rz_analysis_hint_free(hint);
	return true;

error:
	rz_list_free(core->analysis->leaddrs);
	core->analysis->leaddrs = NULL;
	 
	if (fcn) {
		if (!rz_analysis_function_realsize(fcn) || fcn->addr == UT64_MAX) {
			rz_analysis_function_free(fcn);
			fcn = NULL;
		} else {
			 
			if (!fcn->name) {
				 
				fcn->name = rz_str_newf(
					"%s.%08" PFMT64x,
					rz_analysis_fcntype_tostring(fcn->type),
					at);
				 
				rz_flag_space_push(core->flags, RZ_FLAGS_FS_FUNCTIONS);
				rz_flag_set(core->flags, fcn->name, at, rz_analysis_function_linear_size(fcn));
				rz_flag_space_pop(core->flags);
			}
			rz_analysis_add_function(core->analysis, fcn);
		}
		if (fcn && has_next) {
			ut64 newaddr = rz_analysis_function_max_addr(fcn);
			RzIOMap *map = rz_io_map_get(core->io, newaddr);
			if (!map || (map && (map->perm & RZ_PERM_X))) {
				next = next_append(next, &nexti, newaddr);
				for (i = 0; i < nexti; i++) {
					if (!next[i]) {
						continue;
					}
					rz_core_analysis_fcn(core, next[i], next[i], 0, depth - 1);
				}
				free(next);
			}
		}
	}
	if (fcn && core->analysis->cur && core->analysis->cur->arch && !strcmp(core->analysis->cur->arch, "x86")) {
		rz_analysis_function_check_bp_use(fcn);
		if (!fcn->bp_frame) {
			rz_analysis_function_delete_vars_by_kind(fcn, RZ_ANALYSIS_VAR_KIND_BPV);
		}
	}
	rz_analysis_hint_free(hint);
	return false;
}