blob: 89baded816f8f90040e28fe3ef9af6bf1db8b826 [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
Dan Albert85fa7962014-08-10 10:14:59 -070031
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.__rax
38#else
39// 32 bit mac build.
Dave Allison69dfe512014-07-11 17:11:58 +000040#define CTX_ESP uc_mcontext->__ss.__esp
41#define CTX_EIP uc_mcontext->__ss.__eip
42#define CTX_EAX uc_mcontext->__ss.__eax
Dave Allisondfd3b472014-07-16 16:04:32 -070043#define CTX_METHOD uc_mcontext->__ss.__eax
Dan Albert85fa7962014-08-10 10:14:59 -070044#endif
45
Dave Allisondfd3b472014-07-16 16:04:32 -070046#elif defined(__x86_64__)
Dan Albert85fa7962014-08-10 10:14:59 -070047// 64 bit linux build.
Dave Allisondfd3b472014-07-16 16:04:32 -070048#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]
Dave Allison69dfe512014-07-11 17:11:58 +000052#else
Dan Albert85fa7962014-08-10 10:14:59 -070053// 32 bit linux build.
Dave Allison69dfe512014-07-11 17:11:58 +000054#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]
Dave Allisondfd3b472014-07-16 16:04:32 -070057#define CTX_METHOD uc_mcontext.gregs[REG_EAX]
Dave Allison69dfe512014-07-11 17:11:58 +000058#endif
Dave Allisonb373e092014-02-20 16:06:36 -080059
60//
Dave Allisondfd3b472014-07-16 16:04:32 -070061// X86 (and X86_64) specific fault handler functions.
Dave Allisonb373e092014-02-20 16:06:36 -080062//
63
64namespace art {
65
Dan Albert85fa7962014-08-10 10:14:59 -070066#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_from_signal();
70extern "C" void _art_quick_test_suspend();
71#define EXT_SYM(sym) _ ## sym
72#else
Dave Allison69dfe512014-07-11 17:11:58 +000073extern "C" void art_quick_throw_null_pointer_exception();
74extern "C" void art_quick_throw_stack_overflow_from_signal();
75extern "C" void art_quick_test_suspend();
Dan Albert85fa7962014-08-10 10:14:59 -070076#define EXT_SYM(sym) sym
77#endif
Dave Allison69dfe512014-07-11 17:11:58 +000078
Dave Allison69dfe512014-07-11 17:11:58 +000079// Get the size of an instruction in bytes.
Dave Allisondfd3b472014-07-16 16:04:32 -070080// 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;
Dave Allison69dfe512014-07-11 17:11:58 +000086#endif
87
Dave Allisondfd3b472014-07-16 16:04:32 -070088 const uint8_t* startpc = pc;
Dave Allison69dfe512014-07-11 17:11:58 +000089
Dave Allison69dfe512014-07-11 17:11:58 +000090 uint8_t opcode = *pc++;
Dave Allisondfd3b472014-07-16 16:04:32 -070091 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
Dave Allison69dfe512014-07-11 17:11:58 +0000134 two_byte = true;
135 opcode = *pc++;
136 }
137
Dave Allisondfd3b472014-07-16 16:04:32 -0700138 bool unhandled_instruction = false;
Dave Allison69dfe512014-07-11 17:11:58 +0000139
Dave Allison69dfe512014-07-11 17:11:58 +0000140 if (two_byte) {
Dave Allisondfd3b472014-07-16 16:04:32 -0700141 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;
Dave Allison69dfe512014-07-11 17:11:58 +0000169
Dave Allisondfd3b472014-07-16 16:04:32 -0700170 case 0x80: // group 1, byte immediate.
171 case 0x83:
172 modrm = *pc++;
173 has_modrm = true;
174 immediate_size = 1;
Dave Allison69dfe512014-07-11 17:11:58 +0000175 break;
Dave Allisondfd3b472014-07-16 16:04:32 -0700176
177 case 0x81: // group 1, word immediate.
178 modrm = *pc++;
179 has_modrm = true;
180 immediate_size = 4;
Dave Allison69dfe512014-07-11 17:11:58 +0000181 break;
Dave Allisondfd3b472014-07-16 16:04:32 -0700182
183 default:
184 unhandled_instruction = true;
Dave Allison69dfe512014-07-11 17:11:58 +0000185 break;
186 }
187 }
188
Dave Allisondfd3b472014-07-16 16:04:32 -0700189 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;
Dave Allison69dfe512014-07-11 17:11:58 +0000216}
217
Dave Allisondfd3b472014-07-16 16:04:32 -0700218void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
Dave Allison69dfe512014-07-11 17:11:58 +0000219 mirror::ArtMethod** out_method,
Mathieu Chartierc751fdc2014-03-30 15:25:44 -0700220 uintptr_t* out_return_pc, uintptr_t* out_sp) {
Dave Allison69dfe512014-07-11 17:11:58 +0000221 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
Dave Allisondfd3b472014-07-16 16:04:32 -0700229 // 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 +0000230 uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);
231 uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
Dave Allisondfd3b472014-07-16 16:04:32 -0700232#if defined(__x86_64__)
233 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86_64));
234#else
Dave Allison69dfe512014-07-11 17:11:58 +0000235 reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86));
Dave Allisondfd3b472014-07-16 16:04:32 -0700236#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000237 if (overflow_addr == fault_addr) {
Dave Allisondfd3b472014-07-16 16:04:32 -0700238 *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_METHOD);
Dave Allison69dfe512014-07-11 17:11:58 +0000239 } else {
240 // The method is at the top of the stack.
Dave Allisondfd3b472014-07-16 16:04:32 -0700241 *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr();
Dave Allison69dfe512014-07-11 17:11:58 +0000242 }
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);
Dave Allisondfd3b472014-07-16 16:04:32 -0700248 if (instr_size == 0) {
249 // Unknown instruction, tell caller it's not ours.
250 *out_method = nullptr;
251 return;
252 }
Dave Allison69dfe512014-07-11 17:11:58 +0000253 *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
Dave Allisonb373e092014-02-20 16:06:36 -0800254}
255
256bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
Dave Allison69dfe512014-07-11 17:11:58 +0000257 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);
Dave Allisondfd3b472014-07-16 16:04:32 -0700262 if (instr_size == 0) {
263 // Unknown instruction, can't really happen.
264 return false;
265 }
266
Dave Allison69dfe512014-07-11 17:11:58 +0000267 // 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.
Dave Allisondfd3b472014-07-16 16:04:32 -0700273 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size);
274 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
Dave Allison69dfe512014-07-11 17:11:58 +0000275 *next_sp = retaddr;
Dave Allisondfd3b472014-07-16 16:04:32 -0700276 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
Dave Allison69dfe512014-07-11 17:11:58 +0000277
Dan Albert85fa7962014-08-10 10:14:59 -0700278 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_null_pointer_exception));
Dave Allison69dfe512014-07-11 17:11:58 +0000279 VLOG(signals) << "Generating null pointer exception";
280 return true;
281}
282
283// A suspend check is done using the following instruction sequence:
Dave Allisondfd3b472014-07-16 16:04:32 -0700284// (x86)
Dave Allison69dfe512014-07-11 17:11:58 +0000285// 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger
286// .. some intervening instructions.
287// 0xf720f1e6: 8500 test eax, [eax]
Dave Allisondfd3b472014-07-16 16:04:32 -0700288// (x86_64)
289// 0x7f579de45d9e: 65488B0425A8000000 movq rax, gs:[0xa8] ; suspend_trigger
290// .. some intervening instructions.
291// 0x7f579de45da7: 8500 test eax, [eax]
Dave Allison69dfe512014-07-11 17:11:58 +0000292
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.
Dave Allisondfd3b472014-07-16 16:04:32 -0700299#if defined(__x86_64__)
300 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value();
301#else
Dave Allison69dfe512014-07-11 17:11:58 +0000302 uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
Dave Allisondfd3b472014-07-16 16:04:32 -0700303#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000304
305 VLOG(signals) << "Checking for suspension point";
Dave Allisondfd3b472014-07-16 16:04:32 -0700306#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
Dave Allison69dfe512014-07-11 17:11:58 +0000310 uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
311 static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
Dave Allisondfd3b472014-07-16 16:04:32 -0700312#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000313 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.
Dave Allisondfd3b472014-07-16 16:04:32 -0700347 uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2);
348 uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
Dave Allison69dfe512014-07-11 17:11:58 +0000349 *next_sp = retaddr;
Dave Allisondfd3b472014-07-16 16:04:32 -0700350 uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
Dave Allison69dfe512014-07-11 17:11:58 +0000351
Dan Albert85fa7962014-08-10 10:14:59 -0700352 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_test_suspend));
Dave Allison69dfe512014-07-11 17:11:58 +0000353
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";
Dave Allisonb373e092014-02-20 16:06:36 -0800360 return false;
361}
362
Dave Allison69dfe512014-07-11 17:11:58 +0000363// 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.
Dave Allisonb373e092014-02-20 16:06:36 -0800369
370bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
Dave Allison69dfe512014-07-11 17:11:58 +0000371 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
Dave Allisondfd3b472014-07-16 16:04:32 -0700379#if defined(__x86_64__)
380 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64);
381#else
Dave Allison69dfe512014-07-11 17:11:58 +0000382 uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86);
Dave Allisondfd3b472014-07-16 16:04:32 -0700383#endif
Dave Allison69dfe512014-07-11 17:11:58 +0000384
385 Thread* self = Thread::Current();
386 uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) -
387 Thread::kStackOverflowProtectedSize;
388
389 // Check that the fault address is the value expected for a stack overflow.
390 if (fault_addr != overflow_addr) {
391 VLOG(signals) << "Not a stack overflow";
392 return false;
393 }
394
395 // We know this is a stack overflow. We need to move the sp to the overflow region
396 // that exists below the protected region. Determine the address of the next
397 // available valid address below the protected region.
398 VLOG(signals) << "setting sp to overflow region at " << std::hex << pregion;
399
400 // Since the compiler puts the implicit overflow
401 // check before the callee save instructions, the SP is already pointing to
402 // the previous frame.
403
404 // Tell the stack overflow code where the new stack pointer should be.
405 uc->CTX_EAX = pregion;
406
407 // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal.
Dan Albert85fa7962014-08-10 10:14:59 -0700408 uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_stack_overflow_from_signal));
Dave Allison69dfe512014-07-11 17:11:58 +0000409
410 return true;
Dave Allisonb373e092014-02-20 16:06:36 -0800411}
412} // namespace art