arch/s390/kernel/unwind_bc.c

Source file repositories/reference/linux-study-clean/arch/s390/kernel/unwind_bc.c

File Facts

System
Linux kernel
Corpus path
arch/s390/kernel/unwind_bc.c
Extension
.c
Size
5043 bytes
Lines
185
Domain
Architecture Layer
Bucket
arch/s390
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!__kernel_text_address(ip) || state->ip == unwind_recover_ret_addr(state, ip)) {
			state->regs = NULL;
			return unwind_next_frame(state);
		}
	} else {
		sf = (struct stack_frame *) state->sp;
		sp = READ_ONCE_NOCHECK(sf->back_chain);
		if (likely(sp)) {
			/* Non-zero back-chain points to the previous frame */
			if (unlikely(outside_of_stack(state, sp))) {
				if (!update_stack_info(state, sp))
					goto out_err;
			}
			sf = (struct stack_frame *) sp;
			ip = READ_ONCE_NOCHECK(sf->gprs[8]);
			reliable = true;
		} else {
			/* No back-chain, look for a pt_regs structure */
			sp = state->sp + STACK_FRAME_OVERHEAD;
			if (!on_stack(info, sp, sizeof(struct pt_regs)))
				goto out_err;
			regs = (struct pt_regs *) sp;
			if (is_final_pt_regs(state, regs))
				goto out_stop;
			ip = READ_ONCE_NOCHECK(regs->psw.addr);
			sp = READ_ONCE_NOCHECK(regs->gprs[15]);
			if (unlikely(outside_of_stack(state, sp))) {
				if (!update_stack_info(state, sp))
					goto out_err;
			}
			reliable = true;
		}
	}

	/* Sanity check: ABI requires SP to be aligned 8 bytes. */
	if (sp & 0x7)
		goto out_err;

	/* Update unwind state */
	state->sp = sp;
	state->regs = regs;
	state->reliable = reliable;
	state->ip = unwind_recover_ret_addr(state, ip);
	return true;

out_err:
	state->error = true;
out_stop:
	state->stack_info.type = STACK_TYPE_UNKNOWN;
	return false;
}
EXPORT_SYMBOL_GPL(unwind_next_frame);

/* Avoid KMSAN false positives from touching uninitialized frames. */
__no_kmsan_checks
void __unwind_start(struct unwind_state *state, struct task_struct *task,
		    struct pt_regs *regs, unsigned long first_frame)
{
	struct stack_info *info = &state->stack_info;
	struct stack_frame *sf;
	unsigned long ip, sp;

	memset(state, 0, sizeof(*state));
	state->task = task;
	state->regs = regs;

	/* Don't even attempt to start from user mode regs: */
	if (regs && user_mode(regs)) {
		info->type = STACK_TYPE_UNKNOWN;
		return;
	}

	/* Get the instruction pointer from pt_regs or the stack frame */
	if (regs) {
		ip = regs->psw.addr;
		sp = regs->gprs[15];
	} else if (task == current) {
		sp = current_frame_address();
	} else {
		sp = task->thread.ksp;
	}

	/* Get current stack pointer and initialize stack info */
	if (!update_stack_info(state, sp)) {
		/* Something is wrong with the stack pointer */
		info->type = STACK_TYPE_UNKNOWN;
		state->error = true;
		return;
	}

Annotation

Implementation Notes