| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <signal.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <syscall.h> |
| #include <unistd.h> |
| |
| #include "build/build_config.h" |
| |
| // This whole file is only useful on 64-bit architectures. |
| #if defined(ARCH_CPU_64_BITS) |
| |
| namespace content { |
| |
| namespace { |
| |
| // Signal handler for SIGILL; see WorkaroundFlashLAHF(). |
| void SignalHandler(int signum, siginfo_t* info, void* void_context) { |
| const char kLAHFInstruction = 0x9f; |
| ucontext_t* context = static_cast<ucontext_t*>(void_context); |
| greg_t* regs = context->uc_mcontext.gregs; |
| char instruction = *reinterpret_cast<char*>(regs[REG_RIP]); |
| |
| // Check whether this is the kind of SIGILL we care about. |
| // (info->si_addr can be NULL when we get a SIGILL via other means, |
| // like with kill.) |
| if (signum != SIGILL || instruction != kLAHFInstruction) { |
| // Not the problem we're interested in. Reraise the signal. We |
| // need to be careful to handle threads etc. properly. |
| |
| struct sigaction sa = { { NULL } }; |
| sigemptyset(&sa.sa_mask); |
| sa.sa_handler = SIG_DFL; |
| sigaction(signum, &sa, NULL); |
| |
| // block the current signal |
| sigset_t block_set; |
| sigemptyset(&block_set); |
| sigaddset(&block_set, signum); |
| sigprocmask(SIG_BLOCK, &block_set, NULL); |
| |
| // Re-raise signal. It won't be delivered until we return. |
| syscall(SYS_tkill, syscall(SYS_gettid), signum); |
| return; |
| } |
| |
| // LAHF moves the low byte of the EFLAGS register to AH. Emulate that. |
| reinterpret_cast<char*>(®s[REG_RAX])[1] = |
| reinterpret_cast<char*>(®s[REG_EFL])[0]; |
| // And advance the instruction pointer past the (one-byte) instruction. |
| ++regs[REG_RIP]; |
| } |
| |
| } // namespace |
| |
| // 64-bit Flash sometimes uses the LAHF instruction which isn't |
| // available on some CPUs. We can work around it by catching SIGILL |
| // (illegal instruction), checking if the signal was caused by this |
| // particular circumstance, emulating the instruction, and resuming. |
| // This function registers the signal handler. |
| void WorkaroundFlashLAHF() { |
| struct sigaction action = { { NULL } }; |
| action.sa_flags = SA_SIGINFO; |
| action.sa_sigaction = &SignalHandler; |
| |
| sigaction(SIGILL, &action, NULL); |
| } |
| |
| } // namespace content |
| |
| #endif // defined(ARCH_CPU_64_BITS) |