Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e115f2c1 authored by Paul Mundt's avatar Paul Mundt
Browse files

sh: unwinder: Use a special bug flag for unwinder traps.



This simplifies the unwinder trap handling, dropping the use of the
special trapa vector and simply piggybacking on top of the BUG support. A
new BUGFLAG_UNWINDER is added for flagging the unwinder fault, before
continuing on with regular BUG dispatch.

Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent c153a58e
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
#ifndef __ASM_SH_BUG_H
#define __ASM_SH_BUG_H

#define TRAPA_UNWINDER_BUG_OPCODE 0xc33b /* trapa #0x3b */
#define TRAPA_BUG_OPCODE	0xc33e	/* trapa #0x3e */
#define BUGFLAG_UNWINDER	(1 << 1)

#ifdef CONFIG_GENERIC_BUG
#define HAVE_ARCH_BUG
@@ -79,9 +79,10 @@ do { \
		"1:\t.short %O0\n"			\
		_EMIT_BUG_ENTRY				\
		 :					\
		 : "n" (TRAPA_UNWINDER_BUG_OPCODE),	\
		 : "n" (TRAPA_BUG_OPCODE),		\
		   "i" (__FILE__),			\
		   "i" (__LINE__), "i" (0),		\
		   "i" (__LINE__),			\
		   "i" (BUGFLAG_UNWINDER),		\
		   "i" (sizeof(struct bug_entry)));	\
} while (0)

+1 −5
Original line number Diff line number Diff line
@@ -19,10 +19,6 @@

#if !defined(CONFIG_SH_STANDARD_BIOS)
#define sh_bios_handler			debug_trap_handler
#endif

#if !defined(CONFIG_DWARF_UNWINDER)
#define unwinder_trap_handler		debug_trap_handler
#endif

	.data
@@ -39,7 +35,7 @@ ENTRY(debug_trap_table)
	.long debug_trap_handler	/* 0x38 */
	.long debug_trap_handler	/* 0x39 */
	.long debug_trap_handler	/* 0x3a */
	.long unwinder_trap_handler	/* 0x3b */
	.long debug_trap_handler	/* 0x3b */
	.long breakpoint_trap_handler	/* 0x3c */
	.long singlestep_trap_handler	/* 0x3d */
	.long bug_trap_handler		/* 0x3e */
+17 −4
Original line number Diff line number Diff line
@@ -5,18 +5,32 @@
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/unwinder.h>
#include <asm/system.h>

#ifdef CONFIG_BUG
void handle_BUG(struct pt_regs *regs)
{
	const struct bug_entry *bug;
	unsigned long bugaddr = regs->pc;
	enum bug_trap_type tt;
	tt = report_bug(regs->pc, regs);

	if (!is_valid_bugaddr(bugaddr))
		goto invalid;

	bug = find_bug(bugaddr);

	/* Switch unwinders when unwind_stack() is called */
	if (bug->flags & BUGFLAG_UNWINDER)
		unwinder_faulted = 1;

	tt = report_bug(bugaddr, regs);
	if (tt == BUG_TRAP_TYPE_WARN) {
		regs->pc += instruction_size(regs->pc);
		regs->pc += instruction_size(bugaddr);
		return;
	}

invalid:
	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
}

@@ -28,8 +42,7 @@ int is_valid_bugaddr(unsigned long addr)
		return 0;
	if (probe_kernel_address((insn_size_t *)addr, opcode))
		return 0;

	if (opcode == TRAPA_BUG_OPCODE || opcode == TRAPA_UNWINDER_BUG_OPCODE)
	if (opcode == TRAPA_BUG_OPCODE)
		return 1;

	return 0;
+0 −21
Original line number Diff line number Diff line
@@ -161,25 +161,4 @@ void unwind_stack(struct task_struct *task, struct pt_regs *regs,

	curr_unwinder->dump(task, regs, sp, ops, data);
}

/*
 * Trap handler for UWINDER_BUG() statements. We must switch to the
 * unwinder with the next highest rating.
 */
BUILD_TRAP_HANDLER(unwinder)
{
	insn_size_t insn;
	TRAP_HANDLER_DECL;

	/* Rewind */
	regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
	insn = *(insn_size_t *)instruction_pointer(regs);

	/* Switch unwinders when unwind_stack() is called */
	unwinder_faulted = 1;

#ifdef CONFIG_BUG
	handle_BUG(regs);
#endif
}
EXPORT_SYMBOL_GPL(unwind_stack);