Home | History | Annotate | Download | only in plugin
      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 
     16 namespace content {
     17 
     18 namespace {
     19 
     20 // Signal handler for SIGILL; see WorkaroundFlashLAHF().
     21 void 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*>(&regs[REG_RAX])[1] =
     52       reinterpret_cast<char*>(&regs[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.
     64 void 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