arch/microblaze/kernel/unwind.c

Source file repositories/reference/linux-study-clean/arch/microblaze/kernel/unwind.c

File Facts

System
Linux kernel
Corpus path
arch/microblaze/kernel/unwind.c
Extension
.c
Size
8821 bytes
Lines
310
Domain
Architecture Layer
Bucket
arch/microblaze
Inferred role
Architecture Layer: implementation source
Status
source 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 ((frame_size < 8) || (frame_size & 3)) {
			pr_debug("    Invalid frame size %d at 0x%p\n",
				 frame_size, pc);
			return NULL;
		}

		pr_debug("    Found frame creation at 0x%p, size %d\n", pc,
			 frame_size);
		return pc;
	}

	return NULL;
}

/**
 * lookup_prev_stack_frame - Find the stack frame of the previous function.
 * @fp          : Frame (stack) pointer for current function
 * @pc          : Program counter within current function
 * @leaf_return : r15 value within current function. If the current function
 *		  is a leaf, this is the caller's return address.
 * @pprev_fp    : On exit, set to frame (stack) pointer for previous function
 * @pprev_pc    : On exit, set to current function caller's return address
 *
 * Return - 0 on success, -EINVAL if the previous frame cannot be found
 */
static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
				   unsigned long leaf_return,
				   unsigned long *pprev_fp,
				   unsigned long *pprev_pc)
{
	unsigned long *prologue = NULL;

	/* _switch_to is a special leaf function */
	if (pc != (unsigned long) &_switch_to)
		prologue = find_frame_creation((unsigned long *)pc);

	if (prologue) {
		long frame_size = get_frame_size(*prologue);

		*pprev_fp = fp + frame_size;
		*pprev_pc = *(unsigned long *)fp;
	} else {
		if (!leaf_return)
			return -EINVAL;
		*pprev_pc = leaf_return;
		*pprev_fp = fp;
	}

	/* NOTE: don't check kernel_text_address here, to allow display
	 *	 of userland return address
	 */
	return (!*pprev_pc || (*pprev_pc & 3)) ? -EINVAL : 0;
}

static void microblaze_unwind_inner(struct task_struct *task,
				    unsigned long pc, unsigned long fp,
				    unsigned long leaf_return,
				    struct stack_trace *trace,
				    const char *loglvl);

/**
 * unwind_trap - Unwind through a system trap, that stored previous state
 *		 on the stack.
 */
static inline void unwind_trap(struct task_struct *task, unsigned long pc,
				unsigned long fp, struct stack_trace *trace,
				const char *loglvl)
{
	/* To be implemented */
}

/**
 * microblaze_unwind_inner - Unwind the stack from the specified point
 * @task  : Task whose stack we are to unwind (may be NULL)
 * @pc    : Program counter from which we start unwinding
 * @fp    : Frame (stack) pointer from which we start unwinding
 * @leaf_return : Value of r15 at pc. If the function is a leaf, this is
 *				  the caller's return address.
 * @trace : Where to store stack backtrace (PC values).
 *	    NULL == print backtrace to kernel log
 * @loglvl : Used for printk log level if (trace == NULL).
 */
static void microblaze_unwind_inner(struct task_struct *task,
			     unsigned long pc, unsigned long fp,
			     unsigned long leaf_return,
			     struct stack_trace *trace,
			     const char *loglvl)
{
	int ofs = 0;

Annotation

Implementation Notes