bool unwind_next_frame()

in kernel/unwind_orc.c [417:634]


bool unwind_next_frame(struct unwind_state *state)
{
	unsigned long ip_p, sp, tmp, orig_ip = state->ip, prev_sp = state->sp;
	enum stack_type prev_type = state->stack_info.type;
	struct orc_entry *orc;
	bool indirect = false;

	if (unwind_done(state))
		return false;

	/* Don't let modules unload while we're reading their ORC data. */
	preempt_disable();

	/* End-of-stack check for user tasks: */
	if (state->regs && user_mode(state->regs))
		goto the_end;

	/*
	 * Find the orc_entry associated with the text address.
	 *
	 * For a call frame (as opposed to a signal frame), state->ip points to
	 * the instruction after the call.  That instruction's stack layout
	 * could be different from the call instruction's layout, for example
	 * if the call was to a noreturn function.  So get the ORC data for the
	 * call instruction itself.
	 */
	orc = orc_find(state->signal ? state->ip : state->ip - 1);
	if (!orc) {
		/*
		 * As a fallback, try to assume this code uses a frame pointer.
		 * This is useful for generated code, like BPF, which ORC
		 * doesn't know about.  This is just a guess, so the rest of
		 * the unwind is no longer considered reliable.
		 */
		orc = &orc_fp_entry;
		state->error = true;
	}

	/* End-of-stack check for kernel threads: */
	if (orc->sp_reg == ORC_REG_UNDEFINED) {
		if (!orc->end)
			goto err;

		goto the_end;
	}

	/* Find the previous frame's stack: */
	switch (orc->sp_reg) {
	case ORC_REG_SP:
		sp = state->sp + orc->sp_offset;
		break;

	case ORC_REG_BP:
		sp = state->bp + orc->sp_offset;
		break;

	case ORC_REG_SP_INDIRECT:
		sp = state->sp;
		indirect = true;
		break;

	case ORC_REG_BP_INDIRECT:
		sp = state->bp + orc->sp_offset;
		indirect = true;
		break;

	case ORC_REG_R10:
		if (!get_reg(state, offsetof(struct pt_regs, r10), &sp)) {
			orc_warn_current("missing R10 value at %pB\n",
					 (void *)state->ip);
			goto err;
		}
		break;

	case ORC_REG_R13:
		if (!get_reg(state, offsetof(struct pt_regs, r13), &sp)) {
			orc_warn_current("missing R13 value at %pB\n",
					 (void *)state->ip);
			goto err;
		}
		break;

	case ORC_REG_DI:
		if (!get_reg(state, offsetof(struct pt_regs, di), &sp)) {
			orc_warn_current("missing RDI value at %pB\n",
					 (void *)state->ip);
			goto err;
		}
		break;

	case ORC_REG_DX:
		if (!get_reg(state, offsetof(struct pt_regs, dx), &sp)) {
			orc_warn_current("missing DX value at %pB\n",
					 (void *)state->ip);
			goto err;
		}
		break;

	default:
		orc_warn("unknown SP base reg %d at %pB\n",
			 orc->sp_reg, (void *)state->ip);
		goto err;
	}

	if (indirect) {
		if (!deref_stack_reg(state, sp, &sp))
			goto err;

		if (orc->sp_reg == ORC_REG_SP_INDIRECT)
			sp += orc->sp_offset;
	}

	/* Find IP, SP and possibly regs: */
	switch (orc->type) {
	case UNWIND_HINT_TYPE_CALL:
		ip_p = sp - sizeof(long);

		if (!deref_stack_reg(state, ip_p, &state->ip))
			goto err;

		state->ip = unwind_recover_ret_addr(state, state->ip,
						    (unsigned long *)ip_p);
		state->sp = sp;
		state->regs = NULL;
		state->prev_regs = NULL;
		state->signal = false;
		break;

	case UNWIND_HINT_TYPE_REGS:
		if (!deref_stack_regs(state, sp, &state->ip, &state->sp)) {
			orc_warn_current("can't access registers at %pB\n",
					 (void *)orig_ip);
			goto err;
		}
		/*
		 * There is a small chance to interrupt at the entry of
		 * __kretprobe_trampoline() where the ORC info doesn't exist.
		 * That point is right after the RET to __kretprobe_trampoline()
		 * which was modified return address.
		 * At that point, the @addr_p of the unwind_recover_kretprobe()
		 * (this has to point the address of the stack entry storing
		 * the modified return address) must be "SP - (a stack entry)"
		 * because SP is incremented by the RET.
		 */
		state->ip = unwind_recover_kretprobe(state, state->ip,
				(unsigned long *)(state->sp - sizeof(long)));
		state->regs = (struct pt_regs *)sp;
		state->prev_regs = NULL;
		state->full_regs = true;
		state->signal = true;
		break;

	case UNWIND_HINT_TYPE_REGS_PARTIAL:
		if (!deref_stack_iret_regs(state, sp, &state->ip, &state->sp)) {
			orc_warn_current("can't access iret registers at %pB\n",
					 (void *)orig_ip);
			goto err;
		}
		/* See UNWIND_HINT_TYPE_REGS case comment. */
		state->ip = unwind_recover_kretprobe(state, state->ip,
				(unsigned long *)(state->sp - sizeof(long)));

		if (state->full_regs)
			state->prev_regs = state->regs;
		state->regs = (void *)sp - IRET_FRAME_OFFSET;
		state->full_regs = false;
		state->signal = true;
		break;

	default:
		orc_warn("unknown .orc_unwind entry type %d at %pB\n",
			 orc->type, (void *)orig_ip);
		goto err;
	}

	/* Find BP: */
	switch (orc->bp_reg) {
	case ORC_REG_UNDEFINED:
		if (get_reg(state, offsetof(struct pt_regs, bp), &tmp))
			state->bp = tmp;
		break;

	case ORC_REG_PREV_SP:
		if (!deref_stack_reg(state, sp + orc->bp_offset, &state->bp))
			goto err;
		break;

	case ORC_REG_BP:
		if (!deref_stack_reg(state, state->bp + orc->bp_offset, &state->bp))
			goto err;
		break;

	default:
		orc_warn("unknown BP base reg %d for ip %pB\n",
			 orc->bp_reg, (void *)orig_ip);
		goto err;
	}

	/* Prevent a recursive loop due to bad ORC data: */
	if (state->stack_info.type == prev_type &&
	    on_stack(&state->stack_info, (void *)state->sp, sizeof(long)) &&
	    state->sp <= prev_sp) {
		orc_warn_current("stack going in the wrong direction? at %pB\n",
				 (void *)orig_ip);
		goto err;
	}

	preempt_enable();
	return true;

err:
	state->error = true;

the_end:
	preempt_enable();
	state->stack_info.type = STACK_TYPE_UNKNOWN;
	return false;
}