static int get_step_address()

in kernel/kgdb.c [58:137]


static int get_step_address(struct pt_regs *regs, unsigned long *next_addr)
{
	unsigned long pc = regs->epc;
	unsigned long *regs_ptr = (unsigned long *)regs;
	unsigned int rs1_num, rs2_num;
	int op_code;

	if (get_kernel_nofault(op_code, (void *)pc))
		return -EINVAL;
	if ((op_code & __INSN_LENGTH_MASK) != __INSN_LENGTH_GE_32) {
		if (is_c_jalr_insn(op_code) || is_c_jr_insn(op_code)) {
			rs1_num = decode_register_index(op_code, RVC_C2_RS1_OPOFF);
			*next_addr = regs_ptr[rs1_num];
		} else if (is_c_j_insn(op_code) || is_c_jal_insn(op_code)) {
			*next_addr = EXTRACT_RVC_J_IMM(op_code) + pc;
		} else if (is_c_beqz_insn(op_code)) {
			rs1_num = decode_register_index_short(op_code,
							      RVC_C1_RS1_OPOFF);
			if (!rs1_num || regs_ptr[rs1_num] == 0)
				*next_addr = EXTRACT_RVC_B_IMM(op_code) + pc;
			else
				*next_addr = pc + 2;
		} else if (is_c_bnez_insn(op_code)) {
			rs1_num =
			    decode_register_index_short(op_code, RVC_C1_RS1_OPOFF);
			if (rs1_num && regs_ptr[rs1_num] != 0)
				*next_addr = EXTRACT_RVC_B_IMM(op_code) + pc;
			else
				*next_addr = pc + 2;
		} else {
			*next_addr = pc + 2;
		}
	} else {
		if ((op_code & __INSN_OPCODE_MASK) == __INSN_BRANCH_OPCODE) {
			bool result = false;
			long imm = EXTRACT_BTYPE_IMM(op_code);
			unsigned long rs1_val = 0, rs2_val = 0;

			rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
			rs2_num = decode_register_index(op_code, RVG_RS2_OPOFF);
			if (rs1_num)
				rs1_val = regs_ptr[rs1_num];
			if (rs2_num)
				rs2_val = regs_ptr[rs2_num];

			if (is_beq_insn(op_code))
				result = (rs1_val == rs2_val) ? true : false;
			else if (is_bne_insn(op_code))
				result = (rs1_val != rs2_val) ? true : false;
			else if (is_blt_insn(op_code))
				result =
				    ((long)rs1_val <
				     (long)rs2_val) ? true : false;
			else if (is_bge_insn(op_code))
				result =
				    ((long)rs1_val >=
				     (long)rs2_val) ? true : false;
			else if (is_bltu_insn(op_code))
				result = (rs1_val < rs2_val) ? true : false;
			else if (is_bgeu_insn(op_code))
				result = (rs1_val >= rs2_val) ? true : false;
			if (result)
				*next_addr = imm + pc;
			else
				*next_addr = pc + 4;
		} else if (is_jal_insn(op_code)) {
			*next_addr = EXTRACT_JTYPE_IMM(op_code) + pc;
		} else if (is_jalr_insn(op_code)) {
			rs1_num = decode_register_index(op_code, RVG_RS1_OPOFF);
			if (rs1_num)
				*next_addr = ((unsigned long *)regs)[rs1_num];
			*next_addr += EXTRACT_ITYPE_IMM(op_code);
		} else if (is_sret_insn(op_code)) {
			*next_addr = pc;
		} else {
			*next_addr = pc + 4;
		}
	}
	return 0;
}