RZ_API RzList *rz_core_analysis_cycles(RzCore *core, int ccl) {
	ut64 addr = core->offset;
	int depth = 0;
	RzAnalysisOp *op = NULL;
	RzAnalysisCycleFrame *prev = NULL, *cf = NULL;
	RzAnalysisCycleHook *ch;
	RzList *hooks = rz_list_new();
	if (!hooks) {
		return NULL;
	}
	cf = rz_analysis_cycle_frame_new();
	rz_cons_break_push(NULL, NULL);
	while (cf && !rz_cons_is_breaked()) {
		if ((op = rz_core_analysis_op(core, addr, RZ_ANALYSIS_OP_MASK_BASIC)) && (op->cycles) && (ccl > 0)) {
			rz_cons_clear_line(1);
			eprintf("%i -- ", ccl);
			addr += op->size;
			switch (op->type) {
			case RZ_ANALYSIS_OP_TYPE_JMP:
				addr = op->jump;
				ccl -= op->cycles;
				loganalysis(op->addr, addr, depth);
				break;
			case RZ_ANALYSIS_OP_TYPE_UJMP:
			case RZ_ANALYSIS_OP_TYPE_MJMP:
			case RZ_ANALYSIS_OP_TYPE_UCALL:
			case RZ_ANALYSIS_OP_TYPE_ICALL:
			case RZ_ANALYSIS_OP_TYPE_RCALL:
			case RZ_ANALYSIS_OP_TYPE_IRCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = op->addr;
				eprintf("0x%08" PFMT64x " > ?\r", op->addr);
				ch->cycles = ccl;
				rz_list_append(hooks, ch);
				ch = NULL;
				while (!ch && cf) {
					ch = rz_list_pop(cf->hooks);
					if (ch) {
						addr = ch->addr;
						ccl = ch->cycles;
						free(ch);
					} else {
						rz_analysis_cycle_frame_free(cf);
						cf = prev;
						if (cf) {
							prev = cf->prev;
						}
					}
				}
				break;
			case RZ_ANALYSIS_OP_TYPE_CJMP:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = addr;
				ch->cycles = ccl - op->failcycles;
				rz_list_push(cf->hooks, ch);
				ch = NULL;
				addr = op->jump;
				loganalysis(op->addr, addr, depth);
				break;
			case RZ_ANALYSIS_OP_TYPE_UCJMP:
			case RZ_ANALYSIS_OP_TYPE_UCCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = op->addr;
				ch->cycles = ccl;
				rz_list_append(hooks, ch);
				ch = NULL;
				ccl -= op->failcycles;
				eprintf("0x%08" PFMT64x " > ?\r", op->addr);
				break;
			case RZ_ANALYSIS_OP_TYPE_CCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = addr;
				ch->cycles = ccl - op->failcycles;
				rz_list_push(cf->hooks, ch);
				ch = NULL;
			case RZ_ANALYSIS_OP_TYPE_CALL:
				if (op->addr != op->jump) { //no selfies
					cf->naddr = addr;
					prev = cf;
					cf = rz_analysis_cycle_frame_new();
					cf->prev = prev;
				}
				ccl -= op->cycles;
				addr = op->jump;
				loganalysis(op->addr, addr, depth - 1);
				break;
			case RZ_ANALYSIS_OP_TYPE_RET:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				if (prev) {
					ch->addr = prev->naddr;
					ccl -= op->cycles;
					ch->cycles = ccl;
					rz_list_push(prev->hooks, ch);
					eprintf("0x%08" PFMT64x " < 0x%08" PFMT64x "\r", prev->naddr, op->addr);
				} else {
					ch->addr = op->addr;
					ch->cycles = ccl;
					rz_list_append(hooks, ch);
					eprintf("? < 0x%08" PFMT64x "\r", op->addr);
				}
				ch = NULL;
				while (!ch && cf) {
					ch = rz_list_pop(cf->hooks);
					if (ch) {
						addr = ch->addr;
						ccl = ch->cycles;
						free(ch);
					} else {
						rz_analysis_cycle_frame_free(cf);
						cf = prev;
						if (cf) {
							prev = cf->prev;
						}
					}
				}
				break;
			case RZ_ANALYSIS_OP_TYPE_CRET:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				if (prev) {
					ch->addr = prev->naddr;
					ch->cycles = ccl - op->cycles;
					rz_list_push(prev->hooks, ch);
					eprintf("0x%08" PFMT64x " < 0x%08" PFMT64x "\r", prev->naddr, op->addr);
				} else {
					ch->addr = op->addr;
					ch->cycles = ccl - op->cycles;
					rz_list_append(hooks, ch);
					eprintf("? < 0x%08" PFMT64x "\r", op->addr);
				}
				ccl -= op->failcycles;
				break;
			default:
				ccl -= op->cycles;
				eprintf("0x%08" PFMT64x "\r", op->addr);
				break;
			}
		} else {
			ch = RZ_NEW0(RzAnalysisCycleHook);
			if (!ch) {
				rz_analysis_cycle_frame_free(cf);
				rz_list_free(hooks);
				return NULL;
			}
			ch->addr = addr;
			ch->cycles = ccl;
			rz_list_append(hooks, ch);
			ch = NULL;
			while (!ch && cf) {
				ch = rz_list_pop(cf->hooks);
				if (ch) {
					addr = ch->addr;
					ccl = ch->cycles;
					free(ch);
				} else {
					rz_analysis_cycle_frame_free(cf);
					cf = prev;
					if (cf) {
						prev = cf->prev;
					}
				}
			}
		}
		rz_analysis_op_free(op);
	}
	if (rz_cons_is_breaked()) {
		while (cf) {
			ch = rz_list_pop(cf->hooks);
			while (ch) {
				free(ch);
				ch = rz_list_pop(cf->hooks);
			}
			prev = cf->prev;
			rz_analysis_cycle_frame_free(cf);
			cf = prev;
		}
	}
	rz_cons_break_pop();
	return hooks;
}
RZ_API RzList *rz_core_analysis_cycles(RzCore *core, int ccl) {
	ut64 addr = core->offset;
	int depth = 0;
	RzAnalysisOp *op = NULL;
	RzAnalysisCycleFrame *prev = NULL, *cf = NULL;
	RzAnalysisCycleHook *ch;
	RzList *hooks = rz_list_new();
	if (!hooks) {
		return NULL;
	}
	cf = rz_analysis_cycle_frame_new();
	rz_cons_break_push(NULL, NULL);
	while (cf && !rz_cons_is_breaked()) {
		if ((op = rz_core_analysis_op(core, addr, RZ_ANALYSIS_OP_MASK_BASIC)) && (op->cycles) && (ccl > 0)) {
			rz_cons_clear_line(1);
			eprintf("%i -- ", ccl);
			addr += op->size;
			switch (op->type) {
			case RZ_ANALYSIS_OP_TYPE_JMP:
				addr = op->jump;
				ccl -= op->cycles;
				loganalysis(op->addr, addr, depth);
				break;
			case RZ_ANALYSIS_OP_TYPE_UJMP:
			case RZ_ANALYSIS_OP_TYPE_MJMP:
			case RZ_ANALYSIS_OP_TYPE_UCALL:
			case RZ_ANALYSIS_OP_TYPE_ICALL:
			case RZ_ANALYSIS_OP_TYPE_RCALL:
			case RZ_ANALYSIS_OP_TYPE_IRCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = op->addr;
				eprintf("0x%08" PFMT64x " > ?\r", op->addr);
				ch->cycles = ccl;
				rz_list_append(hooks, ch);
				ch = NULL;
				while (!ch && cf) {
					ch = rz_list_pop(cf->hooks);
					if (ch) {
						addr = ch->addr;
						ccl = ch->cycles;
						free(ch);
					} else {
						rz_analysis_cycle_frame_free(cf);
						cf = prev;
						if (cf) {
							prev = cf->prev;
						}
					}
				}
				break;
			case RZ_ANALYSIS_OP_TYPE_CJMP:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = addr;
				ch->cycles = ccl - op->failcycles;
				rz_list_push(cf->hooks, ch);
				ch = NULL;
				addr = op->jump;
				loganalysis(op->addr, addr, depth);
				break;
			case RZ_ANALYSIS_OP_TYPE_UCJMP:
			case RZ_ANALYSIS_OP_TYPE_UCCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = op->addr;
				ch->cycles = ccl;
				rz_list_append(hooks, ch);
				ch = NULL;
				ccl -= op->failcycles;
				eprintf("0x%08" PFMT64x " > ?\r", op->addr);
				break;
			case RZ_ANALYSIS_OP_TYPE_CCALL:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				ch->addr = addr;
				ch->cycles = ccl - op->failcycles;
				rz_list_push(cf->hooks, ch);
				ch = NULL;
			case RZ_ANALYSIS_OP_TYPE_CALL:
				if (op->addr != op->jump) {  
					cf->naddr = addr;
					prev = cf;
					cf = rz_analysis_cycle_frame_new();
					cf->prev = prev;
				}
				ccl -= op->cycles;
				addr = op->jump;
				loganalysis(op->addr, addr, depth - 1);
				break;
			case RZ_ANALYSIS_OP_TYPE_RET:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				if (prev) {
					ch->addr = prev->naddr;
					ccl -= op->cycles;
					ch->cycles = ccl;
					rz_list_push(prev->hooks, ch);
					eprintf("0x%08" PFMT64x " < 0x%08" PFMT64x "\r", prev->naddr, op->addr);
				} else {
					ch->addr = op->addr;
					ch->cycles = ccl;
					rz_list_append(hooks, ch);
					eprintf("? < 0x%08" PFMT64x "\r", op->addr);
				}
				ch = NULL;
				while (!ch && cf) {
					ch = rz_list_pop(cf->hooks);
					if (ch) {
						addr = ch->addr;
						ccl = ch->cycles;
						free(ch);
					} else {
						rz_analysis_cycle_frame_free(cf);
						cf = prev;
						if (cf) {
							prev = cf->prev;
						}
					}
				}
				break;
			case RZ_ANALYSIS_OP_TYPE_CRET:
				ch = RZ_NEW0(RzAnalysisCycleHook);
				if (prev) {
					ch->addr = prev->naddr;
					ch->cycles = ccl - op->cycles;
					rz_list_push(prev->hooks, ch);
					eprintf("0x%08" PFMT64x " < 0x%08" PFMT64x "\r", prev->naddr, op->addr);
				} else {
					ch->addr = op->addr;
					ch->cycles = ccl - op->cycles;
					rz_list_append(hooks, ch);
					eprintf("? < 0x%08" PFMT64x "\r", op->addr);
				}
				ccl -= op->failcycles;
				break;
			default:
				ccl -= op->cycles;
				eprintf("0x%08" PFMT64x "\r", op->addr);
				break;
			}
		} else {
			ch = RZ_NEW0(RzAnalysisCycleHook);
			if (!ch) {
				rz_analysis_cycle_frame_free(cf);
				rz_list_free(hooks);
				return NULL;
			}
			ch->addr = addr;
			ch->cycles = ccl;
			rz_list_append(hooks, ch);
			ch = NULL;
			while (!ch && cf) {
				ch = rz_list_pop(cf->hooks);
				if (ch) {
					addr = ch->addr;
					ccl = ch->cycles;
					free(ch);
				} else {
					rz_analysis_cycle_frame_free(cf);
					cf = prev;
					if (cf) {
						prev = cf->prev;
					}
				}
			}
		}
		rz_analysis_op_free(op);
	}
	if (rz_cons_is_breaked()) {
		while (cf) {
			ch = rz_list_pop(cf->hooks);
			while (ch) {
				free(ch);
				ch = rz_list_pop(cf->hooks);
			}
			prev = cf->prev;
			rz_analysis_cycle_frame_free(cf);
			cf = prev;
		}
	}
	rz_cons_break_pop();
	return hooks;
}