summaryrefslogtreecommitdiffstats
path: root/chrome/plugin
diff options
context:
space:
mode:
authorevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-05 17:46:38 +0000
committerevan@chromium.org <evan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-01-05 17:46:38 +0000
commitf4b8eec380a863f55d64210076c11a17f3218353 (patch)
tree76a2dd9977b2dcbe932afcdbb906d5e8b1080084 /chrome/plugin
parent5cc6fa388d1effe830505acfdc9b068e167ac8de (diff)
downloadchromium_src-f4b8eec380a863f55d64210076c11a17f3218353.zip
chromium_src-f4b8eec380a863f55d64210076c11a17f3218353.tar.gz
chromium_src-f4b8eec380a863f55d64210076c11a17f3218353.tar.bz2
linux: work around LAHF bug in Flash
64-bit Flash uses the LAHF instruction, which isn't available on some CPUs. Work around this by catching SIGILL and emulating the instruction. BUG=29789 TEST=flash works on more computers than before, nothing else changes Review URL: http://codereview.chromium.org/517031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35536 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/plugin')
-rw-r--r--chrome/plugin/plugin_main.cc10
-rw-r--r--chrome/plugin/plugin_main_linux.cc72
2 files changed, 81 insertions, 1 deletions
diff --git a/chrome/plugin/plugin_main.cc b/chrome/plugin/plugin_main.cc
index 1cbcc57..1e77325 100644
--- a/chrome/plugin/plugin_main.cc
+++ b/chrome/plugin/plugin_main.cc
@@ -39,7 +39,10 @@ void TrimInterposeEnvironment();
// Initializes the global Cocoa application object.
void InitializeChromeApplication();
-#endif // OS_MACOSX
+#elif defined(OS_LINUX)
+// Work around an unimplemented instruction in 64-bit Flash.
+void WorkaroundFlashLAHF();
+#endif
// main() routine for running as the plugin process.
int PluginMain(const MainFunctionParams& parameters) {
@@ -67,6 +70,11 @@ int PluginMain(const MainFunctionParams& parameters) {
// process name that shows up in "ps" etc. for plugins show as "exe"
// instead of "chrome" or something reasonable. Try to fix it.
CommandLine::SetProcTitle();
+
+#if defined(ARCH_CPU_64_BITS)
+ WorkaroundFlashLAHF();
+#endif
+
#elif defined(OS_WIN)
sandbox::TargetServices* target_services =
parameters.sandbox_info_.TargetServices();
diff --git a/chrome/plugin/plugin_main_linux.cc b/chrome/plugin/plugin_main_linux.cc
new file mode 100644
index 0000000..6bb9da7
--- /dev/null
+++ b/chrome/plugin/plugin_main_linux.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2009 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 {
+
+// 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;
+ sa.sa_flags = 0;
+ 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*>(&regs[REG_RAX])[1] =
+ reinterpret_cast<char*>(&regs[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;
+ memset(&action, 0, sizeof(action));
+ action.sa_flags = SA_SIGINFO;
+ action.sa_sigaction = &SignalHandler;
+
+ sigaction(SIGILL, &action, NULL);
+}
+
+#endif // defined(ARCH_CPU_64_BITS)