| Index: src/v8.cc
|
| diff --git a/src/v8.cc b/src/v8.cc
|
| index b04ccc07c700e35f572bc42f4eec949315174766..e8af10546db8bc605a31a1cdb6e55d534538aae4 100644
|
| --- a/src/v8.cc
|
| +++ b/src/v8.cc
|
| @@ -2,6 +2,9 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <signal.h>
|
| +#include <ucontext.h>
|
| +
|
| #include "src/v8.h"
|
|
|
| #include "src/assembler.h"
|
| @@ -65,6 +68,186 @@ void V8::SetReturnAddressLocationResolver(
|
| }
|
|
|
|
|
| +// TODO(bmeurer): Move to signal-handlers.cc?
|
| +namespace {
|
| +
|
| +struct sigaction prev_handler;
|
| +
|
| +
|
| +struct Decoder {
|
| + void get_modrm(uint8_t data, int* mod, int* regop, int* rm) {
|
| + *mod = (data >> 6) & 3;
|
| + *regop = (data & 0x38) >> 3;
|
| + *rm = (data & 7);
|
| + }
|
| +
|
| + void get_sib(uint8_t data, int* scale, int* index, int* base) {
|
| + *scale = (data >> 6) & 3;
|
| + *index = ((data >> 3) & 7);
|
| + *base = (data & 7);
|
| + }
|
| +
|
| + int right_operand(uint8_t* modrmp) {
|
| + int mod, regop, rm;
|
| + get_modrm(*modrmp, &mod, ®op, &rm);
|
| + switch (mod) {
|
| + case 0:
|
| + if (rm == 5) {
|
| + return 5;
|
| + } else if (rm == 4) {
|
| + int scale, index, base;
|
| + get_sib(modrmp[1], &scale, &index, &base);
|
| + return base == 5 ? 6 : 2;
|
| + } else {
|
| + return 1;
|
| + }
|
| + case 1:
|
| + return 2 + (rm == 4);
|
| + case 2:
|
| + return 5 + (rm == 4);
|
| + case 3:
|
| + return 1;
|
| + default:
|
| + break;
|
| + }
|
| + UNREACHABLE();
|
| + return 0;
|
| + }
|
| +
|
| + bool Decode(uint8_t** ppc) {
|
| + uint8_t* pc = *ppc;
|
| + bool operand_word_size = false;
|
| + while (true) {
|
| + if (*pc == 0x66) { // Group 3 prefix.
|
| + operand_word_size = true;
|
| + } else if ((*pc & 0xF0) == 0x40) {
|
| + // Skip REX.
|
| + } else {
|
| + break; // Not a prefix - an opcode.
|
| + }
|
| + ++pc;
|
| + }
|
| + switch (*pc) {
|
| + case 0x0F: {
|
| + if (pc[1] == 0xB6) { // mov
|
| + }
|
| + break;
|
| + }
|
| + case 0xF2: {
|
| + if (pc[1] == 0x0F && pc[2] == 0x11) { // movsd mem,reg
|
| + pc += 3;
|
| + *ppc = pc + right_operand(pc);
|
| + PrintF("*** movsd mem,reg\n");
|
| + return true;
|
| + }
|
| + break;
|
| + }
|
| + case 0xF3: {
|
| + if (pc[1] == 0x0F && pc[2] == 0x11) { // movss mem,reg
|
| + pc += 3;
|
| + *ppc = pc + right_operand(pc);
|
| + PrintF("*** movss mem,reg\n");
|
| + return true;
|
| + }
|
| + break;
|
| + }
|
| + case 0x88:
|
| + case 0x89: { // mov mem,reg
|
| + ++pc;
|
| + *ppc = pc + right_operand(pc);
|
| + PrintF("*** mov mem,reg\n");
|
| + return true;
|
| + }
|
| + case 0xC6: { // mov mem,imm8
|
| + ++pc;
|
| + *ppc = pc + right_operand(pc) + 1;
|
| + PrintF("*** mov mem,imm8\n");
|
| + return true;
|
| + }
|
| + case 0xC7: {
|
| + ++pc;
|
| + if (operand_word_size) { // mov mem,imm16
|
| + *ppc = pc + right_operand(pc) + 2;
|
| + PrintF("*** mov mem,imm16\n");
|
| + } else { // mov mem,imm32
|
| + *ppc = pc + right_operand(pc) + 4;
|
| + PrintF("*** mov mem,imm32\n");
|
| + }
|
| + return true;
|
| + }
|
| + default:
|
| + break;
|
| + }
|
| + return false;
|
| + }
|
| +};
|
| +
|
| +
|
| +bool DecodeHeapAccess(uint8_t** ppc) {
|
| + Decoder decoder;
|
| + return decoder.Decode(ppc);
|
| +}
|
| +
|
| +
|
| +bool HandleFault(int signum, siginfo_t* si, ucontext_t* uc) {
|
| + if (signum != SIGSEGV) return false;
|
| + Isolate* const isolate = Isolate::UnsafeCurrent();
|
| + if (!isolate || !isolate->IsInUse()) {
|
| + // We require a fully initialized and entered isolate.
|
| + return false;
|
| + }
|
| + if (v8::Locker::IsActive() &&
|
| + !isolate->thread_manager()->IsLockedByCurrentThread()) {
|
| + return false;
|
| + }
|
| + if (!isolate->IsInGuardArea(si->si_addr)) return false;
|
| + uint8_t** ppc = reinterpret_cast<uint8_t**>(&uc->uc_mcontext.gregs[REG_RIP]);
|
| + if (DecodeHeapAccess(ppc)) return true;
|
| + PrintF("*** Unhandled fault at %p!\n", *ppc);
|
| + return false;
|
| +}
|
| +
|
| +
|
| +void FaultHandler(int signum, siginfo_t* si, void* context) {
|
| + if (HandleFault(signum, si, static_cast<ucontext_t*>(context))) return;
|
| +
|
| + // This signal is not for any asm.js code we expect, so we need to forward
|
| + // the signal to the next handler. If there is no next handler (SIG_IGN or
|
| + // SIG_DFL), then it's time to crash. To do this, we set the signal back to
|
| + // its original disposition and return. This will cause the faulting op to
|
| + // be re-executed which will crash in the normal way. The advantage of
|
| + // doing this to calling _exit() is that we remove ourselves from the crash
|
| + // stack which improves crash reports. If there is a next handler, call it.
|
| + // It will either crash synchronously, fix up the instruction so that
|
| + // execution can continue and return, or trigger a crash by returning the
|
| + // signal to it's original disposition and returning.
|
| + //
|
| + // Note: the order of these tests matter.
|
| + if (prev_handler.sa_flags & SA_SIGINFO) {
|
| + prev_handler.sa_sigaction(signum, si, context);
|
| + } else if (prev_handler.sa_handler == SIG_DFL ||
|
| + prev_handler.sa_handler == SIG_IGN) {
|
| + sigaction(signum, &prev_handler, nullptr);
|
| + } else {
|
| + prev_handler.sa_handler(signum);
|
| + }
|
| +}
|
| +
|
| +
|
| +void InstallFaultHandler() {
|
| + // SA_NODEFER allows us to reenter the signal handler if we crash while
|
| + // handling the signal.
|
| + struct sigaction sa;
|
| + bzero(&sa, sizeof(sa));
|
| + sa.sa_flags = SA_SIGINFO | SA_NODEFER;
|
| + sa.sa_sigaction = &FaultHandler;
|
| + sigemptyset(&sa.sa_mask);
|
| + sigaction(SIGSEGV, &sa, &prev_handler);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| void V8::InitializeOncePerProcessImpl() {
|
| FlagList::EnforceFlagImplications();
|
|
|
| @@ -98,6 +281,7 @@ void V8::InitializeOncePerProcessImpl() {
|
| SetUpJSCallerSavedCodeData();
|
| ExternalReference::SetUp();
|
| Bootstrapper::InitializeOncePerProcess();
|
| + InstallFaultHandler();
|
| }
|
|
|
|
|
|
|