From dfd3b47813c14c5f1607cbe7b10a28b1b2f29cbc Mon Sep 17 00:00:00 2001 From: Dave Allison Date: Wed, 16 Jul 2014 16:04:32 -0700 Subject: [PATCH] Add implicit checks for x86_64 architecture. This combines the x86 and x86_64 fault handlers into one. It also merges in the change to the entrypoints for X86_64. Replaces generic instruction length calculator with one that only works with the specific instructions we use. Bug: 16256184 Change-Id: I1e8ab5ad43f46060de9597615b423c89a836035c Signed-off-by: Chao-ying Fu --- compiler/dex/quick/x86/target_x86.cc | 24 ++- dex2oat/dex2oat.cc | 1 + runtime/Android.mk | 4 +- runtime/arch/arm/fault_handler_arm.cc | 2 +- runtime/arch/arm64/fault_handler_arm64.cc | 2 +- runtime/arch/mips/fault_handler_mips.cc | 2 +- runtime/arch/x86/fault_handler_x86.cc | 266 +++++++++++++++---------- runtime/arch/x86_64/fault_handler_x86_64.cc | 48 ----- runtime/arch/x86_64/quick_entrypoints_x86_64.S | 12 ++ runtime/fault_handler.cc | 6 +- runtime/fault_handler.h | 10 +- runtime/runtime.cc | 1 + runtime/thread_linux.cc | 13 +- 13 files changed, 217 insertions(+), 174 deletions(-) delete mode 100644 runtime/arch/x86_64/fault_handler_x86_64.cc diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 69f3e6751..b78b90cc7 100755 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -880,9 +880,13 @@ RegStorage X86Mir2Lir::LoadHelper(QuickEntrypointEnum trampoline) { LIR* X86Mir2Lir::CheckSuspendUsingLoad() { // First load the pointer in fs:[suspend-trigger] into eax // Then use a test instruction to indirect via that address. - NewLIR2(kX86Mov32RT, rs_rAX.GetReg(), cu_->target64 ? - Thread::ThreadSuspendTriggerOffset<8>().Int32Value() : - Thread::ThreadSuspendTriggerOffset<4>().Int32Value()); + if (cu_->target64) { + NewLIR2(kX86Mov64RT, rs_rAX.GetReg(), + Thread::ThreadSuspendTriggerOffset<8>().Int32Value()); + } else { + NewLIR2(kX86Mov32RT, rs_rAX.GetReg(), + Thread::ThreadSuspendTriggerOffset<4>().Int32Value()); + } return NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rAX.GetReg(), 0); } @@ -1293,14 +1297,14 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { // Compute the number of words to search in to rCX. Load32Disp(rs_rDX, count_offset, rs_rCX); - if (!cu_->target64) { - // Possible signal here due to null pointer dereference. - // Note that the signal handler will expect the top word of - // the stack to be the ArtMethod*. If the PUSH edi instruction - // below is ahead of the load above then this will not be true - // and the signal handler will not work. - MarkPossibleNullPointerException(0); + // Possible signal here due to null pointer dereference. + // Note that the signal handler will expect the top word of + // the stack to be the ArtMethod*. If the PUSH edi instruction + // below is ahead of the load above then this will not be true + // and the signal handler will not work. + MarkPossibleNullPointerException(0); + if (!cu_->target64) { // EDI is callee-save register in 32-bit mode. NewLIR1(kX86Push32R, rs_rDI.GetReg()); } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index ac3eb3981..bb86a74b3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1169,6 +1169,7 @@ static int dex2oat(int argc, char** argv) { case kThumb2: case kArm64: case kX86: + case kX86_64: implicit_null_checks = true; implicit_so_checks = true; break; diff --git a/runtime/Android.mk b/runtime/Android.mk index 302e835e7..09ec00406 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -248,6 +248,8 @@ LIBART_SRC_FILES_x86 := \ LIBART_TARGET_SRC_FILES_x86 := \ $(LIBART_SRC_FILES_x86) +# Note that the fault_handler_x86.cc is not a mistake. This file is +# shared between the x86 and x86_64 architectures. LIBART_SRC_FILES_x86_64 := \ arch/x86_64/context_x86_64.cc \ arch/x86_64/entrypoints_init_x86_64.cc \ @@ -257,7 +259,7 @@ LIBART_SRC_FILES_x86_64 := \ arch/x86_64/quick_entrypoints_x86_64.S \ arch/x86_64/thread_x86_64.cc \ monitor_pool.cc \ - arch/x86_64/fault_handler_x86_64.cc + arch/x86/fault_handler_x86.cc LIBART_TARGET_SRC_FILES_x86_64 := \ $(LIBART_SRC_FILES_x86_64) \ diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc index 48582f464..be28544af 100644 --- a/runtime/arch/arm/fault_handler_arm.cc +++ b/runtime/arch/arm/fault_handler_arm.cc @@ -46,7 +46,7 @@ static uint32_t GetInstructionSize(uint8_t* pc) { return instr_size; } -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, +void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { struct ucontext* uc = reinterpret_cast(context); diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc index dc82cc2d9..3a7e6896a 100644 --- a/runtime/arch/arm64/fault_handler_arm64.cc +++ b/runtime/arch/arm64/fault_handler_arm64.cc @@ -37,7 +37,7 @@ extern "C" void art_quick_implicit_suspend(); namespace art { -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, +void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { struct ucontext *uc = reinterpret_cast(context); diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc index 5a64a698f..0e76aabbc 100644 --- a/runtime/arch/mips/fault_handler_mips.cc +++ b/runtime/arch/mips/fault_handler_mips.cc @@ -29,7 +29,7 @@ namespace art { -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, +void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { } diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc index 435f280a6..8b6c9b1ae 100644 --- a/runtime/arch/x86/fault_handler_x86.cc +++ b/runtime/arch/x86/fault_handler_x86.cc @@ -31,14 +31,21 @@ #define CTX_ESP uc_mcontext->__ss.__esp #define CTX_EIP uc_mcontext->__ss.__eip #define CTX_EAX uc_mcontext->__ss.__eax +#define CTX_METHOD uc_mcontext->__ss.__eax +#elif defined(__x86_64__) +#define CTX_ESP uc_mcontext.gregs[REG_RSP] +#define CTX_EIP uc_mcontext.gregs[REG_RIP] +#define CTX_EAX uc_mcontext.gregs[REG_RAX] +#define CTX_METHOD uc_mcontext.gregs[REG_RDI] #else #define CTX_ESP uc_mcontext.gregs[REG_ESP] #define CTX_EIP uc_mcontext.gregs[REG_EIP] #define CTX_EAX uc_mcontext.gregs[REG_EAX] +#define CTX_METHOD uc_mcontext.gregs[REG_EAX] #endif // -// X86 specific fault handler functions. +// X86 (and X86_64) specific fault handler functions. // namespace art { @@ -47,129 +54,146 @@ extern "C" void art_quick_throw_null_pointer_exception(); extern "C" void art_quick_throw_stack_overflow_from_signal(); extern "C" void art_quick_test_suspend(); -// From the x86 disassembler... -enum SegmentPrefix { - kCs = 0x2e, - kSs = 0x36, - kDs = 0x3e, - kEs = 0x26, - kFs = 0x64, - kGs = 0x65, -}; - // Get the size of an instruction in bytes. -static uint32_t GetInstructionSize(uint8_t* pc) { - uint8_t* instruction_start = pc; - bool have_prefixes = true; - bool two_byte = false; +// Return 0 if the instruction is not handled. +static uint32_t GetInstructionSize(const uint8_t* pc) { +#if defined(__x86_64) + const bool x86_64 = true; +#else + const bool x86_64 = false; +#endif - // Skip all the prefixes. - do { - switch (*pc) { - // Group 1 - lock and repeat prefixes: - case 0xF0: - case 0xF2: - case 0xF3: - // Group 2 - segment override prefixes: - case kCs: - case kSs: - case kDs: - case kEs: - case kFs: - case kGs: - // Group 3 - operand size override: + const uint8_t* startpc = pc; + + uint8_t opcode = *pc++; + uint8_t modrm; + bool has_modrm = false; + bool two_byte = false; + uint32_t displacement_size = 0; + uint32_t immediate_size = 0; + + // Prefixes. + while (true) { + bool prefix_present = false; + switch (opcode) { + // Group 1 + case 0xf0: + case 0xf2: + case 0xf3: + + // Group 2 + case 0x2e: + case 0x36: + case 0x3e: + case 0x26: + case 0x64: + case 0x65: + + // Group 3 case 0x66: - // Group 4 - address size override: + + // Group 4 case 0x67: - break; - default: - have_prefixes = false; + opcode = *pc++; + prefix_present = true; break; } - if (have_prefixes) { - pc++; + if (!prefix_present) { + break; } - } while (have_prefixes); - -#if defined(__x86_64__) - // Skip REX is present. - if (*pc >= 0x40 && *pc <= 0x4F) { - ++pc; - } -#endif - - // Check for known instructions. - uint32_t known_length = 0; - switch (*pc) { - case 0x83: // cmp [r + v], b: 4 byte instruction - known_length = 4; - break; } - if (known_length > 0) { - VLOG(signals) << "known instruction with length " << known_length; - return known_length; + if (x86_64 && opcode >= 0x40 && opcode <= 0x4f) { + opcode = *pc++; } - // Unknown instruction, work out length. - - // Work out if we have a ModR/M byte. - uint8_t opcode = *pc++; - if (opcode == 0xf) { + if (opcode == 0x0f) { + // Two byte opcode two_byte = true; opcode = *pc++; } - bool has_modrm = false; // Is ModR/M byte present? - uint8_t hi = opcode >> 4; // Opcode high nybble. - uint8_t lo = opcode & 0b1111; // Opcode low nybble. + bool unhandled_instruction = false; - // From the Intel opcode tables. if (two_byte) { - has_modrm = true; // TODO: all of these? - } else if (hi < 4) { - has_modrm = lo < 4 || (lo >= 8 && lo <= 0xb); - } else if (hi == 6) { - has_modrm = lo == 3 || lo == 9 || lo == 0xb; - } else if (hi == 8) { - has_modrm = lo != 0xd; - } else if (hi == 0xc) { - has_modrm = lo == 1 || lo == 2 || lo == 6 || lo == 7; - } else if (hi == 0xd) { - has_modrm = lo < 4; - } else if (hi == 0xf) { - has_modrm = lo == 6 || lo == 7; + switch (opcode) { + case 0x10: // vmovsd/ss + case 0x11: // vmovsd/ss + case 0xb6: // movzx + case 0xb7: + case 0xbe: // movsx + case 0xbf: + modrm = *pc++; + has_modrm = true; + break; + default: + unhandled_instruction = true; + break; + } + } else { + switch (opcode) { + case 0x89: // mov + case 0x8b: + case 0x38: // cmp with memory. + case 0x39: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x85: // test. + modrm = *pc++; + has_modrm = true; + break; + + case 0x80: // group 1, byte immediate. + case 0x83: + modrm = *pc++; + has_modrm = true; + immediate_size = 1; + break; + + case 0x81: // group 1, word immediate. + modrm = *pc++; + has_modrm = true; + immediate_size = 4; + break; + + default: + unhandled_instruction = true; + break; + } + } + + if (unhandled_instruction) { + VLOG(signals) << "Unhandled x86 instruction with opcode " << static_cast(opcode); + return 0; } if (has_modrm) { - uint8_t modrm = *pc++; uint8_t mod = (modrm >> 6) & 0b11; - uint8_t reg = (modrm >> 3) & 0b111; + + // Check for SIB. + if (mod != 0b11 && (modrm & 0b111) == 4) { + ++pc; // SIB + } + switch (mod) { - case 0: - break; - case 1: - if (reg == 4) { - // SIB + 1 byte displacement. - pc += 2; - } else { - pc += 1; - } - break; - case 2: - // SIB + 4 byte displacement. - pc += 5; - break; - case 3: + case 0b00: break; + case 0b01: displacement_size = 1; break; + case 0b10: displacement_size = 4; break; + case 0b11: break; } } - VLOG(signals) << "calculated X86 instruction size is " << (pc - instruction_start); - return pc - instruction_start; + // Skip displacement and immediate. + pc += displacement_size + immediate_size; + + VLOG(signals) << "x86 instruction length calculated as " << (pc - startpc); + return pc - startpc; } -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, +void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { struct ucontext* uc = reinterpret_cast(context); @@ -180,21 +204,30 @@ void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, } // In the case of a stack overflow, the stack is not valid and we can't - // get the method from the top of the stack. However it's in EAX. + // get the method from the top of the stack. However it's in EAX(x86)/RDI(x86_64). uintptr_t* fault_addr = reinterpret_cast(siginfo->si_addr); uintptr_t* overflow_addr = reinterpret_cast( +#if defined(__x86_64__) + reinterpret_cast(*out_sp) - GetStackOverflowReservedBytes(kX86_64)); +#else reinterpret_cast(*out_sp) - GetStackOverflowReservedBytes(kX86)); +#endif if (overflow_addr == fault_addr) { - *out_method = reinterpret_cast(uc->CTX_EAX); + *out_method = reinterpret_cast(uc->CTX_METHOD); } else { // The method is at the top of the stack. - *out_method = reinterpret_cast(reinterpret_cast(*out_sp)[0]); + *out_method = (reinterpret_cast* >(*out_sp)[0]).AsMirrorPtr(); } uint8_t* pc = reinterpret_cast(uc->CTX_EIP); VLOG(signals) << HexDump(pc, 32, true, "PC "); uint32_t instr_size = GetInstructionSize(pc); + if (instr_size == 0) { + // Unknown instruction, tell caller it's not ours. + *out_method = nullptr; + return; + } *out_return_pc = reinterpret_cast(pc + instr_size); } @@ -204,16 +237,21 @@ bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { uint8_t* sp = reinterpret_cast(uc->CTX_ESP); uint32_t instr_size = GetInstructionSize(pc); + if (instr_size == 0) { + // Unknown instruction, can't really happen. + return false; + } + // We need to arrange for the signal handler to return to the null pointer // exception generator. The return address must be the address of the // next instruction (this instruction + instruction size). The return address // is on the stack at the top address of the current frame. // Push the return address onto the stack. - uint32_t retaddr = reinterpret_cast(pc + instr_size); - uint32_t* next_sp = reinterpret_cast(sp - 4); + uintptr_t retaddr = reinterpret_cast(pc + instr_size); + uintptr_t* next_sp = reinterpret_cast(sp - sizeof(uintptr_t)); *next_sp = retaddr; - uc->CTX_ESP = reinterpret_cast(next_sp); + uc->CTX_ESP = reinterpret_cast(next_sp); uc->CTX_EIP = reinterpret_cast(art_quick_throw_null_pointer_exception); VLOG(signals) << "Generating null pointer exception"; @@ -221,9 +259,14 @@ bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { } // A suspend check is done using the following instruction sequence: +// (x86) // 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger // .. some intervening instructions. // 0xf720f1e6: 8500 test eax, [eax] +// (x86_64) +// 0x7f579de45d9e: 65488B0425A8000000 movq rax, gs:[0xa8] ; suspend_trigger +// .. some intervening instructions. +// 0x7f579de45da7: 8500 test eax, [eax] // The offset from fs is Thread::ThreadSuspendTriggerOffset(). // To check for a suspend check, we examine the instructions that caused @@ -231,11 +274,20 @@ bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { // These are the instructions to check for. The first one is the mov eax, fs:[xxx] // where xxx is the offset of the suspend trigger. +#if defined(__x86_64__) + uint32_t trigger = Thread::ThreadSuspendTriggerOffset<8>().Int32Value(); +#else uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value(); +#endif VLOG(signals) << "Checking for suspension point"; +#if defined(__x86_64__) + uint8_t checkinst1[] = {0x65, 0x48, 0x8b, 0x04, 0x25, static_cast(trigger & 0xff), + static_cast((trigger >> 8) & 0xff), 0, 0}; +#else uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast(trigger & 0xff), static_cast((trigger >> 8) & 0xff), 0, 0}; +#endif uint8_t checkinst2[] = {0x85, 0x00}; struct ucontext *uc = reinterpret_cast(context); @@ -270,10 +322,10 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { // is on the stack at the top address of the current frame. // Push the return address onto the stack. - uint32_t retaddr = reinterpret_cast(pc + 2); - uint32_t* next_sp = reinterpret_cast(sp - 4); + uintptr_t retaddr = reinterpret_cast(pc + 2); + uintptr_t* next_sp = reinterpret_cast(sp - sizeof(uintptr_t)); *next_sp = retaddr; - uc->CTX_ESP = reinterpret_cast(next_sp); + uc->CTX_ESP = reinterpret_cast(next_sp); uc->CTX_EIP = reinterpret_cast(art_quick_test_suspend); @@ -302,7 +354,11 @@ bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp << ", fault_addr: " << fault_addr; +#if defined(__x86_64__) + uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86_64); +#else uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86); +#endif Thread* self = Thread::Current(); uintptr_t pregion = reinterpret_cast(self->GetStackEnd()) - diff --git a/runtime/arch/x86_64/fault_handler_x86_64.cc b/runtime/arch/x86_64/fault_handler_x86_64.cc deleted file mode 100644 index 88ae7f371..000000000 --- a/runtime/arch/x86_64/fault_handler_x86_64.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -#include "fault_handler.h" -#include -#include "base/macros.h" -#include "globals.h" -#include "base/logging.h" -#include "base/hex_dump.h" - - -// -// X86_64 specific fault handler functions. -// - -namespace art { - -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, - uintptr_t* out_return_pc, uintptr_t* out_sp) { -} - -bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { - return false; -} - -bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { - return false; -} - -bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { - return false; -} -} // namespace art diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index 48bc240da..f021ada6b 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -284,6 +284,18 @@ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode */ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode +// On entry to this function, RAX contains the ESP value for the overflow region. +DEFINE_FUNCTION art_quick_throw_stack_overflow_from_signal + // Here, the RSP is above the protected region. We need to create a + // callee save frame and then move RSP down to the overflow region. + SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context + mov %rsp, %rsi // get current stack pointer, pass SP as second arg + mov %rax, %rsp // move RSP to the overflow region. + mov %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current() as first arg + call PLT_SYMBOL(artThrowStackOverflowFromCode) // artThrowStackOverflowFromCode(Thread*, SP) + int3 // unreached +END_FUNCTION art_quick_throw_stack_overflow_from_signal + /* * Called by managed code, saves callee saves and then calls artThrowException * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index 1b916284c..8ddaf5cf2 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -76,6 +76,7 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { // Also, there is only an 8K stack available here to logging can cause memory // overwrite issues if you are unlucky. If you want to enable logging and // are getting crashes, allocate more space for the alternate signal stack. + VLOG(signals) << "Handling fault"; if (IsInGeneratedCode(info, context, true)) { VLOG(signals) << "in generated code, looking for handler"; @@ -91,6 +92,7 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { return; } } + art_sigsegv_fault(); // Pass this on to the next handler in the chain, or the default if none. @@ -150,7 +152,7 @@ bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool che // Get the architecture specific method address and return address. These // are in architecture specific files in arch//fault_handler_. - GetMethodAndReturnPCAndSP(siginfo, context, &method_obj, &return_pc, &sp); + GetMethodAndReturnPcAndSp(siginfo, context, &method_obj, &return_pc, &sp); // If we don't have a potential method, we're outta here. VLOG(signals) << "potential method: " << method_obj; @@ -236,7 +238,7 @@ bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) { mirror::ArtMethod* method = nullptr; uintptr_t return_pc = 0; uintptr_t sp = 0; - manager_->GetMethodAndReturnPCAndSP(siginfo, context, &method, &return_pc, &sp); + manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp); Thread* self = Thread::Current(); // Inside of generated code, sp[0] is the method, so sp is the frame. StackReference* frame = diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h index 71c99771c..1acd0247e 100644 --- a/runtime/fault_handler.h +++ b/runtime/fault_handler.h @@ -43,8 +43,14 @@ class FaultManager { void HandleFault(int sig, siginfo_t* info, void* context); void AddHandler(FaultHandler* handler, bool generated_code); void RemoveHandler(FaultHandler* handler); - void GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, - uintptr_t* out_return_pc, uintptr_t* out_sp); + + // Note that the following two functions are called in the context of a signal handler. + // The IsInGeneratedCode() function checks that the mutator lock is held before it + // calls GetMethodAndReturnPCAndSP(). + // TODO: think about adding lock assertions and fake lock and unlock functions. + void GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, + uintptr_t* out_return_pc, uintptr_t* out_sp) + NO_THREAD_SAFETY_ANALYSIS; bool IsInGeneratedCode(siginfo_t* siginfo, void *context, bool check_dex_pc) NO_THREAD_SAFETY_ANALYSIS; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index fe877d5a5..e0c0d63ef 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -621,6 +621,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) case kThumb2: case kX86: case kArm64: + case kX86_64: implicit_null_checks_ = true; implicit_so_checks_ = true; break; diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc index ee66ccc29..9aacb301e 100644 --- a/runtime/thread_linux.cc +++ b/runtime/thread_linux.cc @@ -32,11 +32,18 @@ static void SigAltStack(stack_t* new_stack, stack_t* old_stack) { } } +// The default SIGSTKSZ on linux is 8K. If we do any logging in a signal +// handler this is too small. We allocate 16K instead. +static constexpr int kHostAltSigStackSize = 16*1024; // 16K signal stack. + void Thread::SetUpAlternateSignalStack() { // Create and set an alternate signal stack. +#ifdef HAVE_ANDROID_OS + LOG(FATAL) << "Invalid use of alternate signal stack on Android"; +#endif stack_t ss; - ss.ss_sp = new uint8_t[SIGSTKSZ]; - ss.ss_size = SIGSTKSZ; + ss.ss_sp = new uint8_t[kHostAltSigStackSize]; + ss.ss_size = kHostAltSigStackSize; ss.ss_flags = 0; CHECK(ss.ss_sp != NULL); SigAltStack(&ss, NULL); @@ -56,7 +63,7 @@ void Thread::TearDownAlternateSignalStack() { // Tell the kernel to stop using it. ss.ss_sp = NULL; ss.ss_flags = SS_DISABLE; - ss.ss_size = SIGSTKSZ; // Avoid ENOMEM failure with Mac OS' buggy libc. + ss.ss_size = kHostAltSigStackSize; // Avoid ENOMEM failure with Mac OS' buggy libc. SigAltStack(&ss, NULL); // Free it. -- 2.11.0