RZ_API void rz_core_analysis_propagate_noreturn(RzCore *core, ut64 addr) {
	RzList *todo = rz_list_newf(free);
	if (!todo) {
		return;
	}

	HtUU *done = ht_uu_new0();
	if (!done) {
		rz_list_free(todo);
		return;
	}

	RzAnalysisFunction *request_fcn = NULL;
	if (addr != UT64_MAX) {
		request_fcn = rz_analysis_get_function_at(core->analysis, addr);
		if (!request_fcn) {
			rz_list_free(todo);
			ht_uu_free(done);
			return;
		}
	}

	// At first we propagate all noreturn functions that are imports or symbols
	// via the relocations
	rz_core_analysis_propagate_noreturn_relocs(core, addr);

	// find known noreturn functions to propagate
	RzListIter *iter;
	RzAnalysisFunction *f;
	rz_list_foreach (core->analysis->fcns, iter, f) {
		if (f->is_noreturn) {
			ut64 *n = ut64_new(f->addr);
			rz_list_append(todo, n);
		}
	}
	while (!rz_list_empty(todo)) {
		ut64 *paddr = (ut64 *)rz_list_pop(todo);
		ut64 noret_addr = *paddr;
		free(paddr);
		if (rz_cons_is_breaked()) {
			break;
		}
		RzList *xrefs = rz_analysis_xrefs_get_to(core->analysis, noret_addr);
		RzAnalysisXRef *xref;
		rz_list_foreach (xrefs, iter, xref) {
			RzAnalysisOp *xrefop = rz_core_op_analysis(core, xref->from, RZ_ANALYSIS_OP_MASK_ALL);
			if (!xrefop) {
				eprintf("Cannot analyze opcode at 0x%08" PFMT64x "\n", xref->from);
				continue;
			}
			ut64 call_addr = xref->from;
			ut64 chop_addr = call_addr + xrefop->size;
			rz_analysis_op_free(xrefop);
			if (xref->type != RZ_ANALYSIS_REF_TYPE_CALL) {
				continue;
			}

			// Find the block that has an instruction at exactly the xref addr
			RzAnalysisBlock *block = find_block_at_xref_addr(core, call_addr);
			if (!block) {
				continue;
			}

			RzList *block_fcns = rz_list_clone(block->fcns);
			if (request_fcn) {
				// specific function requested, check if it contains the bb
				if (!rz_list_contains(block->fcns, request_fcn)) {
					goto kontinue;
				}
			} else {
				// rz_analysis_block_chop_noreturn() might free the block!
				block = rz_analysis_block_chop_noreturn(block, chop_addr);
			}

			RzListIter *fit;
			rz_list_foreach (block_fcns, fit, f) {
				bool found = ht_uu_find(done, f->addr, NULL) != 0;
				if (f->addr && !found && analyze_noreturn_function(core, f)) {
					f->is_noreturn = true;
					rz_analysis_noreturn_add(core->analysis, NULL, f->addr);
					ut64 *n = malloc(sizeof(ut64));
					*n = f->addr;
					rz_list_append(todo, n);
					ht_uu_insert(done, *n, 1);
				}
			}
		kontinue:
			if (block) {
				rz_analysis_block_unref(block);
			}
			rz_list_free(block_fcns);
		}
		rz_list_free(xrefs);
	}
	rz_list_free(todo);
	ht_uu_free(done);
}
RZ_API void rz_core_analysis_propagate_noreturn(RzCore *core, ut64 addr) {
	RzList *todo = rz_list_newf(free);
	if (!todo) {
		return;
	}

	HtUU *done = ht_uu_new0();
	if (!done) {
		rz_list_free(todo);
		return;
	}

	RzAnalysisFunction *request_fcn = NULL;
	if (addr != UT64_MAX) {
		request_fcn = rz_analysis_get_function_at(core->analysis, addr);
		if (!request_fcn) {
			rz_list_free(todo);
			ht_uu_free(done);
			return;
		}
	}

	 
	 
	rz_core_analysis_propagate_noreturn_relocs(core, addr);

	 
	RzListIter *iter;
	RzAnalysisFunction *f;
	rz_list_foreach (core->analysis->fcns, iter, f) {
		if (f->is_noreturn) {
			ut64 *n = ut64_new(f->addr);
			rz_list_append(todo, n);
		}
	}
	while (!rz_list_empty(todo)) {
		ut64 *paddr = (ut64 *)rz_list_pop(todo);
		ut64 noret_addr = *paddr;
		free(paddr);
		if (rz_cons_is_breaked()) {
			break;
		}
		RzList *xrefs = rz_analysis_xrefs_get_to(core->analysis, noret_addr);
		RzAnalysisXRef *xref;
		rz_list_foreach (xrefs, iter, xref) {
			RzAnalysisOp *xrefop = rz_core_op_analysis(core, xref->from, RZ_ANALYSIS_OP_MASK_ALL);
			if (!xrefop) {
				eprintf("Cannot analyze opcode at 0x%08" PFMT64x "\n", xref->from);
				continue;
			}
			ut64 call_addr = xref->from;
			ut64 chop_addr = call_addr + xrefop->size;
			rz_analysis_op_free(xrefop);
			if (xref->type != RZ_ANALYSIS_REF_TYPE_CALL) {
				continue;
			}

			 
			RzAnalysisBlock *block = find_block_at_xref_addr(core, call_addr);
			if (!block) {
				continue;
			}

			RzList *block_fcns = rz_list_clone(block->fcns);
			if (request_fcn) {
				 
				if (!rz_list_contains(block->fcns, request_fcn)) {
					goto kontinue;
				}
			} else {
				 
				block = rz_analysis_block_chop_noreturn(block, chop_addr);
			}

			RzListIter *fit;
			rz_list_foreach (block_fcns, fit, f) {
				bool found = ht_uu_find(done, f->addr, NULL) != 0;
				if (f->addr && !found && analyze_noreturn_function(core, f)) {
					f->is_noreturn = true;
					rz_analysis_noreturn_add(core->analysis, NULL, f->addr);
					ut64 *n = malloc(sizeof(ut64));
					*n = f->addr;
					rz_list_append(todo, n);
					ht_uu_insert(done, *n, 1);
				}
			}
		kontinue:
			if (block) {
				rz_analysis_block_unref(block);
			}
			rz_list_free(block_fcns);
		}
		rz_list_free(xrefs);
	}
	rz_list_free(todo);
	ht_uu_free(done);
}