fault_handler_x86.cc revision b84d7a226399dcc60bc0a421715ffc90ce9213f7
1/* 2 * Copyright (C) 2008 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 "mirror/art_method.h" 25#include "mirror/art_method-inl.h" 26#include "thread.h" 27#include "thread-inl.h" 28 29#if defined(__APPLE__) 30#define ucontext __darwin_ucontext 31 32#if defined(__x86_64__) 33// 64 bit mac build. 34#define CTX_ESP uc_mcontext->__ss.__rsp 35#define CTX_EIP uc_mcontext->__ss.__rip 36#define CTX_EAX uc_mcontext->__ss.__rax 37#define CTX_METHOD uc_mcontext->__ss.__rdi 38#else 39// 32 bit mac build. 40#define CTX_ESP uc_mcontext->__ss.__esp 41#define CTX_EIP uc_mcontext->__ss.__eip 42#define CTX_EAX uc_mcontext->__ss.__eax 43#define CTX_METHOD uc_mcontext->__ss.__eax 44#endif 45 46#elif defined(__x86_64__) 47// 64 bit linux build. 48#define CTX_ESP uc_mcontext.gregs[REG_RSP] 49#define CTX_EIP uc_mcontext.gregs[REG_RIP] 50#define CTX_EAX uc_mcontext.gregs[REG_RAX] 51#define CTX_METHOD uc_mcontext.gregs[REG_RDI] 52#else 53// 32 bit linux build. 54#define CTX_ESP uc_mcontext.gregs[REG_ESP] 55#define CTX_EIP uc_mcontext.gregs[REG_EIP] 56#define CTX_EAX uc_mcontext.gregs[REG_EAX] 57#define CTX_METHOD uc_mcontext.gregs[REG_EAX] 58#endif 59 60// 61// X86 (and X86_64) specific fault handler functions. 62// 63 64namespace art { 65 66#if defined(__APPLE__) && defined(__x86_64__) 67// mac symbols have a prefix of _ on x86_64 68extern "C" void _art_quick_throw_null_pointer_exception(); 69extern "C" void _art_quick_throw_stack_overflow(); 70extern "C" void _art_quick_test_suspend(); 71#define EXT_SYM(sym) _ ## sym 72#else 73extern "C" void art_quick_throw_null_pointer_exception(); 74extern "C" void art_quick_throw_stack_overflow(); 75extern "C" void art_quick_test_suspend(); 76#define EXT_SYM(sym) sym 77#endif 78 79// Get the size of an instruction in bytes. 80// Return 0 if the instruction is not handled. 81static uint32_t GetInstructionSize(const uint8_t* pc) { 82#if defined(__x86_64) 83 const bool x86_64 = true; 84#else 85 const bool x86_64 = false; 86#endif 87 88 const uint8_t* startpc = pc; 89 90 uint8_t opcode = *pc++; 91 uint8_t modrm; 92 bool has_modrm = false; 93 bool two_byte = false; 94 uint32_t displacement_size = 0; 95 uint32_t immediate_size = 0; 96 97 // Prefixes. 98 while (true) { 99 bool prefix_present = false; 100 switch (opcode) { 101 // Group 1 102 case 0xf0: 103 case 0xf2: 104 case 0xf3: 105 106 // Group 2 107 case 0x2e: 108 case 0x36: 109 case 0x3e: 110 case 0x26: 111 case 0x64: 112 case 0x65: 113 114 // Group 3 115 case 0x66: 116 117 // Group 4 118 case 0x67: 119 opcode = *pc++; 120 prefix_present = true; 121 break; 122 } 123 if (!prefix_present) { 124 break; 125 } 126 } 127 128 if (x86_64 && opcode >= 0x40 && opcode <= 0x4f) { 129 opcode = *pc++; 130 } 131 132 if (opcode == 0x0f) { 133 // Two byte opcode 134 two_byte = true; 135 opcode = *pc++; 136 } 137 138 bool unhandled_instruction = false; 139 140 if (two_byte) { 141 switch (opcode) { 142 case 0x10: // vmovsd/ss 143 case 0x11: // vmovsd/ss 144 case 0xb6: // movzx 145 case 0xb7: 146 case 0xbe: // movsx 147 case 0xbf: 148 modrm = *pc++; 149 has_modrm = true; 150 break; 151 default: 152 unhandled_instruction = true; 153 break; 154 } 155 } else { 156 switch (opcode) { 157 case 0x89: // mov 158 case 0x8b: 159 case 0x38: // cmp with memory. 160 case 0x39: 161 case 0x3a: 162 case 0x3b: 163 case 0x3c: 164 case 0x3d: 165 case 0x85: // test. 166 modrm = *pc++; 167 has_modrm = true; 168 break; 169 170 case 0x80: // group 1, byte immediate. 171 case 0x83: 172 modrm = *pc++; 173 has_modrm = true; 174 immediate_size = 1; 175 break; 176 177 case 0x81: // group 1, word immediate. 178 modrm = *pc++; 179 has_modrm = true; 180 immediate_size = 4; 181 break; 182 183 default: 184 unhandled_instruction = true; 185 break; 186 } 187 } 188 189 if (unhandled_instruction) { 190 VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast<int>(opcode); 191 return 0; 192 } 193 194 if (has_modrm) { 195 uint8_t mod = (modrm >> 6) & 0b11; 196 197 // Check for SIB. 198 if (mod != 0b11 && (modrm & 0b111) == 4) { 199 ++pc; // SIB 200 } 201 202 switch (mod) { 203 case 0b00: break; 204 case 0b01: displacement_size = 1; break; 205 case 0b10: displacement_size = 4; break; 206 case 0b11: 207 break; 208 } 209 } 210 211 // Skip displacement and immediate. 212 pc += displacement_size + immediate_size; 213 214 VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc); 215 return pc - startpc; 216} 217 218void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, 219 mirror::ArtMethod** out_method, 220 uintptr_t* out_return_pc, uintptr_t* out_sp) { 221 struct ucontext* uc = reinterpret_cast<struct ucontext*>(context); 222 *out_sp = static_cast<uintptr_t>(uc->CTX_ESP); 223 VLOG(signals) << "sp: " << std::hex << *out_sp; 224 if (*out_sp == 0) { 225 return; 226 } 227 228 // In the case of a stack overflow, the stack is not valid and we can't 229 // get the method from the top of the stack. However it's in EAX(x86)/RDI(x86_64). 230 uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr); 231 uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>( 232#if defined(__x86_64__) 233 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86_64)); 234#else 235 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86)); 236#endif 237 if (overflow_addr == fault_addr) { 238 *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_METHOD); 239 } else { 240 // The method is at the top of the stack. 241 *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr(); 242 } 243 244 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP); 245 VLOG(signals) << HexDump(pc, 32, true, "PC "); 246 247 uint32_t instr_size = GetInstructionSize(pc); 248 if (instr_size == 0) { 249 // Unknown instruction, tell caller it's not ours. 250 *out_method = nullptr; 251 return; 252 } 253 *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size); 254} 255 256bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { 257 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 258 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP); 259 uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP); 260 261 uint32_t instr_size = GetInstructionSize(pc); 262 if (instr_size == 0) { 263 // Unknown instruction, can't really happen. 264 return false; 265 } 266 267 // We need to arrange for the signal handler to return to the null pointer 268 // exception generator. The return address must be the address of the 269 // next instruction (this instruction + instruction size). The return address 270 // is on the stack at the top address of the current frame. 271 272 // Push the return address onto the stack. 273 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size); 274 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t)); 275 *next_sp = retaddr; 276 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp); 277 278 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_null_pointer_exception)); 279 VLOG(signals) << "Generating null pointer exception"; 280 return true; 281} 282 283// A suspend check is done using the following instruction sequence: 284// (x86) 285// 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger 286// .. some intervening instructions. 287// 0xf720f1e6: 8500 test eax, [eax] 288// (x86_64) 289// 0x7f579de45d9e: 65488B0425A8000000 movq rax, gs:[0xa8] ; suspend_trigger 290// .. some intervening instructions. 291// 0x7f579de45da7: 8500 test eax, [eax] 292 293// The offset from fs is Thread::ThreadSuspendTriggerOffset(). 294// To check for a suspend check, we examine the instructions that caused 295// the fault. 296bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { 297 // These are the instructions to check for. The first one is the mov eax, fs:[xxx] 298 // where xxx is the offset of the suspend trigger. 299#if defined(__x86_64__) 300 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value(); 301#else 302 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value(); 303#endif 304 305 VLOG(signals) << "Checking for suspension point"; 306#if defined(__x86_64__) 307 uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast<uint8_t>(trigger & 0xff), 308 static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0}; 309#else 310 uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff), 311 static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0}; 312#endif 313 uint8_t checkinst2[] = {0x85, 0x00}; 314 315 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 316 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP); 317 uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP); 318 319 if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) { 320 // Second instruction is not correct (test eax,[eax]). 321 VLOG(signals) << "Not a suspension point"; 322 return false; 323 } 324 325 // The first instruction can a little bit up the stream due to load hoisting 326 // in the compiler. 327 uint8_t* limit = pc - 100; // Compiler will hoist to a max of 20 instructions. 328 uint8_t* ptr = pc - sizeof(checkinst1); 329 bool found = false; 330 while (ptr > limit) { 331 if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) { 332 found = true; 333 break; 334 } 335 ptr -= 1; 336 } 337 338 if (found) { 339 VLOG(signals) << "suspend check match"; 340 341 // We need to arrange for the signal handler to return to the null pointer 342 // exception generator. The return address must be the address of the 343 // next instruction (this instruction + 2). The return address 344 // is on the stack at the top address of the current frame. 345 346 // Push the return address onto the stack. 347 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2); 348 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t)); 349 *next_sp = retaddr; 350 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp); 351 352 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_test_suspend)); 353 354 // Now remove the suspend trigger that caused this fault. 355 Thread::Current()->RemoveSuspendTrigger(); 356 VLOG(signals) << "removed suspend trigger invoking test suspend"; 357 return true; 358 } 359 VLOG(signals) << "Not a suspend check match, first instruction mismatch"; 360 return false; 361} 362 363// The stack overflow check is done using the following instruction: 364// test eax, [esp+ -xxx] 365// where 'xxx' is the size of the overflow area. 366// 367// This is done before any frame is established in the method. The return 368// address for the previous method is on the stack at ESP. 369 370bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { 371 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); 372 uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP); 373 374 uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr); 375 VLOG(signals) << "fault_addr: " << std::hex << fault_addr; 376 VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp << 377 ", fault_addr: " << fault_addr; 378 379#if defined(__x86_64__) 380 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64); 381#else 382 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86); 383#endif 384 385 // Check that the fault address is the value expected for a stack overflow. 386 if (fault_addr != overflow_addr) { 387 VLOG(signals) << "Not a stack overflow"; 388 return false; 389 } 390 391 VLOG(signals) << "Stack overflow found"; 392 393 // Since the compiler puts the implicit overflow 394 // check before the callee save instructions, the SP is already pointing to 395 // the previous frame. 396 397 // Now arrange for the signal handler to return to art_quick_throw_stack_overflow. 398 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_stack_overflow)); 399 400 return true; 401} 402} // namespace art 403