summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-07-10 01:54:57 +0000
committerDave Allison <dallison@google.com>2014-07-10 01:54:57 +0000
commit3d14eb620716e92c21c4d2c2d11a95be53319791 (patch)
treeaadce4d6bb70e549b74b537c6f75617cf533576a /runtime
parent34e826ccc80dc1cf7c4c045de6b7f8360d504ccf (diff)
downloadart-3d14eb620716e92c21c4d2c2d11a95be53319791.zip
art-3d14eb620716e92c21c4d2c2d11a95be53319791.tar.gz
art-3d14eb620716e92c21c4d2c2d11a95be53319791.tar.bz2
Revert "Add implicit null and stack checks for x86"
It breaks cross compilation with x86_64. This reverts commit 34e826ccc80dc1cf7c4c045de6b7f8360d504ccf. Change-Id: I34ba07821fc0a022fda33a7ae21850957bbec5e7
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc11
-rw-r--r--runtime/arch/arm64/fault_handler_arm64.cc3
-rw-r--r--runtime/arch/mips/fault_handler_mips.cc3
-rw-r--r--runtime/arch/x86/fault_handler_x86.cc285
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S15
-rw-r--r--runtime/arch/x86_64/fault_handler_x86_64.cc3
-rw-r--r--runtime/fault_handler.cc31
-rw-r--r--runtime/fault_handler.h5
-rw-r--r--runtime/parsed_options.cc5
-rw-r--r--runtime/runtime.cc61
-rw-r--r--runtime/thread.cc90
-rw-r--r--runtime/thread_linux.cc6
13 files changed, 81 insertions, 438 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 3774b32..7f5cf0c 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -412,7 +412,6 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT
LOCAL_STATIC_LIBRARIES := libziparchive libz
else # host
LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
- LOCAL_SHARED_LIBRARIES += libsigchain
LOCAL_LDLIBS += -ldl -lpthread
ifeq ($$(HOST_OS),linux)
LOCAL_LDLIBS += -lrt
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index e22c56e..2a82129 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -46,10 +46,9 @@ static uint32_t GetInstructionSize(uint8_t* pc) {
return instr_size;
}
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
- mirror::ArtMethod** out_method,
+void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
- struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+ struct ucontext *uc = (struct ucontext *)context;
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
*out_sp = static_cast<uintptr_t>(sc->arm_sp);
VLOG(signals) << "sp: " << *out_sp;
@@ -115,7 +114,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
uint32_t checkinst1 = 0xf8d90000 + Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
uint16_t checkinst2 = 0x6800;
- struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+ struct ucontext *uc = (struct ucontext *)context;
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->arm_pc);
uint8_t* ptr1 = ptr2 - 4;
@@ -179,7 +178,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) {
// to the overflow region below the protected region.
bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
- struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+ struct ucontext *uc = (struct ucontext *)context;
struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
VLOG(signals) << "sigcontext: " << std::hex << sc;
@@ -206,7 +205,7 @@ bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
}
// We know this is a stack overflow. We need to move the sp to the overflow region
- // that exists below the protected region. Determine the address of the next
+ // the exists below the protected region. Determine the address of the next
// available valid address below the protected region.
uintptr_t prevsp = sp;
sp = pregion;
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index 34eede6..74c3023 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -29,8 +29,7 @@
namespace art {
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
- mirror::ArtMethod** out_method,
+void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
}
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 5a64a69..1ecd7d9 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -29,8 +29,7 @@
namespace art {
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
- mirror::ArtMethod** out_method,
+void FaultManager::GetMethodAndReturnPCAndSP(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 f62200a..7c1980e 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -21,10 +21,6 @@
#include "globals.h"
#include "base/logging.h"
#include "base/hex_dump.h"
-#include "mirror/art_method.h"
-#include "mirror/art_method-inl.h"
-#include "thread.h"
-#include "thread-inl.h"
//
@@ -33,294 +29,19 @@
namespace art {
-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;
-
- // 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:
- case 0x66:
- // Group 4 - address size override:
- case 0x67:
- break;
- default:
- have_prefixes = false;
- break;
- }
- if (have_prefixes) {
- pc++;
- }
- } 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;
- }
-
- // Unknown instruction, work out length.
-
- // Work out if we have a ModR/M byte.
- uint8_t opcode = *pc++;
- if (opcode == 0xf) {
- 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.
-
- // 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;
- }
-
- if (has_modrm) {
- uint8_t modrm = *pc++;
- uint8_t mod = (modrm >> 6) & 0b11;
- uint8_t reg = (modrm >> 3) & 0b111;
- 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:
- break;
- }
- }
-
- VLOG(signals) << "calculated X86 instruction size is " << (pc - instruction_start);
- return pc - instruction_start;
-}
-
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
- mirror::ArtMethod** out_method,
+void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
- struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
- *out_sp = static_cast<uintptr_t>(uc->uc_mcontext.gregs[REG_ESP]);
- VLOG(signals) << "sp: " << std::hex << *out_sp;
- if (*out_sp == 0) {
- return;
- }
-
- // 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.
- uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr);
- uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>(
- reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86));
- if (overflow_addr == fault_addr) {
- *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->uc_mcontext.gregs[REG_EAX]);
- } else {
- // The method is at the top of the stack.
- *out_method = reinterpret_cast<mirror::ArtMethod*>(reinterpret_cast<uintptr_t*>(*out_sp)[0]);
- }
-
- uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]);
- VLOG(signals) << HexDump(pc, 32, true, "PC ");
-
- uint32_t instr_size = GetInstructionSize(pc);
- *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size);
}
bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) {
- struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
- uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]);
- uint8_t* sp = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_ESP]);
-
- uint32_t instr_size = GetInstructionSize(pc);
- // 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<uint32_t>(pc + instr_size);
- uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4);
- *next_sp = retaddr;
- uc->uc_mcontext.gregs[REG_ESP] = reinterpret_cast<uint32_t>(next_sp);
-
- uc->uc_mcontext.gregs[REG_EIP] =
- reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception);
- VLOG(signals) << "Generating null pointer exception";
- return true;
+ return false;
}
-// A suspend check is done using the following instruction sequence:
-// 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger
-// .. some intervening instructions.
-// 0xf720f1e6: 8500 test eax, [eax]
-
-// The offset from fs is Thread::ThreadSuspendTriggerOffset().
-// To check for a suspend check, we examine the instructions that caused
-// the fault.
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.
- uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value();
-
- VLOG(signals) << "Checking for suspension point";
- uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff),
- static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0};
- uint8_t checkinst2[] = {0x85, 0x00};
-
- struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
- uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]);
- uint8_t* sp = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_ESP]);
-
- if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) {
- // Second instruction is not correct (test eax,[eax]).
- VLOG(signals) << "Not a suspension point";
- return false;
- }
-
- // The first instruction can a little bit up the stream due to load hoisting
- // in the compiler.
- uint8_t* limit = pc - 100; // Compiler will hoist to a max of 20 instructions.
- uint8_t* ptr = pc - sizeof(checkinst1);
- bool found = false;
- while (ptr > limit) {
- if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) {
- found = true;
- break;
- }
- ptr -= 1;
- }
-
- if (found) {
- VLOG(signals) << "suspend check match";
-
- // 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 + 2). 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<uint32_t>(pc + 2);
- uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4);
- *next_sp = retaddr;
- uc->uc_mcontext.gregs[REG_ESP] = reinterpret_cast<uint32_t>(next_sp);
-
- uc->uc_mcontext.gregs[REG_EIP] = reinterpret_cast<uintptr_t>(art_quick_test_suspend);
-
- // Now remove the suspend trigger that caused this fault.
- Thread::Current()->RemoveSuspendTrigger();
- VLOG(signals) << "removed suspend trigger invoking test suspend";
- return true;
- }
- VLOG(signals) << "Not a suspend check match, first instruction mismatch";
return false;
}
-// The stack overflow check is done using the following instruction:
-// test eax, [esp+ -xxx]
-// where 'xxx' is the size of the overflow area.
-//
-// This is done before any frame is established in the method. The return
-// address for the previous method is on the stack at ESP.
-
bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) {
- struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
- uintptr_t sp = static_cast<uintptr_t>(uc->uc_mcontext.gregs[REG_ESP]);
-
- uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
- VLOG(signals) << "fault_addr: " << std::hex << fault_addr;
- VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp <<
- ", fault_addr: " << fault_addr;
-
- uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86);
-
- Thread* self = Thread::Current();
- uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) -
- Thread::kStackOverflowProtectedSize;
-
- // Check that the fault address is the value expected for a stack overflow.
- if (fault_addr != overflow_addr) {
- VLOG(signals) << "Not a stack overflow";
- return false;
- }
-
- // We know this is a stack overflow. We need to move the sp to the overflow region
- // that exists below the protected region. Determine the address of the next
- // available valid address below the protected region.
- VLOG(signals) << "setting sp to overflow region at " << std::hex << pregion;
-
- // Since the compiler puts the implicit overflow
- // check before the callee save instructions, the SP is already pointing to
- // the previous frame.
-
- // Tell the stack overflow code where the new stack pointer should be.
- uc->uc_mcontext.gregs[REG_EAX] = pregion;
-
- // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal.
- uc->uc_mcontext.gregs[REG_EIP] = reinterpret_cast<uintptr_t>(
- art_quick_throw_stack_overflow_from_signal);
-
- return true;
+ return false;
}
} // namespace art
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 68f46ad..24b9e46 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -173,21 +173,6 @@ 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, EAX contains the ESP value for the overflow region.
-DEFINE_FUNCTION art_quick_throw_stack_overflow_from_signal
- // Here, the ESP is above the protected region. We need to create a
- // callee save frame and then move ESP down to the overflow region.
- SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context
- mov %esp, %ecx // get current stack pointer
- mov %eax, %esp // move ESP to the overflow region.
- PUSH ecx // pass SP
- pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
- CFI_ADJUST_CFA_OFFSET(4)
- SETUP_GOT_NOSAVE // clobbers ebx (harmless here)
- 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/arch/x86_64/fault_handler_x86_64.cc b/runtime/arch/x86_64/fault_handler_x86_64.cc
index 88ae7f3..233d3c7 100644
--- a/runtime/arch/x86_64/fault_handler_x86_64.cc
+++ b/runtime/arch/x86_64/fault_handler_x86_64.cc
@@ -29,8 +29,7 @@
namespace art {
-void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context,
- mirror::ArtMethod** out_method,
+void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
}
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index f99ce07..3112bc0 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -29,7 +29,9 @@
#include "mirror/object-inl.h"
#include "object_utils.h"
#include "scoped_thread_state_change.h"
+#ifdef HAVE_ANDROID_OS
#include "sigchain.h"
+#endif
#include "verify_object-inl.h"
namespace art {
@@ -45,7 +47,6 @@ void art_sigsegv_fault() {
// Signal handler called on SIGSEGV.
static void art_fault_handler(int sig, siginfo_t* info, void* context) {
- // std::cout << "handling fault in ART handler\n";
fault_manager.HandleFault(sig, info, context);
}
@@ -54,7 +55,9 @@ FaultManager::FaultManager() {
}
FaultManager::~FaultManager() {
+#ifdef HAVE_ANDROID_OS
UnclaimSignalChain(SIGSEGV);
+#endif
sigaction(SIGSEGV, &oldaction_, nullptr); // Restore old handler.
}
@@ -69,12 +72,11 @@ void FaultManager::Init() {
#endif
// Set our signal handler now.
- int e = sigaction(SIGSEGV, &action, &oldaction_);
- if (e != 0) {
- VLOG(signals) << "Failed to claim SEGV: " << strerror(errno);
- }
+ sigaction(SIGSEGV, &action, &oldaction_);
+#ifdef HAVE_ANDROID_OS
// Make sure our signal handler is called before any user handlers.
ClaimSignalChain(SIGSEGV, &oldaction_);
+#endif
}
void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
@@ -82,12 +84,8 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
//
// If malloc calls abort, it will be holding its lock.
// If the handler tries to call malloc, it will deadlock.
-
- // 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)) {
+ if (IsInGeneratedCode(context, true)) {
VLOG(signals) << "in generated code, looking for handler";
for (const auto& handler : generated_code_handlers_) {
VLOG(signals) << "invoking Action on handler " << handler;
@@ -103,8 +101,11 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) {
}
art_sigsegv_fault();
- // Pass this on to the next handler in the chain, or the default if none.
+#ifdef HAVE_ANDROID_OS
InvokeUserSignalHandler(sig, info, context);
+#else
+ oldaction_.sa_sigaction(sig, info, context);
+#endif
}
void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
@@ -131,7 +132,7 @@ void FaultManager::RemoveHandler(FaultHandler* handler) {
// This function is called within the signal handler. It checks that
// the mutator_lock is held (shared). No annotalysis is done.
-bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool check_dex_pc) {
+bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) {
// We can only be running Java code in the current thread if it
// is in Runnable state.
VLOG(signals) << "Checking for generated code";
@@ -160,7 +161,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/<arch>/fault_handler_<arch>.
- GetMethodAndReturnPCAndSP(siginfo, context, &method_obj, &return_pc, &sp);
+ GetMethodAndReturnPCAndSP(context, &method_obj, &return_pc, &sp);
// If we don't have a potential method, we're outta here.
VLOG(signals) << "potential method: " << method_obj;
@@ -241,12 +242,12 @@ JavaStackTraceHandler::JavaStackTraceHandler(FaultManager* manager) : FaultHandl
bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) {
// Make sure that we are in the generated code, but we may not have a dex pc.
- if (manager_->IsInGeneratedCode(siginfo, context, false)) {
+ if (manager_->IsInGeneratedCode(context, false)) {
LOG(ERROR) << "Dumping java stack trace for crash in generated code";
mirror::ArtMethod* method = nullptr;
uintptr_t return_pc = 0;
uintptr_t sp = 0;
- manager_->GetMethodAndReturnPCAndSP(siginfo, context, &method, &return_pc, &sp);
+ manager_->GetMethodAndReturnPCAndSP(context, &method, &return_pc, &sp);
Thread* self = Thread::Current();
// Inside of generated code, sp[0] is the method, so sp is the frame.
StackReference<mirror::ArtMethod>* frame =
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 71c9977..026f5b9 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -43,10 +43,9 @@ 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,
+ void GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp);
- bool IsInGeneratedCode(siginfo_t* siginfo, void *context, bool check_dex_pc)
- NO_THREAD_SAFETY_ANALYSIS;
+ bool IsInGeneratedCode(void *context, bool check_dex_pc) NO_THREAD_SAFETY_ANALYSIS;
private:
std::vector<FaultHandler*> generated_code_handlers_;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 333ba03..e1e133f 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -286,8 +286,8 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
}
}
#else
- // Host. Only suspend check is explicit by default.
- explicit_checks_ = kExplicitSuspendCheck;
+ explicit_checks_ = kExplicitNullCheck | kExplicitSuspendCheck |
+ kExplicitStackOverflowCheck;
#endif
for (size_t i = 0; i < options.size(); ++i) {
@@ -305,7 +305,6 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni
Exit(0);
} else if (StartsWith(option, "-Xbootclasspath:")) {
boot_class_path_string_ = option.substr(strlen("-Xbootclasspath:")).data();
- LOG(INFO) << "setting boot class path to " << boot_class_path_string_;
} else if (option == "-classpath" || option == "-cp") {
// TODO: support -Djava.class.path
i++;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6459a52..efa205e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -580,41 +580,10 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
GetInstrumentation()->ForceInterpretOnly();
}
- heap_ = new gc::Heap(options->heap_initial_size_,
- options->heap_growth_limit_,
- options->heap_min_free_,
- options->heap_max_free_,
- options->heap_target_utilization_,
- options->foreground_heap_growth_multiplier_,
- options->heap_maximum_size_,
- options->image_,
- options->image_isa_,
- options->collector_type_,
- options->background_collector_type_,
- options->parallel_gc_threads_,
- options->conc_gc_threads_,
- options->low_memory_mode_,
- options->long_pause_log_threshold_,
- options->long_gc_log_threshold_,
- options->ignore_max_footprint_,
- options->use_tlab_,
- options->verify_pre_gc_heap_,
- options->verify_pre_sweeping_heap_,
- options->verify_post_gc_heap_,
- options->verify_pre_gc_rosalloc_,
- options->verify_pre_sweeping_rosalloc_,
- options->verify_post_gc_rosalloc_);
-
- dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_;
-
- BlockSignals();
- InitPlatformSignalHandlers();
-
bool implicit_checks_supported = false;
switch (kRuntimeISA) {
case kArm:
case kThumb2:
- case kX86:
implicit_checks_supported = true;
break;
default:
@@ -646,6 +615,36 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
}
}
+ heap_ = new gc::Heap(options->heap_initial_size_,
+ options->heap_growth_limit_,
+ options->heap_min_free_,
+ options->heap_max_free_,
+ options->heap_target_utilization_,
+ options->foreground_heap_growth_multiplier_,
+ options->heap_maximum_size_,
+ options->image_,
+ options->image_isa_,
+ options->collector_type_,
+ options->background_collector_type_,
+ options->parallel_gc_threads_,
+ options->conc_gc_threads_,
+ options->low_memory_mode_,
+ options->long_pause_log_threshold_,
+ options->long_gc_log_threshold_,
+ options->ignore_max_footprint_,
+ options->use_tlab_,
+ options->verify_pre_gc_heap_,
+ options->verify_pre_sweeping_heap_,
+ options->verify_post_gc_heap_,
+ options->verify_pre_gc_rosalloc_,
+ options->verify_pre_sweeping_rosalloc_,
+ options->verify_post_gc_rosalloc_);
+
+ dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_;
+
+ BlockSignals();
+ InitPlatformSignalHandlers();
+
java_vm_ = new JavaVMExt(this, options.get());
Thread::Startup();
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 4147dc2..d60fb49 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -233,99 +233,47 @@ static size_t FixStackSize(size_t stack_size) {
return stack_size;
}
-// Global variable to prevent the compiler optimizing away the page reads for the stack.
-byte dont_optimize_this;
-
// Install a protected region in the stack. This is used to trigger a SIGSEGV if a stack
// overflow is detected. It is located right below the stack_end_. Just below that
// is the StackOverflow reserved region used when creating the StackOverflow
// exception.
-//
-// There is a little complexity here that deserves a special mention. When running on the
-// host (glibc), the process's main thread's stack is allocated with a special flag
-// to prevent memory being allocated when it's not needed. This flag makes the
-// kernel only allocate memory for the stack by growing down in memory. Because we
-// want to put an mprotected region far away from that at the stack top, we need
-// to make sure the pages for the stack are mapped in before we call mprotect. We do
-// this by reading every page from the stack bottom (highest address) to the stack top.
-// We then madvise this away.
void Thread::InstallImplicitProtection(bool is_main_stack) {
byte* pregion = tlsPtr_.stack_end;
- byte* stack_lowmem = tlsPtr_.stack_begin;
- byte* stack_top = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(&pregion) &
- ~(kPageSize - 1)); // Page containing current top of stack.
-#ifndef HAVE_ANDROID_OS
- bool running_on_host = true;
-#else
- bool running_on_host = false;
-#endif
-
- if (running_on_host) {
- // On Host, we need to map in the main stack. This must be done by reading from the
- // current stack pointer downwards as the stack is mapped using VM_GROWSDOWN
- // in the kernel. Any access more than a page below the current SP will cause
- // a segv.
- if (is_main_stack) {
- // First we need to unprotect the protected region because this may
- // be called more than once for a particular stack and we will crash
- // if we try to read the protected page.
- mprotect(pregion - kStackOverflowProtectedSize, kStackOverflowProtectedSize, PROT_READ);
-
- // Read every page from the high address to the low.
- for (byte* p = stack_top; p > stack_lowmem; p -= kPageSize) {
- dont_optimize_this = *p;
- }
- }
- }
-
- // Check and place a marker word at the lowest usable address in the stack. This
- // is used to prevent a double protection.
constexpr uint32_t kMarker = 0xdadadada;
uintptr_t *marker = reinterpret_cast<uintptr_t*>(pregion);
if (*marker == kMarker) {
- // The region has already been set up. But on the main stack on the host we have
- // removed the protected region in order to read the stack memory. We need to put
- // this back again.
- if (is_main_stack && running_on_host) {
- mprotect(pregion - kStackOverflowProtectedSize, kStackOverflowProtectedSize, PROT_NONE);
- madvise(stack_lowmem, stack_top - stack_lowmem, MADV_DONTNEED);
- }
+ // The region has already been set up.
return;
}
// Add marker so that we can detect a second attempt to do this.
*marker = kMarker;
- if (!running_on_host) {
- // Running on Android, stacks are mapped cleanly. The protected region for the
- // main stack just needs to be mapped in. We do this by writing one byte per page.
- for (byte* p = pregion - kStackOverflowProtectedSize; p < pregion; p += kPageSize) {
- *p = 0;
+ pregion -= kStackOverflowProtectedSize;
+
+ // Touch the pages in the region to map them in. Otherwise mprotect fails. Only
+ // need to do this on the main stack. We only need to touch one byte per page.
+ if (is_main_stack) {
+ byte* start = pregion;
+ byte* end = pregion + kStackOverflowProtectedSize;
+ while (start < end) {
+ *start = static_cast<byte>(0);
+ start += kPageSize;
}
}
- pregion -= kStackOverflowProtectedSize;
-
VLOG(threads) << "installing stack protected region at " << std::hex <<
static_cast<void*>(pregion) << " to " <<
static_cast<void*>(pregion + kStackOverflowProtectedSize - 1);
-
if (mprotect(pregion, kStackOverflowProtectedSize, PROT_NONE) == -1) {
LOG(FATAL) << "Unable to create protected region in stack for implicit overflow check. Reason:"
<< strerror(errno);
}
// Tell the kernel that we won't be needing these pages any more.
- // NB. madvise will probably write zeroes into the memory (on linux it does).
if (is_main_stack) {
- if (running_on_host) {
- // On the host, it's the whole stack (minus a page to prevent overwrite of stack top).
- madvise(stack_lowmem, stack_top - stack_lowmem - kPageSize, MADV_DONTNEED);
- } else {
- // On Android, just the protected region.
- madvise(pregion, kStackOverflowProtectedSize, MADV_DONTNEED);
- }
+ madvise(pregion, kStackOverflowProtectedSize, MADV_DONTNEED);
}
}
@@ -586,17 +534,13 @@ void Thread::InitStackHwm() {
// Install the protected region if we are doing implicit overflow checks.
if (implicit_stack_check) {
if (is_main_thread) {
- size_t guardsize;
- pthread_attr_t attributes;
- CHECK_PTHREAD_CALL(pthread_attr_init, (&attributes), "guard size query");
- CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, &guardsize), "guard size query");
- CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), "guard size query");
- // The main thread might have protected region at the bottom. We need
+ // The main thread has a 16K protected region at the bottom. We need
// to install our own region so we need to move the limits
// of the stack to make room for it.
- tlsPtr_.stack_begin += guardsize;
- tlsPtr_.stack_end += guardsize;
- tlsPtr_.stack_size -= guardsize;
+ constexpr uint32_t kDelta = 16 * KB;
+ tlsPtr_.stack_begin += kDelta;
+ tlsPtr_.stack_end += kDelta;
+ tlsPtr_.stack_size -= kDelta;
}
InstallImplicitProtection(is_main_thread);
}
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index 518211b..ee66ccc 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -35,8 +35,8 @@ static void SigAltStack(stack_t* new_stack, stack_t* old_stack) {
void Thread::SetUpAlternateSignalStack() {
// Create and set an alternate signal stack.
stack_t ss;
- ss.ss_sp = new uint8_t[SIGSTKSZ * 2]; // NB. this is 16K.
- ss.ss_size = SIGSTKSZ * 2;
+ ss.ss_sp = new uint8_t[SIGSTKSZ];
+ ss.ss_size = SIGSTKSZ;
ss.ss_flags = 0;
CHECK(ss.ss_sp != NULL);
SigAltStack(&ss, NULL);
@@ -56,7 +56,7 @@ void Thread::TearDownAlternateSignalStack() {
// Tell the kernel to stop using it.
ss.ss_sp = NULL;
ss.ss_flags = SS_DISABLE;
- ss.ss_size = SIGSTKSZ * 2; // Avoid ENOMEM failure with Mac OS' buggy libc.
+ ss.ss_size = SIGSTKSZ; // Avoid ENOMEM failure with Mac OS' buggy libc.
SigAltStack(&ss, NULL);
// Free it.