arch/x86/kernel/unwind_frame.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/unwind_frame.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/unwind_frame.c
Extension
.c
Size
11517 bytes
Lines
420
Domain
Architecture Layer
Bucket
arch/x86
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 (zero) {
				if (!prev_zero)
					printk_deferred("%p: %0*x ...\n",
							sp, BITS_PER_LONG/4, 0);
				continue;
			}

			printk_deferred("%p: %0*lx (%pB)\n",
					sp, BITS_PER_LONG/4, word, (void *)word);
		}
	}
}

static bool in_entry_code(unsigned long ip)
{
	char *addr = (char *)ip;

	return addr >= __entry_text_start && addr < __entry_text_end;
}

static inline unsigned long *last_frame(struct unwind_state *state)
{
	return (unsigned long *)task_pt_regs(state->task) - 2;
}

static bool is_last_frame(struct unwind_state *state)
{
	return state->bp == last_frame(state);
}

#ifdef CONFIG_X86_32
#define GCC_REALIGN_WORDS 3
#else
#define GCC_REALIGN_WORDS 1
#endif

static inline unsigned long *last_aligned_frame(struct unwind_state *state)
{
	return last_frame(state) - GCC_REALIGN_WORDS;
}

static bool is_last_aligned_frame(struct unwind_state *state)
{
	unsigned long *last_bp = last_frame(state);
	unsigned long *aligned_bp = last_aligned_frame(state);

	/*
	 * GCC can occasionally decide to realign the stack pointer and change
	 * the offset of the stack frame in the prologue of a function called
	 * by head/entry code.  Examples:
	 *
	 * <start_secondary>:
	 *      push   %edi
	 *      lea    0x8(%esp),%edi
	 *      and    $0xfffffff8,%esp
	 *      pushl  -0x4(%edi)
	 *      push   %ebp
	 *      mov    %esp,%ebp
	 *
	 * <x86_64_start_kernel>:
	 *      lea    0x8(%rsp),%r10
	 *      and    $0xfffffffffffffff0,%rsp
	 *      pushq  -0x8(%r10)
	 *      push   %rbp
	 *      mov    %rsp,%rbp
	 *
	 * After aligning the stack, it pushes a duplicate copy of the return
	 * address before pushing the frame pointer.
	 */
	return (state->bp == aligned_bp && *(aligned_bp + 1) == *(last_bp + 1));
}

static bool is_last_ftrace_frame(struct unwind_state *state)
{
	unsigned long *last_bp = last_frame(state);
	unsigned long *last_ftrace_bp = last_bp - 3;

	/*
	 * When unwinding from an ftrace handler of a function called by entry
	 * code, the stack layout of the last frame is:
	 *
	 *   bp
	 *   parent ret addr
	 *   bp
	 *   function ret addr
	 *   parent ret addr
	 *   pt_regs
	 *   -----------------
	 */
	return (state->bp == last_ftrace_bp &&

Annotation

Implementation Notes