blob: 8b6c9b1ae3d026d1b1b0e1dd52d5b3501bbeb673 [file] [log] [blame]
Dave Allisonb373e092014-02-20 16:06:36 -08001/*
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"
Dave Allison69dfe512014-07-11 17:11:58 +000024#include "mirror/art_method.h"
25#include "mirror/art_method-inl.h"
26#include "thread.h"
27#include "thread-inl.h"
Dave Allisonb373e092014-02-20 16:06:36 -080028
Dave Allison69dfe512014-07-11 17:11:58 +000029#if defined(__APPLE__)
30#define ucontext __darwin_ucontext
31#define CTX_ESP uc_mcontext->__ss.__esp
32#define CTX_EIP uc_mcontext->__ss.__eip
33#define CTX_EAX uc_mcontext->__ss.__eax
Dave Allisondfd3b472014-07-16 16:04:32 -070034#define CTX_METHOD uc_mcontext->__ss.__eax
35#elif defined(__x86_64__)
36#define CTX_ESP uc_mcontext.gregs[REG_RSP]
37#define CTX_EIP uc_mcontext.gregs[REG_RIP]
38#define CTX_EAX uc_mcontext.gregs[REG_RAX]
39#define CTX_METHOD uc_mcontext.gregs[REG_RDI]
Dave Allison69dfe512014-07-11 17:11:58 +000040#else
41#define CTX_ESP uc_mcontext.gregs[REG_ESP]
42#define CTX_EIP uc_mcontext.gregs[REG_EIP]
43#define CTX_EAX uc_mcontext.gregs[REG_EAX]
Dave Allisondfd3b472014-07-16 16:04:32 -070044#define CTX_METHOD uc_mcontext.gregs[REG_EAX]
Dave Allison69dfe512014-07-11 17:11:58 +000045#endif
Dave Allisonb373e092014-02-20 16:06:36 -080046
47//
Dave Allisondfd3b472014-07-16 16:04:32 -070048// X86 (and X86_64) specific fault handler functions.
Dave Allisonb373e092014-02-20 16:06:36 -080049//
50
51namespace art {
52
Dave Allison69dfe512014-07-11 17:11:58 +000053extern "C" void art_quick_throw_null_pointer_exception();
54extern "C" void art_quick_throw_stack_overflow_from_signal();
55extern "C" void art_quick_test_suspend();
56
Dave Allison69dfe512014-07-11 17:11:58 +000057// Get the size of an instruction in bytes.
Dave Allisondfd3b472014-07-16 16:04:32 -070058// Return 0 if the instruction is not handled.
59static uint32_t GetInstructionSize(const uint8_t* pc) {
60#if defined(__x86_64)
61 const bool x86_64 = true;
62#else
63 const bool x86_64 = false;
Dave Allison69dfe512014-07-11 17:11:58 +000064#endif
65
Dave Allisondfd3b472014-07-16 16:04:32 -070066 const uint8_t* startpc = pc;
Dave Allison69dfe512014-07-11 17:11:58 +000067
Dave Allison69dfe512014-07-11 17:11:58 +000068 uint8_t opcode = *pc++;
Dave Allisondfd3b472014-07-16 16:04:32 -070069 uint8_t modrm;
70 bool has_modrm = false;
71 bool two_byte = false;
72 uint32_t displacement_size = 0;
73 uint32_t immediate_size = 0;
74
75 // Prefixes.
76 while (true) {
77 bool prefix_present = false;
78 switch (opcode) {
79 // Group 1
80 case 0xf0:
81 case 0xf2:
82 case 0xf3:
83
84 // Group 2
85 case 0x2e:
86 case 0x36:
87 case 0x3e:
88 case 0x26:
89 case 0x64:
90 case 0x65:
91
92 // Group 3
93 case 0x66:
94
95 // Group 4
96 case 0x67:
97 opcode = *pc++;
98 prefix_present = true;
99 break;
100 }
101 if (!prefix_present) {
102 break;
103 }
104 }
105
106 if (x86_64 && opcode >= 0x40 && opcode <= 0x4f) {
107 opcode = *pc++;
108 }
109
110 if (opcode == 0x0f) {
111 // Two byte opcode
Dave Allison69dfe512014-07-11 17:11:58 +0000112 two_byte = true;
113 opcode = *pc++;
114 }
115
Dave Allisondfd3b472014-07-16 16:04:32 -0700116 bool unhandled_instruction = false;
Dave Allison69dfe512014-07-11 17:11:58 +0000117
Dave Allison69dfe512014-07-11 17:11:58 +0000118 if (two_byte) {
Dave Allisondfd3b472014-07-16 16:04:32 -0700119 switch (opcode) {
120 case 0x10: // vmovsd/ss
121 case 0x11: // vmovsd/ss
122 case 0xb6: // movzx
123 case 0xb7:
124 case 0xbe: // movsx
125 case 0xbf:
126 modrm = *pc++;
127 has_modrm = true;
128 break;
129 default:
130 unhandled_instruction = true;
131 break;
132 }
133 } else {
134 switch (opcode) {
135 case 0x89: // mov
136 case 0x8b:
137 case 0x38: // cmp with memory.
138 case 0x39:
139 case 0x3a:
140 case 0x3b:
141 case 0x3c:
142 case 0x3d:
143 case 0x85: // test.
144 modrm = *pc++;
145 has_modrm = true;
146 break;
Dave Allison69dfe512014-07-11 17:11:58 +0000147
Dave Allisondfd3b472014-07-16 16:04:32 -0700148 case 0x80: // group 1, byte immediate.
149 case 0x83:
150 modrm = *pc++;
151 has_modrm = true;
152 immediate_size = 1;
Dave Allison69dfe512014-07-11 17:11:58 +0000153 break;
Dave Allisondfd3b472014-07-16 16:04:32 -0700154
155 case 0x81: // group 1, word immediate.
156 modrm = *pc++;
157 has_modrm = true;
158 immediate_size = 4;
Dave Allison69dfe512014-07-11 17:11:58 +0000159 break;
Dave Allisondfd3b472014-07-16 16:04:32 -0700160
161 default:
162 unhandled_instruction = true;
Dave Allison69dfe512014-07-11 17:11:58 +0000163 break;
164 }
165 }
166
Dave Allisondfd3b472014-07-16 16:04:32 -0700167 if (unhandled_instruction) {
168 VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast<int>(opcode);
169 return 0;
170 }
171
172 if (has_modrm) {
173 uint8_t mod = (modrm >> 6) & 0b11;
174
175 // Check for SIB.
176 if (mod != 0b11 && (modrm & 0b111) == 4) {
177 ++pc; // SIB
178 }
179
180 switch (mod) {
181 case 0b00: break;
182 case 0b01: displacement_size = 1; break;
183 case 0b10: displacement_size = 4; break;
184 case 0b11:
185 break;
186 }
187 }
188
189 // Skip displacement and immediate.
190 pc += displacement_size + immediate_size;
191
192 VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc);
193 return pc - startpc;
Dave Allison69dfe512014-07-11 17:11:58 +0000194}
195
Dave Allisondfd3b472014-07-16 16:04:32 -0700196void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
Dave Allison69dfe512014-07-11 17:11:58 +0000197 mirror::ArtMethod** out_method,
Mathieu Chartierc751fdc2014-03-30 15:25:44 -0700198 uintptr_t* out_return_pc, uintptr_t* out_sp) {
Dave Allison69dfe512014-07-11 17:11:58 +0000199 struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
200 *out_sp = static_cast<uintptr_t>(uc->CTX_ESP);
201 VLOG(signals) << "sp: " << std::hex << *out_sp;
202 if (*out_sp == 0) {
203 return;
204 }
205
206 // In the case of a stack overflow, the stack is not valid and we can't
Dave Allisondfd3b472014-07-16 16:04:32 -0700207 // get the method from the top of the stack. However it's in EAX(x86)/RDI(x86_64).
Dave Allison69dfe512014-07-11 17:11:58 +0000208 uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);
209 uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
Dave Allisondfd3b472014-07-16 16:04:32 -0700210#if defined(__x86_64__)
211 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86_64));
212#else
Dave Allison69dfe512014-07-11 17:11:58 +0000213 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86));
Dave Allisondfd3b472014-07-16 16:04:32 -0700214#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000215 if (overflow_addr == fault_addr) {
Dave Allisondfd3b472014-07-16 16:04:32 -0700216 *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_METHOD);
Dave Allison69dfe512014-07-11 17:11:58 +0000217 } else {
218 // The method is at the top of the stack.
Dave Allisondfd3b472014-07-16 16:04:32 -0700219 *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr();
Dave Allison69dfe512014-07-11 17:11:58 +0000220 }
221
222 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
223 VLOG(signals) << HexDump(pc, 32, true, "PC ");
224
225 uint32_t instr_size = GetInstructionSize(pc);
Dave Allisondfd3b472014-07-16 16:04:32 -0700226 if (instr_size == 0) {
227 // Unknown instruction, tell caller it's not ours.
228 *out_method = nullptr;
229 return;
230 }
Dave Allison69dfe512014-07-11 17:11:58 +0000231 *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
Dave Allisonb373e092014-02-20 16:06:36 -0800232}
233
234bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
Dave Allison69dfe512014-07-11 17:11:58 +0000235 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
236 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
237 uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
238
239 uint32_t instr_size = GetInstructionSize(pc);
Dave Allisondfd3b472014-07-16 16:04:32 -0700240 if (instr_size == 0) {
241 // Unknown instruction, can't really happen.
242 return false;
243 }
244
Dave Allison69dfe512014-07-11 17:11:58 +0000245 // We need to arrange for the signal handler to return to the null pointer
246 // exception generator. The return address must be the address of the
247 // next instruction (this instruction + instruction size). The return address
248 // is on the stack at the top address of the current frame.
249
250 // Push the return address onto the stack.
Dave Allisondfd3b472014-07-16 16:04:32 -0700251 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size);
252 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
Dave Allison69dfe512014-07-11 17:11:58 +0000253 *next_sp = retaddr;
Dave Allisondfd3b472014-07-16 16:04:32 -0700254 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
Dave Allison69dfe512014-07-11 17:11:58 +0000255
256 uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
257 VLOG(signals) << "Generating null pointer exception";
258 return true;
259}
260
261// A suspend check is done using the following instruction sequence:
Dave Allisondfd3b472014-07-16 16:04:32 -0700262// (x86)
Dave Allison69dfe512014-07-11 17:11:58 +0000263// 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger
264// .. some intervening instructions.
265// 0xf720f1e6: 8500 test eax, [eax]
Dave Allisondfd3b472014-07-16 16:04:32 -0700266// (x86_64)
267// 0x7f579de45d9e: 65488B0425A8000000 movq rax, gs:[0xa8] ; suspend_trigger
268// .. some intervening instructions.
269// 0x7f579de45da7: 8500 test eax, [eax]
Dave Allison69dfe512014-07-11 17:11:58 +0000270
271// The offset from fs is Thread::ThreadSuspendTriggerOffset().
272// To check for a suspend check, we examine the instructions that caused
273// the fault.
274bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
275 // These are the instructions to check for. The first one is the mov eax, fs:[xxx]
276 // where xxx is the offset of the suspend trigger.
Dave Allisondfd3b472014-07-16 16:04:32 -0700277#if defined(__x86_64__)
278 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value();
279#else
Dave Allison69dfe512014-07-11 17:11:58 +0000280 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
Dave Allisondfd3b472014-07-16 16:04:32 -0700281#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000282
283 VLOG(signals) << "Checking for suspension point";
Dave Allisondfd3b472014-07-16 16:04:32 -0700284#if defined(__x86_64__)
285 uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast<uint8_t>(trigger & 0xff),
286 static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
287#else
Dave Allison69dfe512014-07-11 17:11:58 +0000288 uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
289 static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
Dave Allisondfd3b472014-07-16 16:04:32 -0700290#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000291 uint8_t checkinst2[] = {0x85, 0x00};
292
293 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
294 uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
295 uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
296
297 if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) {
298 // Second instruction is not correct (test eax,[eax]).
299 VLOG(signals) << "Not a suspension point";
300 return false;
301 }
302
303 // The first instruction can a little bit up the stream due to load hoisting
304 // in the compiler.
305 uint8_t* limit = pc - 100; // Compiler will hoist to a max of 20 instructions.
306 uint8_t* ptr = pc - sizeof(checkinst1);
307 bool found = false;
308 while (ptr > limit) {
309 if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) {
310 found = true;
311 break;
312 }
313 ptr -= 1;
314 }
315
316 if (found) {
317 VLOG(signals) << "suspend check match";
318
319 // We need to arrange for the signal handler to return to the null pointer
320 // exception generator. The return address must be the address of the
321 // next instruction (this instruction + 2). The return address
322 // is on the stack at the top address of the current frame.
323
324 // Push the return address onto the stack.
Dave Allisondfd3b472014-07-16 16:04:32 -0700325 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2);
326 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
Dave Allison69dfe512014-07-11 17:11:58 +0000327 *next_sp = retaddr;
Dave Allisondfd3b472014-07-16 16:04:32 -0700328 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
Dave Allison69dfe512014-07-11 17:11:58 +0000329
330 uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_test_suspend);
331
332 // Now remove the suspend trigger that caused this fault.
333 Thread::Current()->RemoveSuspendTrigger();
334 VLOG(signals) << "removed suspend trigger invoking test suspend";
335 return true;
336 }
337 VLOG(signals) << "Not a suspend check match, first instruction mismatch";
Dave Allisonb373e092014-02-20 16:06:36 -0800338 return false;
339}
340
Dave Allison69dfe512014-07-11 17:11:58 +0000341// The stack overflow check is done using the following instruction:
342// test eax, [esp+ -xxx]
343// where 'xxx' is the size of the overflow area.
344//
345// This is done before any frame is established in the method. The return
346// address for the previous method is on the stack at ESP.
Dave Allisonb373e092014-02-20 16:06:36 -0800347
348bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
Dave Allison69dfe512014-07-11 17:11:58 +0000349 struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
350 uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP);
351
352 uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
353 VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
354 VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
355 ", fault_addr: " << fault_addr;
356
Dave Allisondfd3b472014-07-16 16:04:32 -0700357#if defined(__x86_64__)
358 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64);
359#else
Dave Allison69dfe512014-07-11 17:11:58 +0000360 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86);
Dave Allisondfd3b472014-07-16 16:04:32 -0700361#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000362
363 Thread* self = Thread::Current();
364 uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) -
365 Thread::kStackOverflowProtectedSize;
366
367 // Check that the fault address is the value expected for a stack overflow.
368 if (fault_addr != overflow_addr) {
369 VLOG(signals) << "Not a stack overflow";
370 return false;
371 }
372
373 // We know this is a stack overflow. We need to move the sp to the overflow region
374 // that exists below the protected region. Determine the address of the next
375 // available valid address below the protected region.
376 VLOG(signals) << "setting sp to overflow region at " << std::hex << pregion;
377
378 // Since the compiler puts the implicit overflow
379 // check before the callee save instructions, the SP is already pointing to
380 // the previous frame.
381
382 // Tell the stack overflow code where the new stack pointer should be.
383 uc->CTX_EAX = pregion;
384
385 // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal.
386 uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow_from_signal);
387
388 return true;
Dave Allisonb373e092014-02-20 16:06:36 -0800389}
390} // namespace art