summaryrefslogtreecommitdiff
path: root/Debugger/undef_handler.S
blob: 385bf0ce0e93c0669655e179b34b608dab748a26 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* Copyright (C) 2007-2010 the NxOS developers
 *
 * Module Developed by: TC Wan <tcwan@cs.usm.my>
 *
 * See AUTHORS for a full list of the developers.
 *
 * Redistribution of this file is permitted under
 * the terms of the GNU Public License (GPL) version 2.
 */
#define __ASSEMBLY__
#include "debug_stub.h"

#define MODE_SVC 0x13 			/* Supervisor mode. */

.text
.code 32
.align 0

	.extern dbg__thumb_bkpt_handler
	.extern dbg__arm_bkpt_handler
	.extern default_undef_handler

	.global undef_handler

undef_handler:
/* Remote GDB Debugger relies on BKPT instruction being trapped here
   In ARMv4t, it is an Illegal (Undefined) Instruction.
   On triggering, lr (R14) contains the previous mode's pc (R15).
   Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques"
   Chapter 11, Example 11.1.
   Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.)
 */
 /* We assume that the UNDEF stack has been setup previously
    On entry, LR_undef points to one instruction past the UNDEF instruction
  */
  		ldr	sp, =__debugger_stack__
 		stmfd sp, {r0-r15}^				/* Save workspace, user mode's pc via 'S' flag */
 		sub	sp, sp, #(4*16)				/* Need to manually update SP(undef) */
 		mrs	r1, spsr					/* Copy SPSR to r0 */
 		tst	r1, #CPSR_THUMB				/* Check for Thumb Mode */
		beq	_is_arm						/* Clear, so it's ARM mode */
_is_thumb:
 		sub	r0, lr, #-2					/* LR points to instruction after UNDEF instruction */
 		stmfd	sp!, {r0,r1}			/* Save UNDEF instruction addr and previous mode's CPSR to stack */
		ldrh r0, [r0]					/* load UNDEF instruction into r0 */
		ldr	r1, =BKPT16_ENUM_MASK		/* Thumb BKPT enum mask */
		bic	r2, r0, r1					/* leave only opcode */
		ldr	r1, =BKPT16_INSTR			/* check for Thumb Breakpoint Instruction */
		teq	r2, r1
		bne	default_undef_handler
		ldr	r1, =BKPT16_ENUM_MASK		/* get Thumb BKPT Enum Mask */
		and	r0, r1, r0					/* Keep index value */
		msr	cpsr_c, #(MODE_SVC)			/* Configure Supervisor Mode */
		ldr	lr, =dbg__thumb_bkpt_handler	/* handle BKPT, BKPT index in r0 */
		mov	pc, lr						/* Invoke Debugger State (Supervisor Mode) */
_is_arm:
 		sub	r0, lr, #-4					/* LR points to instruction after UNDEF instruction */
 		stmfd	sp!, {r0,r1}			/* Save UNDEF instruction addr and previous mode's CPSR to stack */
		ldr	r0, [r0]					/* load UNDEF instruction into r0 */
		ldr	r1, =BKPT32_ENUM_MASK		/* ARM BKPT enum mask */
		bic	r2, r0, r1					/* leave only opcode */
		ldr	r1, =BKPT32_INSTR			/* check for ARM Breakpoint Instruction */
		teq	r2, r1
		bne	default_undef_handler
		ldr	r1, =BKPT32_ENUM_MASK		/* get ARM BKPT Enum Mask */
		and	r0, r1, r0					/* Keep index value */
		msr	cpsr_c, #(MODE_SVC)			/* Configure Supervisor Mode */
		ldr	lr, =dbg__arm_bkpt_handler		/* handle BKPT, BKPT index in r0 */
		mov	pc, lr						/* Invoke Debugger State (Supervisor Mode) */