xref: /aosp_15_r20/art/runtime/arch/arm/fault_handler_arm.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "fault_handler.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <sys/ucontext.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
22*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/hex_dump.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"  // For VLOG.
25*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
27*795d594fSAndroid Build Coastguard Worker #include "runtime_globals.h"
28*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker //
31*795d594fSAndroid Build Coastguard Worker // ARM specific fault handler functions.
32*795d594fSAndroid Build Coastguard Worker //
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_throw_null_pointer_exception_from_signal();
37*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_throw_stack_overflow();
38*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_implicit_suspend();
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker // Get the size of a thumb2 instruction in bytes.
GetInstructionSize(uint8_t * pc)41*795d594fSAndroid Build Coastguard Worker static uint32_t GetInstructionSize(uint8_t* pc) {
42*795d594fSAndroid Build Coastguard Worker   uint16_t instr = pc[0] | pc[1] << 8;
43*795d594fSAndroid Build Coastguard Worker   bool is_32bit = ((instr & 0xF000) == 0xF000) || ((instr & 0xF800) == 0xE800);
44*795d594fSAndroid Build Coastguard Worker   uint32_t instr_size = is_32bit ? 4 : 2;
45*795d594fSAndroid Build Coastguard Worker   return instr_size;
46*795d594fSAndroid Build Coastguard Worker }
47*795d594fSAndroid Build Coastguard Worker 
GetFaultPc(siginfo_t * siginfo,void * context)48*795d594fSAndroid Build Coastguard Worker uintptr_t FaultManager::GetFaultPc([[maybe_unused]] siginfo_t* siginfo, void* context) {
49*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
50*795d594fSAndroid Build Coastguard Worker   mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
51*795d594fSAndroid Build Coastguard Worker   if (mc->arm_sp == 0) {
52*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Missing SP";
53*795d594fSAndroid Build Coastguard Worker     return 0u;
54*795d594fSAndroid Build Coastguard Worker   }
55*795d594fSAndroid Build Coastguard Worker   return mc->arm_pc;
56*795d594fSAndroid Build Coastguard Worker }
57*795d594fSAndroid Build Coastguard Worker 
GetFaultSp(void * context)58*795d594fSAndroid Build Coastguard Worker uintptr_t FaultManager::GetFaultSp(void* context) {
59*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
60*795d594fSAndroid Build Coastguard Worker   mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
61*795d594fSAndroid Build Coastguard Worker   return mc->arm_sp;
62*795d594fSAndroid Build Coastguard Worker }
63*795d594fSAndroid Build Coastguard Worker 
Action(int sig,siginfo_t * info,void * context)64*795d594fSAndroid Build Coastguard Worker bool NullPointerHandler::Action([[maybe_unused]] int sig, siginfo_t* info, void* context) {
65*795d594fSAndroid Build Coastguard Worker   uintptr_t fault_address = reinterpret_cast<uintptr_t>(info->si_addr);
66*795d594fSAndroid Build Coastguard Worker   if (!IsValidFaultAddress(fault_address)) {
67*795d594fSAndroid Build Coastguard Worker     return false;
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
71*795d594fSAndroid Build Coastguard Worker   mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
72*795d594fSAndroid Build Coastguard Worker   ArtMethod** sp = reinterpret_cast<ArtMethod**>(mc->arm_sp);
73*795d594fSAndroid Build Coastguard Worker   if (!IsValidMethod(*sp)) {
74*795d594fSAndroid Build Coastguard Worker     return false;
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker   // For null checks in compiled code we insert a stack map that is immediately
78*795d594fSAndroid Build Coastguard Worker   // after the load/store instruction that might cause the fault and we need to
79*795d594fSAndroid Build Coastguard Worker   // pass the return PC to the handler. For null checks in Nterp, we similarly
80*795d594fSAndroid Build Coastguard Worker   // need the return PC to recognize that this was a null check in Nterp, so
81*795d594fSAndroid Build Coastguard Worker   // that the handler can get the needed data from the Nterp frame.
82*795d594fSAndroid Build Coastguard Worker 
83*795d594fSAndroid Build Coastguard Worker   // Note: Currently, Nterp is compiled to the A32 instruction set and managed
84*795d594fSAndroid Build Coastguard Worker   // code is compiled to the T32 instruction set.
85*795d594fSAndroid Build Coastguard Worker   // To find the stack map for compiled code, we need to set the bottom bit in
86*795d594fSAndroid Build Coastguard Worker   // the return PC indicating T32 just like we would if we were going to return
87*795d594fSAndroid Build Coastguard Worker   // to that PC (though we're going to jump to the exception handler instead).
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker   // Need to work out the size of the instruction that caused the exception.
90*795d594fSAndroid Build Coastguard Worker   uint8_t* ptr = reinterpret_cast<uint8_t*>(mc->arm_pc);
91*795d594fSAndroid Build Coastguard Worker   bool in_thumb_mode = mc->arm_cpsr & (1 << 5);
92*795d594fSAndroid Build Coastguard Worker   uint32_t instr_size = in_thumb_mode ? GetInstructionSize(ptr) : 4;
93*795d594fSAndroid Build Coastguard Worker   uintptr_t return_pc = (mc->arm_pc + instr_size) | (in_thumb_mode ? 1 : 0);
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker   // Push the return PC to the stack and pass the fault address in LR.
96*795d594fSAndroid Build Coastguard Worker   mc->arm_sp -= sizeof(uintptr_t);
97*795d594fSAndroid Build Coastguard Worker   *reinterpret_cast<uintptr_t*>(mc->arm_sp) = return_pc;
98*795d594fSAndroid Build Coastguard Worker   mc->arm_lr = fault_address;
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker   // Arrange for the signal handler to return to the NPE entrypoint.
101*795d594fSAndroid Build Coastguard Worker   mc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
102*795d594fSAndroid Build Coastguard Worker   // Make sure the thumb bit is set as the handler is in thumb mode.
103*795d594fSAndroid Build Coastguard Worker   mc->arm_cpsr = mc->arm_cpsr | (1 << 5);
104*795d594fSAndroid Build Coastguard Worker   // Pass the faulting address as the first argument of
105*795d594fSAndroid Build Coastguard Worker   // art_quick_throw_null_pointer_exception_from_signal.
106*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Generating null pointer exception";
107*795d594fSAndroid Build Coastguard Worker   return true;
108*795d594fSAndroid Build Coastguard Worker }
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker // A suspend check is done using the following instruction sequence:
111*795d594fSAndroid Build Coastguard Worker // 0xf723c0b2: f8d902c0  ldr.w   r0, [r9, #704]  ; suspend_trigger_
112*795d594fSAndroid Build Coastguard Worker // .. some intervening instruction
113*795d594fSAndroid Build Coastguard Worker // 0xf723c0b6: 6800      ldr     r0, [r0, #0]
114*795d594fSAndroid Build Coastguard Worker 
115*795d594fSAndroid Build Coastguard Worker // The offset from r9 is Thread::ThreadSuspendTriggerOffset().
116*795d594fSAndroid Build Coastguard Worker // To check for a suspend check, we examine the instructions that caused
117*795d594fSAndroid Build Coastguard Worker // the fault (at PC-4 and PC).
Action(int sig,siginfo_t * info,void * context)118*795d594fSAndroid Build Coastguard Worker bool SuspensionHandler::Action([[maybe_unused]] int sig,
119*795d594fSAndroid Build Coastguard Worker                                [[maybe_unused]] siginfo_t* info,
120*795d594fSAndroid Build Coastguard Worker                                void* context) {
121*795d594fSAndroid Build Coastguard Worker   // These are the instructions to check for.  The first one is the ldr r0,[r9,#xxx]
122*795d594fSAndroid Build Coastguard Worker   // where xxx is the offset of the suspend trigger.
123*795d594fSAndroid Build Coastguard Worker   uint32_t checkinst1 = 0xf8d90000
124*795d594fSAndroid Build Coastguard Worker       + Thread::ThreadSuspendTriggerOffset<PointerSize::k32>().Int32Value();
125*795d594fSAndroid Build Coastguard Worker   uint16_t checkinst2 = 0x6800;
126*795d594fSAndroid Build Coastguard Worker 
127*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
128*795d594fSAndroid Build Coastguard Worker   mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
129*795d594fSAndroid Build Coastguard Worker   uint8_t* ptr2 = reinterpret_cast<uint8_t*>(mc->arm_pc);
130*795d594fSAndroid Build Coastguard Worker   uint8_t* ptr1 = ptr2 - 4;
131*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "checking suspend";
132*795d594fSAndroid Build Coastguard Worker 
133*795d594fSAndroid Build Coastguard Worker   uint16_t inst2 = ptr2[0] | ptr2[1] << 8;
134*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "inst2: " << std::hex << inst2 << " checkinst2: " << checkinst2;
135*795d594fSAndroid Build Coastguard Worker   if (inst2 != checkinst2) {
136*795d594fSAndroid Build Coastguard Worker     // Second instruction is not good, not ours.
137*795d594fSAndroid Build Coastguard Worker     return false;
138*795d594fSAndroid Build Coastguard Worker   }
139*795d594fSAndroid Build Coastguard Worker 
140*795d594fSAndroid Build Coastguard Worker   // The first instruction can a little bit up the stream due to load hoisting
141*795d594fSAndroid Build Coastguard Worker   // in the compiler.
142*795d594fSAndroid Build Coastguard Worker   uint8_t* limit = ptr1 - 40;   // Compiler will hoist to a max of 20 instructions.
143*795d594fSAndroid Build Coastguard Worker   bool found = false;
144*795d594fSAndroid Build Coastguard Worker   while (ptr1 > limit) {
145*795d594fSAndroid Build Coastguard Worker     uint32_t inst1 = ((ptr1[0] | ptr1[1] << 8) << 16) | (ptr1[2] | ptr1[3] << 8);
146*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "inst1: " << std::hex << inst1 << " checkinst1: " << checkinst1;
147*795d594fSAndroid Build Coastguard Worker     if (inst1 == checkinst1) {
148*795d594fSAndroid Build Coastguard Worker       found = true;
149*795d594fSAndroid Build Coastguard Worker       break;
150*795d594fSAndroid Build Coastguard Worker     }
151*795d594fSAndroid Build Coastguard Worker     ptr1 -= 2;      // Min instruction size is 2 bytes.
152*795d594fSAndroid Build Coastguard Worker   }
153*795d594fSAndroid Build Coastguard Worker   if (found) {
154*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "suspend check match";
155*795d594fSAndroid Build Coastguard Worker     // This is a suspend check.  Arrange for the signal handler to return to
156*795d594fSAndroid Build Coastguard Worker     // art_quick_implicit_suspend.  Also set LR so that after the suspend check it
157*795d594fSAndroid Build Coastguard Worker     // will resume the instruction (current PC + 2).  PC points to the
158*795d594fSAndroid Build Coastguard Worker     // ldr r0,[r0,#0] instruction (r0 will be 0, set by the trigger).
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker     // NB: remember that we need to set the bottom bit of the LR register
161*795d594fSAndroid Build Coastguard Worker     // to switch to thumb mode.
162*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "arm lr: " << std::hex << mc->arm_lr;
163*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "arm pc: " << std::hex << mc->arm_pc;
164*795d594fSAndroid Build Coastguard Worker     mc->arm_lr = mc->arm_pc + 3;  // +2 + 1 (for thumb)
165*795d594fSAndroid Build Coastguard Worker     mc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_implicit_suspend);
166*795d594fSAndroid Build Coastguard Worker 
167*795d594fSAndroid Build Coastguard Worker     // Now remove the suspend trigger that caused this fault.
168*795d594fSAndroid Build Coastguard Worker     Thread::Current()->RemoveSuspendTrigger();
169*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "removed suspend trigger invoking test suspend";
170*795d594fSAndroid Build Coastguard Worker     return true;
171*795d594fSAndroid Build Coastguard Worker   }
172*795d594fSAndroid Build Coastguard Worker   return false;
173*795d594fSAndroid Build Coastguard Worker }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker // Stack overflow fault handler.
176*795d594fSAndroid Build Coastguard Worker //
177*795d594fSAndroid Build Coastguard Worker // This checks that the fault address is equal to the current stack pointer
178*795d594fSAndroid Build Coastguard Worker // minus the overflow region size (16K typically).  The instruction sequence
179*795d594fSAndroid Build Coastguard Worker // that generates this signal is:
180*795d594fSAndroid Build Coastguard Worker //
181*795d594fSAndroid Build Coastguard Worker // sub r12,sp,#16384
182*795d594fSAndroid Build Coastguard Worker // ldr.w r12,[r12,#0]
183*795d594fSAndroid Build Coastguard Worker //
184*795d594fSAndroid Build Coastguard Worker // The second instruction will fault if r12 is inside the protected region
185*795d594fSAndroid Build Coastguard Worker // on the stack.
186*795d594fSAndroid Build Coastguard Worker //
187*795d594fSAndroid Build Coastguard Worker // If we determine this is a stack overflow we need to move the stack pointer
188*795d594fSAndroid Build Coastguard Worker // to the overflow region below the protected region.
189*795d594fSAndroid Build Coastguard Worker 
Action(int sig,siginfo_t * info,void * context)190*795d594fSAndroid Build Coastguard Worker bool StackOverflowHandler::Action([[maybe_unused]] int sig,
191*795d594fSAndroid Build Coastguard Worker                                   [[maybe_unused]] siginfo_t* info,
192*795d594fSAndroid Build Coastguard Worker                                   void* context) {
193*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
194*795d594fSAndroid Build Coastguard Worker   mcontext_t* mc = reinterpret_cast<mcontext_t*>(&uc->uc_mcontext);
195*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
196*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "sigcontext: " << std::hex << mc;
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker   uintptr_t sp = mc->arm_sp;
199*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "sp: " << std::hex << sp;
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker   uintptr_t fault_addr = mc->fault_address;
202*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
203*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
204*795d594fSAndroid Build Coastguard Worker     ", fault_addr: " << fault_addr;
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker   uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(InstructionSet::kArm);
207*795d594fSAndroid Build Coastguard Worker 
208*795d594fSAndroid Build Coastguard Worker   // Check that the fault address is the value expected for a stack overflow.
209*795d594fSAndroid Build Coastguard Worker   if (fault_addr != overflow_addr) {
210*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Not a stack overflow";
211*795d594fSAndroid Build Coastguard Worker     return false;
212*795d594fSAndroid Build Coastguard Worker   }
213*795d594fSAndroid Build Coastguard Worker 
214*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Stack overflow found";
215*795d594fSAndroid Build Coastguard Worker 
216*795d594fSAndroid Build Coastguard Worker   // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from.
217*795d594fSAndroid Build Coastguard Worker   // The value of LR must be the same as it was when we entered the code that
218*795d594fSAndroid Build Coastguard Worker   // caused this fault.  This will be inserted into a callee save frame by
219*795d594fSAndroid Build Coastguard Worker   // the function to which this handler returns (art_quick_throw_stack_overflow).
220*795d594fSAndroid Build Coastguard Worker   mc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   // Make sure the thumb bit is set as the handler is in thumb mode.
223*795d594fSAndroid Build Coastguard Worker   mc->arm_cpsr = mc->arm_cpsr | (1 << 5);
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker   // The kernel will now return to the address in sc->arm_pc.
226*795d594fSAndroid Build Coastguard Worker   return true;
227*795d594fSAndroid Build Coastguard Worker }
228*795d594fSAndroid Build Coastguard Worker }       // namespace art
229