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*>(&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.
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