fault_handler_arm64.cc revision 83b1940e6482b9d8feba5c492507735686650ea5
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18#include "fault_handler.h" 19#include <sys/ucontext.h> 20#include "base/macros.h" 21#include "globals.h" 22#include "base/logging.h" 23#include "base/hex_dump.h" 24#include "registers_arm64.h" 25#include "mirror/art_method.h" 26#include "mirror/art_method-inl.h" 27#include "thread.h" 28#include "thread-inl.h" 29 30extern "C" void art_quick_throw_stack_overflow_from_signal(); 31extern "C" void art_quick_throw_null_pointer_exception(); 32extern "C" void art_quick_implicit_suspend(); 33 34// 35// ARM64 specific fault handler functions. 36// 37 38namespace art { 39 40void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, 41 mirror::ArtMethod** out_method, 42 uintptr_t* out_return_pc, uintptr_t* out_sp) { 43 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 44 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 45 *out_sp = static_cast<uintptr_t>(sc->sp); 46 VLOG(signals) << "sp: " << *out_sp; 47 if (*out_sp == 0) { 48 return; 49 } 50 51 // In the case of a stack overflow, the stack is not valid and we can't 52 // get the method from the top of the stack. However it's in x0. 53 uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(sc->fault_address); 54 uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>( 55 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kArm64)); 56 if (overflow_addr == fault_addr) { 57 *out_method = reinterpret_cast<mirror::ArtMethod*>(sc->regs[0]); 58 } else { 59 // The method is at the top of the stack. 60 *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr(); 61 } 62 63 // Work out the return PC. This will be the address of the instruction 64 // following the faulting ldr/str instruction. 65 VLOG(signals) << "pc: " << std::hex 66 << static_cast<void*>(reinterpret_cast<uint8_t*>(sc->pc)); 67 68 *out_return_pc = sc->pc + 4; 69} 70 71bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { 72 // The code that looks for the catch location needs to know the value of the 73 // PC at the point of call. For Null checks we insert a GC map that is immediately after 74 // the load/store instruction that might cause the fault. 75 76 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 77 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 78 79 sc->regs[30] = sc->pc + 4; // LR needs to point to gc map location 80 81 sc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception); 82 VLOG(signals) << "Generating null pointer exception"; 83 return true; 84} 85 86// A suspend check is done using the following instruction sequence: 87// 0xf7223228: f9405640 ldr x0, [x18, #168] 88// .. some intervening instructions 89// 0xf7223230: f9400000 ldr x0, [x0] 90 91// The offset from r18 is Thread::ThreadSuspendTriggerOffset(). 92// To check for a suspend check, we examine the instructions that caused 93// the fault (at PC-4 and PC). 94bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { 95 // These are the instructions to check for. The first one is the ldr x0,[r18,#xxx] 96 // where xxx is the offset of the suspend trigger. 97 uint32_t checkinst1 = 0xf9400240 | (Thread::ThreadSuspendTriggerOffset<8>().Int32Value() << 7); 98 uint32_t checkinst2 = 0xf9400000; 99 100 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 101 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 102 uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->pc); 103 uint8_t* ptr1 = ptr2 - 4; 104 VLOG(signals) << "checking suspend"; 105 106 uint32_t inst2 = *reinterpret_cast<uint32_t*>(ptr2); 107 VLOG(signals) << "inst2: " << std::hex << inst2 << " checkinst2: " << checkinst2; 108 if (inst2 != checkinst2) { 109 // Second instruction is not good, not ours. 110 return false; 111 } 112 113 // The first instruction can a little bit up the stream due to load hoisting 114 // in the compiler. 115 uint8_t* limit = ptr1 - 80; // Compiler will hoist to a max of 20 instructions. 116 bool found = false; 117 while (ptr1 > limit) { 118 uint32_t inst1 = *reinterpret_cast<uint32_t*>(ptr1); 119 VLOG(signals) << "inst1: " << std::hex << inst1 << " checkinst1: " << checkinst1; 120 if (inst1 == checkinst1) { 121 found = true; 122 break; 123 } 124 ptr1 -= 4; 125 } 126 if (found) { 127 VLOG(signals) << "suspend check match"; 128 // This is a suspend check. Arrange for the signal handler to return to 129 // art_quick_implicit_suspend. Also set LR so that after the suspend check it 130 // will resume the instruction (current PC + 4). PC points to the 131 // ldr x0,[x0,#0] instruction (r0 will be 0, set by the trigger). 132 133 sc->regs[30] = sc->pc + 4; 134 sc->pc = reinterpret_cast<uintptr_t>(art_quick_implicit_suspend); 135 136 // Now remove the suspend trigger that caused this fault. 137 Thread::Current()->RemoveSuspendTrigger(); 138 VLOG(signals) << "removed suspend trigger invoking test suspend"; 139 return true; 140 } 141 return false; 142} 143 144bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { 145 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 146 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 147 VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc; 148 VLOG(signals) << "sigcontext: " << std::hex << sc; 149 150 uintptr_t sp = sc->sp; 151 VLOG(signals) << "sp: " << std::hex << sp; 152 153 uintptr_t fault_addr = sc->fault_address; 154 VLOG(signals) << "fault_addr: " << std::hex << fault_addr; 155 VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp << 156 ", fault_addr: " << fault_addr; 157 158 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kArm64); 159 160 Thread* self = reinterpret_cast<Thread*>(sc->regs[art::arm64::TR]); 161 CHECK_EQ(self, Thread::Current()); 162 uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) - 163 Thread::kStackOverflowProtectedSize; 164 165 // Check that the fault address is the value expected for a stack overflow. 166 if (fault_addr != overflow_addr) { 167 VLOG(signals) << "Not a stack overflow"; 168 return false; 169 } 170 171 // We know this is a stack overflow. We need to move the sp to the overflow region 172 // that exists below the protected region. Determine the address of the next 173 // available valid address below the protected region. 174 uintptr_t prevsp = sp; 175 sp = pregion; 176 VLOG(signals) << "setting sp to overflow region at " << std::hex << sp; 177 178 // Since the compiler puts the implicit overflow 179 // check before the callee save instructions, the SP is already pointing to 180 // the previous frame. 181 VLOG(signals) << "previous frame: " << std::hex << prevsp; 182 183 // Now establish the stack pointer for the signal return. 184 sc->sp = prevsp; 185 186 // Tell the stack overflow code where the new stack pointer should be. 187 sc->regs[art::arm64::IP0] = sp; // aka x16 188 189 // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal. 190 // The value of LR must be the same as it was when we entered the code that 191 // caused this fault. This will be inserted into a callee save frame by 192 // the function to which this handler returns (art_quick_throw_stack_overflow_from_signal). 193 sc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow_from_signal); 194 195 // The kernel will now return to the address in sc->pc. 196 return true; 197} 198} // namespace art 199 200