1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <signal.h> 6#include <string.h> 7#include <sys/types.h> 8#include <syscall.h> 9#include <unistd.h> 10 11#include "build/build_config.h" 12 13// This whole file is only useful on 64-bit architectures. 14#if defined(ARCH_CPU_64_BITS) 15 16namespace content { 17 18namespace { 19 20// Signal handler for SIGILL; see WorkaroundFlashLAHF(). 21void SignalHandler(int signum, siginfo_t* info, void* void_context) { 22 const char kLAHFInstruction = 0x9f; 23 ucontext_t* context = static_cast<ucontext_t*>(void_context); 24 greg_t* regs = context->uc_mcontext.gregs; 25 char instruction = *reinterpret_cast<char*>(regs[REG_RIP]); 26 27 // Check whether this is the kind of SIGILL we care about. 28 // (info->si_addr can be NULL when we get a SIGILL via other means, 29 // like with kill.) 30 if (signum != SIGILL || instruction != kLAHFInstruction) { 31 // Not the problem we're interested in. Reraise the signal. We 32 // need to be careful to handle threads etc. properly. 33 34 struct sigaction sa = { { NULL } }; 35 sigemptyset(&sa.sa_mask); 36 sa.sa_handler = SIG_DFL; 37 sigaction(signum, &sa, NULL); 38 39 // block the current signal 40 sigset_t block_set; 41 sigemptyset(&block_set); 42 sigaddset(&block_set, signum); 43 sigprocmask(SIG_BLOCK, &block_set, NULL); 44 45 // Re-raise signal. It won't be delivered until we return. 46 syscall(SYS_tkill, syscall(SYS_gettid), signum); 47 return; 48 } 49 50 // LAHF moves the low byte of the EFLAGS register to AH. Emulate that. 51 reinterpret_cast<char*>(®s[REG_RAX])[1] = 52 reinterpret_cast<char*>(®s[REG_EFL])[0]; 53 // And advance the instruction pointer past the (one-byte) instruction. 54 ++regs[REG_RIP]; 55} 56 57} // namespace 58 59// 64-bit Flash sometimes uses the LAHF instruction which isn't 60// available on some CPUs. We can work around it by catching SIGILL 61// (illegal instruction), checking if the signal was caused by this 62// particular circumstance, emulating the instruction, and resuming. 63// This function registers the signal handler. 64void WorkaroundFlashLAHF() { 65 struct sigaction action = { { NULL } }; 66 action.sa_flags = SA_SIGINFO; 67 action.sa_sigaction = &SignalHandler; 68 69 sigaction(SIGILL, &action, NULL); 70} 71 72} // namespace content 73 74#endif // defined(ARCH_CPU_64_BITS) 75