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