Пример #1
0
static void arm_backtrace_eabi(int cpu, int buftype, struct pt_regs * const regs, unsigned int depth)
{
#if defined(__arm__)
	struct frame_tail_eabi *tail;
	struct frame_tail_eabi *next;
	struct frame_tail_eabi *ptrtail;
	struct frame_tail_eabi buftail;
	unsigned long fp = regs->ARM_fp;
	unsigned long sp = regs->ARM_sp;
	unsigned long lr = regs->ARM_lr;
	int is_user_mode = user_mode(regs);

	if (!is_user_mode) {
		return;
	}

	/* entry preamble may not have executed */
	gator_add_trace(cpu, buftype, lr);

	/* check tail is valid */
	if (fp == 0 || fp < sp) {
		return;
	}

	tail = (struct frame_tail_eabi *)(fp - 4);

	while (depth-- && tail && !((unsigned long) tail & 3)) {
		/* Also check accessibility of one struct frame_tail beyond */
		if (!access_ok(VERIFY_READ, tail, sizeof(struct frame_tail_eabi)))
			return;
		if (__copy_from_user_inatomic(&buftail, tail, sizeof(struct frame_tail_eabi)))
			return;
		ptrtail = &buftail;

		lr = ptrtail[0].lr;
		gator_add_trace(cpu, buftype, lr);

		/* frame pointers should progress back up the stack, towards higher addresses */
		next = (struct frame_tail_eabi *)(lr - 4);
		if (tail >= next || lr == 0) {
			fp = ptrtail[0].fp;
			next = (struct frame_tail_eabi *)(fp - 4);
			/* check tail is valid */
			if (tail >= next || fp == 0) {
				return;
			}
		}

		tail = next;
	}
#endif
}
Пример #2
0
static void arm_backtrace_eabi(int cpu, struct pt_regs *const regs, unsigned int depth)
{
#if defined(__arm__) || defined(__aarch64__)
	struct stack_frame_eabi *curr;
	struct stack_frame_eabi bufcurr;
#if defined(__arm__)
	const bool is_compat = false;
	unsigned long fp = regs->ARM_fp;
	unsigned long sp = regs->ARM_sp;
	unsigned long lr = regs->ARM_lr;
	const int gcc_frame_offset = sizeof(unsigned long);
#else
	// Is userspace aarch32 (32 bit)
	const bool is_compat = compat_user_mode(regs);
	unsigned long fp = (is_compat ? regs->regs[11] : regs->regs[29]);
	unsigned long sp = (is_compat ? regs->compat_sp : regs->sp);
	unsigned long lr = (is_compat ? regs->compat_lr : regs->regs[30]);
	const int gcc_frame_offset = (is_compat ? sizeof(u32) : 0);
#endif
	// clang frame offset is always zero
	int is_user_mode = user_mode(regs);

	// pc (current function) has already been added

	if (!is_user_mode) {
		return;
	}

	// Add the lr (parent function)
	// entry preamble may not have executed
	gator_add_trace(cpu, lr);

	// check fp is valid
	if (fp == 0 || fp < sp) {
		return;
	}

	// Get the current stack frame
	curr = (struct stack_frame_eabi *)(fp - gcc_frame_offset);
	if ((unsigned long)curr & 3) {
		return;
	}

	while (depth-- && curr) {
		if (!access_ok(VERIFY_READ, curr, sizeof(struct stack_frame_eabi)) ||
				__copy_from_user_inatomic(&bufcurr, curr, sizeof(struct stack_frame_eabi))) {
			return;
		}

		fp = (is_compat ? bufcurr.fp_32 : bufcurr.fp);
		lr = (is_compat ? bufcurr.lr_32 : bufcurr.lr);

#define calc_next(reg) ((reg) - gcc_frame_offset)
		// Returns true if reg is a valid fp
#define validate_next(reg, curr) \
		((reg) != 0 && (calc_next(reg) & 3) == 0 && (unsigned long)(curr) < calc_next(reg))

		// Try lr from the stack as the fp because gcc leaf functions do not push lr
		// If gcc_frame_offset is non-zero, the lr will also be the clang fp
		// This assumes code is at a lower address than the stack
		if (validate_next(lr, curr)) {
			fp = lr;
			lr = (is_compat ? bufcurr.lr2_32 : bufcurr.lr2);
		}

		gator_add_trace(cpu, lr);

		if (!validate_next(fp, curr)) {
			return;
		}

		// Move to the next stack frame
		curr = (struct stack_frame_eabi *)calc_next(fp);
	}
#endif
}