fault_handler_x86.cc revision 8ce6b9040747054b444a7fa706503cd257801936
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 0x89:            // mov
169      case 0x8b:
170      case 0x38:        // cmp with memory.
171      case 0x39:
172      case 0x3a:
173      case 0x3b:
174      case 0x3c:
175      case 0x3d:
176      case 0x85:        // test.
177        modrm = *pc++;
178        has_modrm = true;
179        break;
180
181      case 0x80:        // group 1, byte immediate.
182      case 0x83:
183        modrm = *pc++;
184        has_modrm = true;
185        immediate_size = 1;
186        break;
187
188      case 0x81:        // group 1, word immediate.
189        modrm = *pc++;
190        has_modrm = true;
191        immediate_size = 4;
192        break;
193
194      default:
195        unhandled_instruction = true;
196        break;
197    }
198  }
199
200  if (unhandled_instruction) {
201    VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast<int>(opcode);
202    return 0;
203  }
204
205  if (has_modrm) {
206    uint8_t mod = (modrm >> 6) & 0b11;
207
208    // Check for SIB.
209    if (mod != 0b11 && (modrm & 0b111) == 4) {
210      ++pc;     // SIB
211    }
212
213    switch (mod) {
214      case 0b00: break;
215      case 0b01: displacement_size = 1; break;
216      case 0b10: displacement_size = 4; break;
217      case 0b11:
218        break;
219    }
220  }
221
222  // Skip displacement and immediate.
223  pc += displacement_size + immediate_size;
224
225  VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc);
226  return pc - startpc;
227}
228
229void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
230  // For the Intel architectures we need to go to an assembly language
231  // stub.  This is because the 32 bit call to longjmp is much different
232  // from the 64 bit ABI call and pushing things onto the stack inside this
233  // handler was unwieldy and ugly.  The use of the stub means we can keep
234  // this code the same for both 32 and 64 bit.
235
236  Thread* self = Thread::Current();
237  CHECK(self != nullptr);       // This will cause a SIGABRT if self is nullptr.
238
239  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
240  uc->CTX_JMP_BUF = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
241  uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_nested_signal_return);
242}
243
244void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
245                                             mirror::ArtMethod** out_method,
246                                             uintptr_t* out_return_pc, uintptr_t* out_sp) {
247  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
248  *out_sp = static_cast<uintptr_t>(uc->CTX_ESP);
249  VLOG(signals) << "sp: " << std::hex << *out_sp;
250  if (*out_sp == 0) {
251    return;
252  }
253
254  // In the case of a stack overflow, the stack is not valid and we can't
255  // get the method from the top of the stack.  However it's in EAX(x86)/RDI(x86_64).
256  uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);
257  uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
258#if defined(__x86_64__)
259      reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86_64));
260#else
261      reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86));
262#endif
263  if (overflow_addr == fault_addr) {
264    *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->CTX_METHOD);
265  } else {
266    // The method is at the top of the stack.
267    *out_method = (reinterpret_cast<StackReference<mirror::ArtMethod>* >(*out_sp)[0]).AsMirrorPtr();
268  }
269
270  uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
271  VLOG(signals) << HexDump(pc, 32, true, "PC ");
272
273  uint32_t instr_size = GetInstructionSize(pc);
274  if (instr_size == 0) {
275    // Unknown instruction, tell caller it's not ours.
276    *out_method = nullptr;
277    return;
278  }
279  *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
280}
281
282bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
283  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
284  uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
285  uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
286
287  uint32_t instr_size = GetInstructionSize(pc);
288  if (instr_size == 0) {
289    // Unknown instruction, can't really happen.
290    return false;
291  }
292
293  // We need to arrange for the signal handler to return to the null pointer
294  // exception generator.  The return address must be the address of the
295  // next instruction (this instruction + instruction size).  The return address
296  // is on the stack at the top address of the current frame.
297
298  // Push the return address onto the stack.
299  uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size);
300  uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
301  *next_sp = retaddr;
302  uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
303
304  uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_null_pointer_exception));
305  VLOG(signals) << "Generating null pointer exception";
306  return true;
307}
308
309// A suspend check is done using the following instruction sequence:
310// (x86)
311// 0xf720f1df:         648B058C000000      mov     eax, fs:[0x8c]  ; suspend_trigger
312// .. some intervening instructions.
313// 0xf720f1e6:                   8500      test    eax, [eax]
314// (x86_64)
315// 0x7f579de45d9e: 65488B0425A8000000      movq    rax, gs:[0xa8]  ; suspend_trigger
316// .. some intervening instructions.
317// 0x7f579de45da7:               8500      test    eax, [eax]
318
319// The offset from fs is Thread::ThreadSuspendTriggerOffset().
320// To check for a suspend check, we examine the instructions that caused
321// the fault.
322bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
323  // These are the instructions to check for.  The first one is the mov eax, fs:[xxx]
324  // where xxx is the offset of the suspend trigger.
325#if defined(__x86_64__)
326  uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value();
327#else
328  uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
329#endif
330
331  VLOG(signals) << "Checking for suspension point";
332#if defined(__x86_64__)
333  uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast<uint8_t>(trigger & 0xff),
334      static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
335#else
336  uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
337      static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
338#endif
339  uint8_t checkinst2[] = {0x85, 0x00};
340
341  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
342  uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
343  uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
344
345  if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) {
346    // Second instruction is not correct (test eax,[eax]).
347    VLOG(signals) << "Not a suspension point";
348    return false;
349  }
350
351  // The first instruction can a little bit up the stream due to load hoisting
352  // in the compiler.
353  uint8_t* limit = pc - 100;   // Compiler will hoist to a max of 20 instructions.
354  uint8_t* ptr = pc - sizeof(checkinst1);
355  bool found = false;
356  while (ptr > limit) {
357    if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) {
358      found = true;
359      break;
360    }
361    ptr -= 1;
362  }
363
364  if (found) {
365    VLOG(signals) << "suspend check match";
366
367    // We need to arrange for the signal handler to return to the null pointer
368    // exception generator.  The return address must be the address of the
369    // next instruction (this instruction + 2).  The return address
370    // is on the stack at the top address of the current frame.
371
372    // Push the return address onto the stack.
373    uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2);
374    uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
375    *next_sp = retaddr;
376    uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
377
378    uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_test_suspend));
379
380    // Now remove the suspend trigger that caused this fault.
381    Thread::Current()->RemoveSuspendTrigger();
382    VLOG(signals) << "removed suspend trigger invoking test suspend";
383    return true;
384  }
385  VLOG(signals) << "Not a suspend check match, first instruction mismatch";
386  return false;
387}
388
389// The stack overflow check is done using the following instruction:
390// test eax, [esp+ -xxx]
391// where 'xxx' is the size of the overflow area.
392//
393// This is done before any frame is established in the method.  The return
394// address for the previous method is on the stack at ESP.
395
396bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
397  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
398  uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP);
399
400  uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
401  VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
402  VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
403    ", fault_addr: " << fault_addr;
404
405#if defined(__x86_64__)
406  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64);
407#else
408  uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86);
409#endif
410
411  // Check that the fault address is the value expected for a stack overflow.
412  if (fault_addr != overflow_addr) {
413    VLOG(signals) << "Not a stack overflow";
414    return false;
415  }
416
417  VLOG(signals) << "Stack overflow found";
418
419  // Since the compiler puts the implicit overflow
420  // check before the callee save instructions, the SP is already pointing to
421  // the previous frame.
422
423  // Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
424  uc->CTX_EIP = reinterpret_cast<uintptr_t>(EXT_SYM(art_quick_throw_stack_overflow));
425
426  return true;
427}
428}       // namespace art
429