summaryrefslogtreecommitdiff
path: root/src/vm/arm/ehhelpers.S
blob: 1c8b5c04c1097ef8c342c54b89fc4a0049e531f4 (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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// ==++==
//

//
// ==--==

#include "unixasmmacros.inc"
#include "asmconstants.h"

.syntax unified
.thumb

//
// WARNING!!  These functions immediately ruin thread unwindability.  This is
// WARNING!!  OK as long as there is a mechanism for saving the thread context
// WARNING!!  prior to running these functions as well as a mechanism for
// WARNING!!  restoring the context prior to any stackwalk.  This means that
// WARNING!!  we need to ensure that no GC can occur while the stack is
// WARNING!!  unwalkable.  This further means that we cannot allow any exception
// WARNING!!  to occur when the stack is unwalkable
//

        // GSCookie + alignment padding
OFFSET_OF_FRAME=(4 + SIZEOF__GSCookie)

        .macro GenerateRedirectedStubWithFrame STUB, TARGET

        // 
        // This is the primary function to which execution will be redirected to.
        //
        NESTED_ENTRY \STUB, _TEXT, NoHandler

        //
        // IN: lr: original IP before redirect
        //

        PROLOG_PUSH  "{r4,r7,lr}"
        alloc_stack  OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame

        // At this point, the stack maybe misaligned if the thread abort was asynchronously
        // triggered in the prolog or epilog of the managed method. For such a case, we must
        // align the stack before calling into the VM.
        //
        // Runtime check for 8-byte alignment. 
        PROLOG_STACK_SAVE r7
        // We lose stack unwindability here by configuring fp(r7) incorrectely
        // here.
        and r0, r7, #4
        sub sp, sp, r0

        // Save pointer to FEF for GetFrameFromRedirectedStubStackFrame
        add r4, sp, #OFFSET_OF_FRAME

        // Prepare to initialize to NULL
        mov r1,#0
        str r1, [r4]                                                        // Initialize vtbl (it is not strictly necessary)
        str r1, [r4, #FaultingExceptionFrame__m_fFilterExecuted]            // Initialize BOOL for personality routine

        mov r0, r4                      // move the ptr to FEF in R0
        
        // stack must be 8 byte aligned
        CHECK_STACK_ALIGNMENT       
        
        bl            C_FUNC(\TARGET)

        // Target should not return.
        EMIT_BREAKPOINT

        NESTED_END \STUB, _TEXT

        .endm

// ------------------------------------------------------------------
//
// Helpers for async (NullRef, AccessViolation) exceptions
//

        NESTED_ENTRY NakedThrowHelper2,_TEXT,UnhandledExceptionHandlerUnix
        push         {r0, lr}

        // On entry:
        //
        // R0 = Address of FaultingExceptionFrame
        bl C_FUNC(LinkFrameAndThrow)

        // Target should not return.
        EMIT_BREAKPOINT

        NESTED_END NakedThrowHelper2, _TEXT


        GenerateRedirectedStubWithFrame NakedThrowHelper, NakedThrowHelper2

// ------------------------------------------------------------------

        // This helper enables us to call into a funclet after applying the non-volatiles
        NESTED_ENTRY CallEHFunclet, _TEXT, NoHandler

        PROLOG_PUSH  "{r4-r11, lr}"
        PROLOG_STACK_SAVE_OFFSET  r7, #12
        alloc_stack  4

        // On entry:
        //
        // R0 = throwable        
        // R1 = PC to invoke
        // R2 = address of R4 register in CONTEXT record// used to restore the non-volatile registers of CrawlFrame
        // R3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
        //
        // Save the SP of this function
        str sp, [r3]
        // apply the non-volatiles corresponding to the CrawlFrame
        ldm r2!, {r4-r6}
        add r2, r2, #4
        ldm r2!, {r8-r11}
        // Invoke the funclet
        blx r1

        free_stack   4
        EPILOG_POP   "{r4-r11, pc}"

        NESTED_END CallEHFunclet, _TEXT

        // This helper enables us to call into a filter funclet by passing it the CallerSP to lookup the 
        // frame pointer for accessing the locals in the parent method.
        NESTED_ENTRY CallEHFilterFunclet, _TEXT, NoHandler

        PROLOG_PUSH  "{r7, lr}"
        PROLOG_STACK_SAVE r7

        // On entry:
        //
        // R0 = throwable        
        // R1 = SP of the caller of the method/funclet containing the filter
        // R2 = PC to invoke
        // R3 = address of the location where the SP of funclet's caller (i.e. this helper) should be saved.
        //
        // Save the SP of this function
        str sp, [r3]
        // Invoke the filter funclet
        blx r2

        EPILOG_POP   "{r7, pc}"

        NESTED_END CallEHFilterFunclet, _TEXT