OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 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 { | |
17 | |
18 // Signal handler for SIGILL; see WorkaroundFlashLAHF(). | |
19 void SignalHandler(int signum, siginfo_t* info, void* void_context) { | |
20 const char kLAHFInstruction = 0x9f; | |
21 ucontext_t* context = static_cast<ucontext_t*>(void_context); | |
22 greg_t* regs = context->uc_mcontext.gregs; | |
23 char instruction = *reinterpret_cast<char*>(regs[REG_RIP]); | |
24 | |
25 // Check whether this is the kind of SIGILL we care about. | |
26 // (info->si_addr can be NULL when we get a SIGILL via other means, | |
27 // like with kill.) | |
28 if (signum != SIGILL || instruction != kLAHFInstruction) { | |
29 // Not the problem we're interested in. Reraise the signal. We | |
30 // need to be careful to handle threads etc. properly. | |
31 | |
32 struct sigaction sa; | |
33 sa.sa_flags = 0; | |
34 sigemptyset(&sa.sa_mask); | |
35 sa.sa_handler = SIG_DFL; | |
36 sigaction(signum, &sa, NULL); | |
37 | |
38 // block the current signal | |
39 sigset_t block_set; | |
40 sigemptyset(&block_set); | |
41 sigaddset(&block_set, signum); | |
42 sigprocmask(SIG_BLOCK, &block_set, NULL); | |
43 | |
44 // Re-raise signal. It won't be delivered until we return. | |
45 syscall(SYS_tkill, syscall(SYS_gettid), signum); | |
46 return; | |
47 } | |
48 | |
49 // LAHF moves the low byte of the EFLAGS register to AH. Emulate that. | |
50 reinterpret_cast<char*>(®s[REG_RAX])[1] = | |
51 reinterpret_cast<char*>(®s[REG_EFL])[0]; | |
52 // And advance the instruction pointer past the (one-byte) instruction. | |
53 ++regs[REG_RIP]; | |
54 } | |
55 | |
56 } // namespace | |
57 | |
58 // 64-bit Flash sometimes uses the LAHF instruction which isn't | |
59 // available on some CPUs. We can work around it by catching SIGILL | |
60 // (illegal instruction), checking if the signal was caused by this | |
61 // particular circumstance, emulating the instruction, and resuming. | |
62 // This function registers the signal handler. | |
63 void WorkaroundFlashLAHF() { | |
64 struct sigaction action; | |
65 memset(&action, 0, sizeof(action)); | |
66 action.sa_flags = SA_SIGINFO; | |
67 action.sa_sigaction = &SignalHandler; | |
68 | |
69 sigaction(SIGILL, &action, NULL); | |
70 } | |
71 | |
72 #endif // defined(ARCH_CPU_64_BITS) | |
OLD | NEW |