arch/openrisc/kernel/unwinder.c

Source file repositories/reference/linux-study-clean/arch/openrisc/kernel/unwinder.c

File Facts

System
Linux kernel
Corpus path
arch/openrisc/kernel/unwinder.c
Extension
.c
Size
2871 bytes
Lines
106
Domain
Architecture Layer
Bucket
arch/openrisc
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

struct or1k_frameinfo {
	unsigned long *fp;
	unsigned long ra;
	unsigned long top;
};

/*
 * Verify a frameinfo structure.  The return address should be a valid text
 * address.  The frame pointer may be null if its the last frame, otherwise
 * the frame pointer should point to a location in the stack after the
 * top of the next frame up.
 */
static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
{
	return (frameinfo->fp == NULL ||
		(!kstack_end(frameinfo->fp) &&
		 frameinfo->fp > &frameinfo->top)) &&
	       __kernel_text_address(frameinfo->ra);
}

/*
 * Create a stack trace doing scanning which is frame pointer aware. We can
 * get reliable stack traces by matching the previously found frame
 * pointer with the top of the stack address every time we find a valid
 * or1k_frameinfo.
 *
 * Ideally the stack parameter will be passed as FP, but it can not be
 * guaranteed.  Therefore we scan each address looking for the first sign
 * of a return address.
 *
 * The OpenRISC stack frame looks something like the following.  The
 * location SP is held in r1 and location FP is held in r2 when frame pointers
 * enabled.
 *
 * SP   -> (top of stack)
 *      -  (callee saved registers)
 *      -  (local variables)
 * FP-8 -> previous FP             \
 * FP-4 -> return address          |- or1k_frameinfo
 * FP   -> (previous top of stack) /
 */
void unwind_stack(void *data, unsigned long *stack,
		  void (*trace)(void *data, unsigned long addr, int reliable))
{
	unsigned long *next_fp = NULL;
	struct or1k_frameinfo *frameinfo = NULL;
	int reliable = 0;

	while (!kstack_end(stack)) {
		frameinfo = container_of(stack,
					 struct or1k_frameinfo,
					 top);

		if (__kernel_text_address(frameinfo->ra)) {
			if (or1k_frameinfo_valid(frameinfo) &&
			    (next_fp == NULL ||
			     next_fp == &frameinfo->top)) {
				reliable = 1;
				next_fp = frameinfo->fp;
			} else
				reliable = 0;

			trace(data, frameinfo->ra, reliable);
		}
		stack++;
	}
}

#else /* CONFIG_FRAME_POINTER */

/*
 * Create a stack trace by doing a simple scan treating all text addresses
 * as return addresses.
 */
void unwind_stack(void *data, unsigned long *stack,
		   void (*trace)(void *data, unsigned long addr, int reliable))
{
	unsigned long addr;

	while (!kstack_end(stack)) {
		addr = *stack++;
		if (__kernel_text_address(addr))
			trace(data, addr, 0);
	}
}
#endif /* CONFIG_FRAME_POINTER */

Annotation

Implementation Notes