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 #include "fault_handler.h" 18 19 #include <sys/ucontext.h> 20 21 #include "arch/instruction_set.h" 22 #include "art_method.h" 23 #include "base/enums.h" 24 #include "base/hex_dump.h" 25 #include "base/logging.h" // For VLOG. 26 #include "base/macros.h" 27 #include "registers_arm64.h" 28 #include "runtime_globals.h" 29 #include "thread-current-inl.h" 30 31 extern "C" void art_quick_throw_stack_overflow(); 32 extern "C" void art_quick_throw_null_pointer_exception_from_signal(); 33 extern "C" void art_quick_implicit_suspend(); 34 35 // 36 // ARM64 specific fault handler functions. 37 // 38 39 namespace art { 40 41 void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context, 42 ArtMethod** out_method, 43 uintptr_t* out_return_pc, uintptr_t* out_sp) { 44 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 45 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 46 *out_sp = static_cast<uintptr_t>(sc->sp); 47 VLOG(signals) << "sp: " << *out_sp; 48 if (*out_sp == 0) { 49 return; 50 } 51 52 // In the case of a stack overflow, the stack is not valid and we can't 53 // get the method from the top of the stack. However it's in x0. 54 uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(sc->fault_address); 55 uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>( 56 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(InstructionSet::kArm64)); 57 if (overflow_addr == fault_addr) { 58 *out_method = reinterpret_cast<ArtMethod*>(sc->regs[0]); 59 } else { 60 // The method is at the top of the stack. 61 *out_method = *reinterpret_cast<ArtMethod**>(*out_sp); 62 } 63 64 // Work out the return PC. This will be the address of the instruction 65 // following the faulting ldr/str instruction. 66 VLOG(signals) << "pc: " << std::hex 67 << static_cast<void*>(reinterpret_cast<uint8_t*>(sc->pc)); 68 69 *out_return_pc = sc->pc + 4; 70 } 71 72 bool NullPointerHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info, void* context) { 73 if (!IsValidImplicitCheck(info)) { 74 return false; 75 } 76 // The code that looks for the catch location needs to know the value of the 77 // PC at the point of call. For Null checks we insert a GC map that is immediately after 78 // the load/store instruction that might cause the fault. 79 80 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 81 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 82 83 // Push the gc map location to the stack and pass the fault address in LR. 84 sc->sp -= sizeof(uintptr_t); 85 *reinterpret_cast<uintptr_t*>(sc->sp) = sc->pc + 4; 86 sc->regs[30] = reinterpret_cast<uintptr_t>(info->si_addr); 87 88 sc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal); 89 VLOG(signals) << "Generating null pointer exception"; 90 return true; 91 } 92 93 // A suspend check is done using the following instruction sequence: 94 // 0xf7223228: f9405640 ldr x0, [x18, #168] 95 // .. some intervening instructions 96 // 0xf7223230: f9400000 ldr x0, [x0] 97 98 // The offset from r18 is Thread::ThreadSuspendTriggerOffset(). 99 // To check for a suspend check, we examine the instructions that caused 100 // the fault (at PC-4 and PC). 101 bool SuspensionHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, 102 void* context) { 103 // These are the instructions to check for. The first one is the ldr x0,[r18,#xxx] 104 // where xxx is the offset of the suspend trigger. 105 uint32_t checkinst1 = 0xf9400240 | 106 (Thread::ThreadSuspendTriggerOffset<PointerSize::k64>().Int32Value() << 7); 107 uint32_t checkinst2 = 0xf9400000; 108 109 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 110 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 111 uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->pc); 112 uint8_t* ptr1 = ptr2 - 4; 113 VLOG(signals) << "checking suspend"; 114 115 uint32_t inst2 = *reinterpret_cast<uint32_t*>(ptr2); 116 VLOG(signals) << "inst2: " << std::hex << inst2 << " checkinst2: " << checkinst2; 117 if (inst2 != checkinst2) { 118 // Second instruction is not good, not ours. 119 return false; 120 } 121 122 // The first instruction can a little bit up the stream due to load hoisting 123 // in the compiler. 124 uint8_t* limit = ptr1 - 80; // Compiler will hoist to a max of 20 instructions. 125 bool found = false; 126 while (ptr1 > limit) { 127 uint32_t inst1 = *reinterpret_cast<uint32_t*>(ptr1); 128 VLOG(signals) << "inst1: " << std::hex << inst1 << " checkinst1: " << checkinst1; 129 if (inst1 == checkinst1) { 130 found = true; 131 break; 132 } 133 ptr1 -= 4; 134 } 135 if (found) { 136 VLOG(signals) << "suspend check match"; 137 // This is a suspend check. Arrange for the signal handler to return to 138 // art_quick_implicit_suspend. Also set LR so that after the suspend check it 139 // will resume the instruction (current PC + 4). PC points to the 140 // ldr x0,[x0,#0] instruction (r0 will be 0, set by the trigger). 141 142 sc->regs[30] = sc->pc + 4; 143 sc->pc = reinterpret_cast<uintptr_t>(art_quick_implicit_suspend); 144 145 // Now remove the suspend trigger that caused this fault. 146 Thread::Current()->RemoveSuspendTrigger(); 147 VLOG(signals) << "removed suspend trigger invoking test suspend"; 148 return true; 149 } 150 return false; 151 } 152 153 bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, 154 void* context) { 155 struct ucontext *uc = reinterpret_cast<struct ucontext *>(context); 156 struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); 157 VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc; 158 VLOG(signals) << "sigcontext: " << std::hex << sc; 159 160 uintptr_t sp = sc->sp; 161 VLOG(signals) << "sp: " << std::hex << sp; 162 163 uintptr_t fault_addr = sc->fault_address; 164 VLOG(signals) << "fault_addr: " << std::hex << fault_addr; 165 VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp << 166 ", fault_addr: " << fault_addr; 167 168 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(InstructionSet::kArm64); 169 170 // Check that the fault address is the value expected for a stack overflow. 171 if (fault_addr != overflow_addr) { 172 VLOG(signals) << "Not a stack overflow"; 173 return false; 174 } 175 176 VLOG(signals) << "Stack overflow found"; 177 178 // Now arrange for the signal handler to return to art_quick_throw_stack_overflow. 179 // The value of LR must be the same as it was when we entered the code that 180 // caused this fault. This will be inserted into a callee save frame by 181 // the function to which this handler returns (art_quick_throw_stack_overflow). 182 sc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow); 183 184 // The kernel will now return to the address in sc->pc. 185 return true; 186 } 187 } // namespace art 188 189