xref: /aosp_15_r20/art/runtime/arch/x86/fault_handler_x86.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "fault_handler.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <sys/ucontext.h>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "arch/instruction_set.h"
22*795d594fSAndroid Build Coastguard Worker #include "art_method.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/hex_dump.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"  // For VLOG.
25*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/pointer_size.h"
27*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
28*795d594fSAndroid Build Coastguard Worker #include "runtime_globals.h"
29*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker #if defined(__APPLE__)
32*795d594fSAndroid Build Coastguard Worker #define ucontext __darwin_ucontext
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker #if defined(__x86_64__)
35*795d594fSAndroid Build Coastguard Worker // 64 bit mac build.
36*795d594fSAndroid Build Coastguard Worker #define CTX_ESP uc_mcontext->__ss.__rsp
37*795d594fSAndroid Build Coastguard Worker #define CTX_EIP uc_mcontext->__ss.__rip
38*795d594fSAndroid Build Coastguard Worker #define CTX_EAX uc_mcontext->__ss.__rax
39*795d594fSAndroid Build Coastguard Worker #define CTX_METHOD uc_mcontext->__ss.__rdi
40*795d594fSAndroid Build Coastguard Worker #define CTX_RDI uc_mcontext->__ss.__rdi
41*795d594fSAndroid Build Coastguard Worker #define CTX_JMP_BUF uc_mcontext->__ss.__rdi
42*795d594fSAndroid Build Coastguard Worker #else
43*795d594fSAndroid Build Coastguard Worker // 32 bit mac build.
44*795d594fSAndroid Build Coastguard Worker #define CTX_ESP uc_mcontext->__ss.__esp
45*795d594fSAndroid Build Coastguard Worker #define CTX_EIP uc_mcontext->__ss.__eip
46*795d594fSAndroid Build Coastguard Worker #define CTX_EAX uc_mcontext->__ss.__eax
47*795d594fSAndroid Build Coastguard Worker #define CTX_METHOD uc_mcontext->__ss.__eax
48*795d594fSAndroid Build Coastguard Worker #define CTX_JMP_BUF uc_mcontext->__ss.__eax
49*795d594fSAndroid Build Coastguard Worker #endif
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker #elif defined(__x86_64__)
52*795d594fSAndroid Build Coastguard Worker // 64 bit linux build.
53*795d594fSAndroid Build Coastguard Worker #define CTX_ESP uc_mcontext.gregs[REG_RSP]
54*795d594fSAndroid Build Coastguard Worker #define CTX_EIP uc_mcontext.gregs[REG_RIP]
55*795d594fSAndroid Build Coastguard Worker #define CTX_EAX uc_mcontext.gregs[REG_RAX]
56*795d594fSAndroid Build Coastguard Worker #define CTX_METHOD uc_mcontext.gregs[REG_RDI]
57*795d594fSAndroid Build Coastguard Worker #define CTX_RDI uc_mcontext.gregs[REG_RDI]
58*795d594fSAndroid Build Coastguard Worker #define CTX_JMP_BUF uc_mcontext.gregs[REG_RDI]
59*795d594fSAndroid Build Coastguard Worker #else
60*795d594fSAndroid Build Coastguard Worker // 32 bit linux build.
61*795d594fSAndroid Build Coastguard Worker #define CTX_ESP uc_mcontext.gregs[REG_ESP]
62*795d594fSAndroid Build Coastguard Worker #define CTX_EIP uc_mcontext.gregs[REG_EIP]
63*795d594fSAndroid Build Coastguard Worker #define CTX_EAX uc_mcontext.gregs[REG_EAX]
64*795d594fSAndroid Build Coastguard Worker #define CTX_METHOD uc_mcontext.gregs[REG_EAX]
65*795d594fSAndroid Build Coastguard Worker #define CTX_JMP_BUF uc_mcontext.gregs[REG_EAX]
66*795d594fSAndroid Build Coastguard Worker #endif
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker //
69*795d594fSAndroid Build Coastguard Worker // X86 (and X86_64) specific fault handler functions.
70*795d594fSAndroid Build Coastguard Worker //
71*795d594fSAndroid Build Coastguard Worker 
72*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_throw_null_pointer_exception_from_signal();
75*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_throw_stack_overflow();
76*795d594fSAndroid Build Coastguard Worker extern "C" void art_quick_test_suspend();
77*795d594fSAndroid Build Coastguard Worker 
78*795d594fSAndroid Build Coastguard Worker // Get the size of an instruction in bytes.
79*795d594fSAndroid Build Coastguard Worker // Return 0 if the instruction is not handled.
GetInstructionSize(const uint8_t * pc,size_t bytes)80*795d594fSAndroid Build Coastguard Worker static uint32_t GetInstructionSize(const uint8_t* pc, size_t bytes) {
81*795d594fSAndroid Build Coastguard Worker #define FETCH_OR_SKIP_BYTE(assignment)  \
82*795d594fSAndroid Build Coastguard Worker   do {                                  \
83*795d594fSAndroid Build Coastguard Worker     if (bytes == 0u) {                  \
84*795d594fSAndroid Build Coastguard Worker       return 0u;                        \
85*795d594fSAndroid Build Coastguard Worker     }                                   \
86*795d594fSAndroid Build Coastguard Worker     (assignment);                       \
87*795d594fSAndroid Build Coastguard Worker     ++pc;                               \
88*795d594fSAndroid Build Coastguard Worker     --bytes;                            \
89*795d594fSAndroid Build Coastguard Worker   } while (0)
90*795d594fSAndroid Build Coastguard Worker #define FETCH_BYTE(var) FETCH_OR_SKIP_BYTE((var) = *pc)
91*795d594fSAndroid Build Coastguard Worker #define SKIP_BYTE() FETCH_OR_SKIP_BYTE((void)0)
92*795d594fSAndroid Build Coastguard Worker 
93*795d594fSAndroid Build Coastguard Worker #if defined(__x86_64)
94*795d594fSAndroid Build Coastguard Worker   const bool x86_64 = true;
95*795d594fSAndroid Build Coastguard Worker #else
96*795d594fSAndroid Build Coastguard Worker   const bool x86_64 = false;
97*795d594fSAndroid Build Coastguard Worker #endif
98*795d594fSAndroid Build Coastguard Worker 
99*795d594fSAndroid Build Coastguard Worker   const uint8_t* startpc = pc;
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker   uint8_t opcode;
102*795d594fSAndroid Build Coastguard Worker   FETCH_BYTE(opcode);
103*795d594fSAndroid Build Coastguard Worker   uint8_t modrm;
104*795d594fSAndroid Build Coastguard Worker   bool has_modrm = false;
105*795d594fSAndroid Build Coastguard Worker   bool two_byte = false;
106*795d594fSAndroid Build Coastguard Worker   uint32_t displacement_size = 0;
107*795d594fSAndroid Build Coastguard Worker   uint32_t immediate_size = 0;
108*795d594fSAndroid Build Coastguard Worker   bool operand_size_prefix = false;
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker   // Prefixes.
111*795d594fSAndroid Build Coastguard Worker   while (true) {
112*795d594fSAndroid Build Coastguard Worker     bool prefix_present = false;
113*795d594fSAndroid Build Coastguard Worker     switch (opcode) {
114*795d594fSAndroid Build Coastguard Worker       // Group 3
115*795d594fSAndroid Build Coastguard Worker       case 0x66:
116*795d594fSAndroid Build Coastguard Worker         operand_size_prefix = true;
117*795d594fSAndroid Build Coastguard Worker         FALLTHROUGH_INTENDED;
118*795d594fSAndroid Build Coastguard Worker 
119*795d594fSAndroid Build Coastguard Worker       // Group 1
120*795d594fSAndroid Build Coastguard Worker       case 0xf0:
121*795d594fSAndroid Build Coastguard Worker       case 0xf2:
122*795d594fSAndroid Build Coastguard Worker       case 0xf3:
123*795d594fSAndroid Build Coastguard Worker 
124*795d594fSAndroid Build Coastguard Worker       // Group 2
125*795d594fSAndroid Build Coastguard Worker       case 0x2e:
126*795d594fSAndroid Build Coastguard Worker       case 0x36:
127*795d594fSAndroid Build Coastguard Worker       case 0x3e:
128*795d594fSAndroid Build Coastguard Worker       case 0x26:
129*795d594fSAndroid Build Coastguard Worker       case 0x64:
130*795d594fSAndroid Build Coastguard Worker       case 0x65:
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker       // Group 4
133*795d594fSAndroid Build Coastguard Worker       case 0x67:
134*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(opcode);
135*795d594fSAndroid Build Coastguard Worker         prefix_present = true;
136*795d594fSAndroid Build Coastguard Worker         break;
137*795d594fSAndroid Build Coastguard Worker     }
138*795d594fSAndroid Build Coastguard Worker     if (!prefix_present) {
139*795d594fSAndroid Build Coastguard Worker       break;
140*795d594fSAndroid Build Coastguard Worker     }
141*795d594fSAndroid Build Coastguard Worker   }
142*795d594fSAndroid Build Coastguard Worker 
143*795d594fSAndroid Build Coastguard Worker   if (x86_64 && opcode >= 0x40 && opcode <= 0x4f) {
144*795d594fSAndroid Build Coastguard Worker     FETCH_BYTE(opcode);
145*795d594fSAndroid Build Coastguard Worker   }
146*795d594fSAndroid Build Coastguard Worker 
147*795d594fSAndroid Build Coastguard Worker   if (opcode == 0x0f) {
148*795d594fSAndroid Build Coastguard Worker     // Two byte opcode
149*795d594fSAndroid Build Coastguard Worker     two_byte = true;
150*795d594fSAndroid Build Coastguard Worker     FETCH_BYTE(opcode);
151*795d594fSAndroid Build Coastguard Worker   }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker   bool unhandled_instruction = false;
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker   if (two_byte) {
156*795d594fSAndroid Build Coastguard Worker     switch (opcode) {
157*795d594fSAndroid Build Coastguard Worker       case 0x10:        // vmovsd/ss
158*795d594fSAndroid Build Coastguard Worker       case 0x11:        // vmovsd/ss
159*795d594fSAndroid Build Coastguard Worker       case 0xb6:        // movzx
160*795d594fSAndroid Build Coastguard Worker       case 0xb7:
161*795d594fSAndroid Build Coastguard Worker       case 0xbe:        // movsx
162*795d594fSAndroid Build Coastguard Worker       case 0xbf:
163*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(modrm);
164*795d594fSAndroid Build Coastguard Worker         has_modrm = true;
165*795d594fSAndroid Build Coastguard Worker         break;
166*795d594fSAndroid Build Coastguard Worker       default:
167*795d594fSAndroid Build Coastguard Worker         unhandled_instruction = true;
168*795d594fSAndroid Build Coastguard Worker         break;
169*795d594fSAndroid Build Coastguard Worker     }
170*795d594fSAndroid Build Coastguard Worker   } else {
171*795d594fSAndroid Build Coastguard Worker     switch (opcode) {
172*795d594fSAndroid Build Coastguard Worker       case 0x88:        // mov byte
173*795d594fSAndroid Build Coastguard Worker       case 0x89:        // mov
174*795d594fSAndroid Build Coastguard Worker       case 0x8b:
175*795d594fSAndroid Build Coastguard Worker       case 0x38:        // cmp with memory.
176*795d594fSAndroid Build Coastguard Worker       case 0x39:
177*795d594fSAndroid Build Coastguard Worker       case 0x3a:
178*795d594fSAndroid Build Coastguard Worker       case 0x3b:
179*795d594fSAndroid Build Coastguard Worker       case 0x3c:
180*795d594fSAndroid Build Coastguard Worker       case 0x3d:
181*795d594fSAndroid Build Coastguard Worker       case 0x85:        // test.
182*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(modrm);
183*795d594fSAndroid Build Coastguard Worker         has_modrm = true;
184*795d594fSAndroid Build Coastguard Worker         break;
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker       case 0x80:        // group 1, byte immediate.
187*795d594fSAndroid Build Coastguard Worker       case 0x83:
188*795d594fSAndroid Build Coastguard Worker       case 0xc6:
189*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(modrm);
190*795d594fSAndroid Build Coastguard Worker         has_modrm = true;
191*795d594fSAndroid Build Coastguard Worker         immediate_size = 1;
192*795d594fSAndroid Build Coastguard Worker         break;
193*795d594fSAndroid Build Coastguard Worker 
194*795d594fSAndroid Build Coastguard Worker       case 0x81:        // group 1, word immediate.
195*795d594fSAndroid Build Coastguard Worker       case 0xc7:        // mov
196*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(modrm);
197*795d594fSAndroid Build Coastguard Worker         has_modrm = true;
198*795d594fSAndroid Build Coastguard Worker         immediate_size = operand_size_prefix ? 2 : 4;
199*795d594fSAndroid Build Coastguard Worker         break;
200*795d594fSAndroid Build Coastguard Worker 
201*795d594fSAndroid Build Coastguard Worker       case 0xf6:
202*795d594fSAndroid Build Coastguard Worker       case 0xf7:
203*795d594fSAndroid Build Coastguard Worker         FETCH_BYTE(modrm);
204*795d594fSAndroid Build Coastguard Worker         has_modrm = true;
205*795d594fSAndroid Build Coastguard Worker         switch ((modrm >> 3) & 7) {  // Extract "reg/opcode" from "modr/m".
206*795d594fSAndroid Build Coastguard Worker           case 0:  // test
207*795d594fSAndroid Build Coastguard Worker             immediate_size = (opcode == 0xf6) ? 1 : (operand_size_prefix ? 2 : 4);
208*795d594fSAndroid Build Coastguard Worker             break;
209*795d594fSAndroid Build Coastguard Worker           case 2:  // not
210*795d594fSAndroid Build Coastguard Worker           case 3:  // neg
211*795d594fSAndroid Build Coastguard Worker           case 4:  // mul
212*795d594fSAndroid Build Coastguard Worker           case 5:  // imul
213*795d594fSAndroid Build Coastguard Worker           case 6:  // div
214*795d594fSAndroid Build Coastguard Worker           case 7:  // idiv
215*795d594fSAndroid Build Coastguard Worker             break;
216*795d594fSAndroid Build Coastguard Worker           default:
217*795d594fSAndroid Build Coastguard Worker             unhandled_instruction = true;
218*795d594fSAndroid Build Coastguard Worker             break;
219*795d594fSAndroid Build Coastguard Worker         }
220*795d594fSAndroid Build Coastguard Worker         break;
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker       default:
223*795d594fSAndroid Build Coastguard Worker         unhandled_instruction = true;
224*795d594fSAndroid Build Coastguard Worker         break;
225*795d594fSAndroid Build Coastguard Worker     }
226*795d594fSAndroid Build Coastguard Worker   }
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker   if (unhandled_instruction) {
229*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast<int>(opcode);
230*795d594fSAndroid Build Coastguard Worker     return 0;
231*795d594fSAndroid Build Coastguard Worker   }
232*795d594fSAndroid Build Coastguard Worker 
233*795d594fSAndroid Build Coastguard Worker   if (has_modrm) {
234*795d594fSAndroid Build Coastguard Worker     uint8_t mod = (modrm >> 6) & 3U /* 0b11 */;
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker     // Check for SIB.
237*795d594fSAndroid Build Coastguard Worker     if (mod != 3U /* 0b11 */ && (modrm & 7U /* 0b111 */) == 4) {
238*795d594fSAndroid Build Coastguard Worker       SKIP_BYTE();  // SIB
239*795d594fSAndroid Build Coastguard Worker     }
240*795d594fSAndroid Build Coastguard Worker 
241*795d594fSAndroid Build Coastguard Worker     switch (mod) {
242*795d594fSAndroid Build Coastguard Worker       case 0U /* 0b00 */: break;
243*795d594fSAndroid Build Coastguard Worker       case 1U /* 0b01 */: displacement_size = 1; break;
244*795d594fSAndroid Build Coastguard Worker       case 2U /* 0b10 */: displacement_size = 4; break;
245*795d594fSAndroid Build Coastguard Worker       case 3U /* 0b11 */:
246*795d594fSAndroid Build Coastguard Worker         break;
247*795d594fSAndroid Build Coastguard Worker     }
248*795d594fSAndroid Build Coastguard Worker   }
249*795d594fSAndroid Build Coastguard Worker 
250*795d594fSAndroid Build Coastguard Worker   // Skip displacement and immediate.
251*795d594fSAndroid Build Coastguard Worker   pc += displacement_size + immediate_size;
252*795d594fSAndroid Build Coastguard Worker 
253*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc);
254*795d594fSAndroid Build Coastguard Worker   return pc - startpc;
255*795d594fSAndroid Build Coastguard Worker 
256*795d594fSAndroid Build Coastguard Worker #undef SKIP_BYTE
257*795d594fSAndroid Build Coastguard Worker #undef FETCH_BYTE
258*795d594fSAndroid Build Coastguard Worker #undef FETCH_OR_SKIP_BYTE
259*795d594fSAndroid Build Coastguard Worker }
260*795d594fSAndroid Build Coastguard Worker 
GetFaultPc(siginfo_t * siginfo,void * context)261*795d594fSAndroid Build Coastguard Worker uintptr_t FaultManager::GetFaultPc([[maybe_unused]] siginfo_t* siginfo, void* context) {
262*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
263*795d594fSAndroid Build Coastguard Worker   if (uc->CTX_ESP == 0) {
264*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Missing SP";
265*795d594fSAndroid Build Coastguard Worker     return 0u;
266*795d594fSAndroid Build Coastguard Worker   }
267*795d594fSAndroid Build Coastguard Worker   return uc->CTX_EIP;
268*795d594fSAndroid Build Coastguard Worker }
269*795d594fSAndroid Build Coastguard Worker 
GetFaultSp(void * context)270*795d594fSAndroid Build Coastguard Worker uintptr_t FaultManager::GetFaultSp(void* context) {
271*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
272*795d594fSAndroid Build Coastguard Worker   return uc->CTX_ESP;
273*795d594fSAndroid Build Coastguard Worker }
274*795d594fSAndroid Build Coastguard Worker 
Action(int,siginfo_t * sig,void * context)275*795d594fSAndroid Build Coastguard Worker bool NullPointerHandler::Action(int, siginfo_t* sig, void* context) {
276*795d594fSAndroid Build Coastguard Worker   uintptr_t fault_address = reinterpret_cast<uintptr_t>(sig->si_addr);
277*795d594fSAndroid Build Coastguard Worker   if (!IsValidFaultAddress(fault_address)) {
278*795d594fSAndroid Build Coastguard Worker     return false;
279*795d594fSAndroid Build Coastguard Worker   }
280*795d594fSAndroid Build Coastguard Worker 
281*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
282*795d594fSAndroid Build Coastguard Worker   ArtMethod** sp = reinterpret_cast<ArtMethod**>(uc->CTX_ESP);
283*795d594fSAndroid Build Coastguard Worker   ArtMethod* method = *sp;
284*795d594fSAndroid Build Coastguard Worker   if (!IsValidMethod(method)) {
285*795d594fSAndroid Build Coastguard Worker     return false;
286*795d594fSAndroid Build Coastguard Worker   }
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker   // For null checks in compiled code we insert a stack map that is immediately
289*795d594fSAndroid Build Coastguard Worker   // after the load/store instruction that might cause the fault and we need to
290*795d594fSAndroid Build Coastguard Worker   // pass the return PC to the handler. For null checks in Nterp, we similarly
291*795d594fSAndroid Build Coastguard Worker   // need the return PC to recognize that this was a null check in Nterp, so
292*795d594fSAndroid Build Coastguard Worker   // that the handler can get the needed data from the Nterp frame.
293*795d594fSAndroid Build Coastguard Worker 
294*795d594fSAndroid Build Coastguard Worker   // Note: Allowing nested faults if `IsValidMethod()` returned a false positive.
295*795d594fSAndroid Build Coastguard Worker   // Note: The `ArtMethod::GetOatQuickMethodHeader()` can acquire locks, which is
296*795d594fSAndroid Build Coastguard Worker   // essentially unsafe in a signal handler, but we allow that here just like in
297*795d594fSAndroid Build Coastguard Worker   // `NullPointerHandler::IsValidReturnPc()`. For more details see comments there.
298*795d594fSAndroid Build Coastguard Worker   uintptr_t pc = uc->CTX_EIP;
299*795d594fSAndroid Build Coastguard Worker   const OatQuickMethodHeader* method_header = method->GetOatQuickMethodHeader(pc);
300*795d594fSAndroid Build Coastguard Worker   if (method_header == nullptr) {
301*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "No method header.";
302*795d594fSAndroid Build Coastguard Worker     return false;
303*795d594fSAndroid Build Coastguard Worker   }
304*795d594fSAndroid Build Coastguard Worker   const uint8_t* pc_ptr = reinterpret_cast<const uint8_t*>(pc);
305*795d594fSAndroid Build Coastguard Worker   size_t offset = pc_ptr - method_header->GetCode();
306*795d594fSAndroid Build Coastguard Worker   size_t code_size = method_header->GetCodeSize();
307*795d594fSAndroid Build Coastguard Worker   CHECK_LT(offset, code_size);
308*795d594fSAndroid Build Coastguard Worker   size_t max_instr_size = code_size - offset;
309*795d594fSAndroid Build Coastguard Worker   uint32_t instr_size = GetInstructionSize(pc_ptr, max_instr_size);
310*795d594fSAndroid Build Coastguard Worker   if (instr_size == 0u) {
311*795d594fSAndroid Build Coastguard Worker     // Unknown instruction (can't really happen) or not enough bytes until end of method code.
312*795d594fSAndroid Build Coastguard Worker     return false;
313*795d594fSAndroid Build Coastguard Worker   }
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker   uintptr_t return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
316*795d594fSAndroid Build Coastguard Worker   if (!IsValidReturnPc(sp, return_pc)) {
317*795d594fSAndroid Build Coastguard Worker     return false;
318*795d594fSAndroid Build Coastguard Worker   }
319*795d594fSAndroid Build Coastguard Worker 
320*795d594fSAndroid Build Coastguard Worker   // Push the return PC and fault address onto the stack.
321*795d594fSAndroid Build Coastguard Worker   uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp) - 2;
322*795d594fSAndroid Build Coastguard Worker   next_sp[1] = return_pc;
323*795d594fSAndroid Build Coastguard Worker   next_sp[0] = fault_address;
324*795d594fSAndroid Build Coastguard Worker   uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
325*795d594fSAndroid Build Coastguard Worker 
326*795d594fSAndroid Build Coastguard Worker   // Arrange for the signal handler to return to the NPE entrypoint.
327*795d594fSAndroid Build Coastguard Worker   uc->CTX_EIP = reinterpret_cast<uintptr_t>(
328*795d594fSAndroid Build Coastguard Worker       art_quick_throw_null_pointer_exception_from_signal);
329*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Generating null pointer exception";
330*795d594fSAndroid Build Coastguard Worker   return true;
331*795d594fSAndroid Build Coastguard Worker }
332*795d594fSAndroid Build Coastguard Worker 
333*795d594fSAndroid Build Coastguard Worker // A suspend check is done using the following instruction sequence:
334*795d594fSAndroid Build Coastguard Worker // (x86)
335*795d594fSAndroid Build Coastguard Worker // 0xf720f1df:         648B058C000000      mov     eax, fs:[0x8c]  ; suspend_trigger
336*795d594fSAndroid Build Coastguard Worker // .. some intervening instructions.
337*795d594fSAndroid Build Coastguard Worker // 0xf720f1e6:                   8500      test    eax, [eax]
338*795d594fSAndroid Build Coastguard Worker // (x86_64)
339*795d594fSAndroid Build Coastguard Worker // 0x7f579de45d9e: 65488B0425A8000000      movq    rax, gs:[0xa8]  ; suspend_trigger
340*795d594fSAndroid Build Coastguard Worker // .. some intervening instructions.
341*795d594fSAndroid Build Coastguard Worker // 0x7f579de45da7:               8500      test    eax, [eax]
342*795d594fSAndroid Build Coastguard Worker 
343*795d594fSAndroid Build Coastguard Worker // The offset from fs is Thread::ThreadSuspendTriggerOffset().
344*795d594fSAndroid Build Coastguard Worker // To check for a suspend check, we examine the instructions that caused
345*795d594fSAndroid Build Coastguard Worker // the fault.
Action(int,siginfo_t *,void * context)346*795d594fSAndroid Build Coastguard Worker bool SuspensionHandler::Action(int, siginfo_t*, void* context) {
347*795d594fSAndroid Build Coastguard Worker   // These are the instructions to check for.  The first one is the mov eax, fs:[xxx]
348*795d594fSAndroid Build Coastguard Worker   // where xxx is the offset of the suspend trigger.
349*795d594fSAndroid Build Coastguard Worker   uint32_t trigger = Thread::ThreadSuspendTriggerOffset<kRuntimePointerSize>().Int32Value();
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Checking for suspension point";
352*795d594fSAndroid Build Coastguard Worker #if defined(__x86_64__)
353*795d594fSAndroid Build Coastguard Worker   uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast<uint8_t>(trigger & 0xff),
354*795d594fSAndroid Build Coastguard Worker       static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
355*795d594fSAndroid Build Coastguard Worker #else
356*795d594fSAndroid Build Coastguard Worker   uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
357*795d594fSAndroid Build Coastguard Worker       static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
358*795d594fSAndroid Build Coastguard Worker #endif
359*795d594fSAndroid Build Coastguard Worker   uint8_t checkinst2[] = {0x85, 0x00};
360*795d594fSAndroid Build Coastguard Worker 
361*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
362*795d594fSAndroid Build Coastguard Worker   uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
363*795d594fSAndroid Build Coastguard Worker   uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
364*795d594fSAndroid Build Coastguard Worker 
365*795d594fSAndroid Build Coastguard Worker   if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) {
366*795d594fSAndroid Build Coastguard Worker     // Second instruction is not correct (test eax,[eax]).
367*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Not a suspension point";
368*795d594fSAndroid Build Coastguard Worker     return false;
369*795d594fSAndroid Build Coastguard Worker   }
370*795d594fSAndroid Build Coastguard Worker 
371*795d594fSAndroid Build Coastguard Worker   // The first instruction can a little bit up the stream due to load hoisting
372*795d594fSAndroid Build Coastguard Worker   // in the compiler.
373*795d594fSAndroid Build Coastguard Worker   uint8_t* limit = pc - 100;   // Compiler will hoist to a max of 20 instructions.
374*795d594fSAndroid Build Coastguard Worker   uint8_t* ptr = pc - sizeof(checkinst1);
375*795d594fSAndroid Build Coastguard Worker   bool found = false;
376*795d594fSAndroid Build Coastguard Worker   while (ptr > limit) {
377*795d594fSAndroid Build Coastguard Worker     if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) {
378*795d594fSAndroid Build Coastguard Worker       found = true;
379*795d594fSAndroid Build Coastguard Worker       break;
380*795d594fSAndroid Build Coastguard Worker     }
381*795d594fSAndroid Build Coastguard Worker     ptr -= 1;
382*795d594fSAndroid Build Coastguard Worker   }
383*795d594fSAndroid Build Coastguard Worker 
384*795d594fSAndroid Build Coastguard Worker   if (found) {
385*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "suspend check match";
386*795d594fSAndroid Build Coastguard Worker 
387*795d594fSAndroid Build Coastguard Worker     // We need to arrange for the signal handler to return to the null pointer
388*795d594fSAndroid Build Coastguard Worker     // exception generator.  The return address must be the address of the
389*795d594fSAndroid Build Coastguard Worker     // next instruction (this instruction + 2).  The return address
390*795d594fSAndroid Build Coastguard Worker     // is on the stack at the top address of the current frame.
391*795d594fSAndroid Build Coastguard Worker 
392*795d594fSAndroid Build Coastguard Worker     // Push the return address onto the stack.
393*795d594fSAndroid Build Coastguard Worker     uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + 2);
394*795d594fSAndroid Build Coastguard Worker     uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
395*795d594fSAndroid Build Coastguard Worker     *next_sp = retaddr;
396*795d594fSAndroid Build Coastguard Worker     uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
397*795d594fSAndroid Build Coastguard Worker 
398*795d594fSAndroid Build Coastguard Worker     uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_test_suspend);
399*795d594fSAndroid Build Coastguard Worker 
400*795d594fSAndroid Build Coastguard Worker     // Now remove the suspend trigger that caused this fault.
401*795d594fSAndroid Build Coastguard Worker     Thread::Current()->RemoveSuspendTrigger();
402*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "removed suspend trigger invoking test suspend";
403*795d594fSAndroid Build Coastguard Worker     return true;
404*795d594fSAndroid Build Coastguard Worker   }
405*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Not a suspend check match, first instruction mismatch";
406*795d594fSAndroid Build Coastguard Worker   return false;
407*795d594fSAndroid Build Coastguard Worker }
408*795d594fSAndroid Build Coastguard Worker 
409*795d594fSAndroid Build Coastguard Worker // The stack overflow check is done using the following instruction:
410*795d594fSAndroid Build Coastguard Worker // test eax, [esp+ -xxx]
411*795d594fSAndroid Build Coastguard Worker // where 'xxx' is the size of the overflow area.
412*795d594fSAndroid Build Coastguard Worker //
413*795d594fSAndroid Build Coastguard Worker // This is done before any frame is established in the method.  The return
414*795d594fSAndroid Build Coastguard Worker // address for the previous method is on the stack at ESP.
415*795d594fSAndroid Build Coastguard Worker 
Action(int,siginfo_t * info,void * context)416*795d594fSAndroid Build Coastguard Worker bool StackOverflowHandler::Action(int, siginfo_t* info, void* context) {
417*795d594fSAndroid Build Coastguard Worker   ucontext_t* uc = reinterpret_cast<ucontext_t*>(context);
418*795d594fSAndroid Build Coastguard Worker   uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP);
419*795d594fSAndroid Build Coastguard Worker 
420*795d594fSAndroid Build Coastguard Worker   uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
421*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
422*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
423*795d594fSAndroid Build Coastguard Worker     ", fault_addr: " << fault_addr;
424*795d594fSAndroid Build Coastguard Worker 
425*795d594fSAndroid Build Coastguard Worker #if defined(__x86_64__)
426*795d594fSAndroid Build Coastguard Worker   uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(InstructionSet::kX86_64);
427*795d594fSAndroid Build Coastguard Worker #else
428*795d594fSAndroid Build Coastguard Worker   uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(InstructionSet::kX86);
429*795d594fSAndroid Build Coastguard Worker #endif
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker   // Check that the fault address is the value expected for a stack overflow.
432*795d594fSAndroid Build Coastguard Worker   if (fault_addr != overflow_addr) {
433*795d594fSAndroid Build Coastguard Worker     VLOG(signals) << "Not a stack overflow";
434*795d594fSAndroid Build Coastguard Worker     return false;
435*795d594fSAndroid Build Coastguard Worker   }
436*795d594fSAndroid Build Coastguard Worker 
437*795d594fSAndroid Build Coastguard Worker   VLOG(signals) << "Stack overflow found";
438*795d594fSAndroid Build Coastguard Worker 
439*795d594fSAndroid Build Coastguard Worker   // Since the compiler puts the implicit overflow
440*795d594fSAndroid Build Coastguard Worker   // check before the callee save instructions, the SP is already pointing to
441*795d594fSAndroid Build Coastguard Worker   // the previous frame.
442*795d594fSAndroid Build Coastguard Worker 
443*795d594fSAndroid Build Coastguard Worker   // Now arrange for the signal handler to return to art_quick_throw_stack_overflow.
444*795d594fSAndroid Build Coastguard Worker   uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_quick_throw_stack_overflow);
445*795d594fSAndroid Build Coastguard Worker 
446*795d594fSAndroid Build Coastguard Worker   return true;
447*795d594fSAndroid Build Coastguard Worker }
448*795d594fSAndroid Build Coastguard Worker }       // namespace art
449