Reland r216808, underlying lldb bug has been fixed.
[WebKit-https.git] / Source / JavaScriptCore / tools / SigillCrashAnalyzer.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "SigillCrashAnalyzer.h"
28
29 #include "CallFrame.h"
30 #include "CodeBlock.h"
31 #include "MachineContext.h"
32 #include "VMInspector.h"
33 #include <mutex>
34 #include <wtf/StdLibExtras.h>
35
36 #if USE(ARM64_DISASSEMBLER)
37 #include "A64DOpcode.h"
38 #endif
39
40 #include <wtf/threads/Signals.h>
41
42 namespace JSC {
43
44 struct SignalContext;
45
46 class SigillCrashAnalyzer {
47 public:
48     static SigillCrashAnalyzer& instance();
49
50     enum class CrashSource {
51         Unknown,
52         JavaScriptCore,
53         Other,
54     };
55     CrashSource analyze(SignalContext&);
56
57 private:
58     SigillCrashAnalyzer() { }
59     void dumpCodeBlock(CodeBlock*, void* machinePC);
60
61 #if USE(ARM64_DISASSEMBLER)
62     A64DOpcode m_arm64Opcode;
63 #endif
64 };
65
66 #if OS(DARWIN)
67
68 #if USE(OS_LOG)
69
70 #define log(format, ...) \
71     os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
72
73 #else // USE(OS_LOG)
74
75 #define log(format, ...) \
76     dataLogF(format, ##__VA_ARGS__)
77     
78 #endif // USE(OS_LOG)
79
80 struct SignalContext {
81     SignalContext(PlatformRegisters& registers)
82         : registers(registers)
83         , machinePC(MachineContext::instructionPointer(registers))
84         , stackPointer(MachineContext::stackPointer(registers))
85         , framePointer(MachineContext::framePointer(registers))
86     { }
87
88     void dump()
89     {
90 #if CPU(X86_64)
91 #define FOR_EACH_REGISTER(v) \
92         v(rax) \
93         v(rbx) \
94         v(rcx) \
95         v(rdx) \
96         v(rdi) \
97         v(rsi) \
98         v(rbp) \
99         v(rsp) \
100         v(r8) \
101         v(r9) \
102         v(r10) \
103         v(r11) \
104         v(r12) \
105         v(r13) \
106         v(r14) \
107         v(r15) \
108         v(rip) \
109         v(rflags) \
110         v(cs) \
111         v(fs) \
112         v(gs)
113
114 #define DUMP_REGISTER(__reg) \
115         log("Register " #__reg ": %p", reinterpret_cast<void*>(registers.__##__reg));
116         FOR_EACH_REGISTER(DUMP_REGISTER)
117 #undef FOR_EACH_REGISTER
118
119 #elif CPU(ARM64)
120         int i;
121         for (i = 0; i < 28; i += 4) {
122             log("x%d: %016llx x%d: %016llx x%d: %016llx x%d: %016llx",
123                 i, registers.__x[i],
124                 i+1, registers.__x[i+1],
125                 i+2, registers.__x[i+2],
126                 i+3, registers.__x[i+3]);
127         }
128         ASSERT(i < 29);
129         log("x%d: %016llx fp: %016llx lr: %016llx",
130             i, registers.__x[i], registers.__fp, registers.__lr);
131         log("sp: %016llx pc: %016llx cpsr: %08x",
132             registers.__sp, registers.__pc, registers.__cpsr);
133 #endif
134     }
135
136     PlatformRegisters& registers;
137     void* machinePC;
138     void* stackPointer;
139     void* framePointer;
140 };
141
142 static void installCrashHandler()
143 {
144 #if CPU(X86_64) || CPU(ARM64)
145     installSignalHandler(Signal::Ill, [] (Signal, SigInfo&, PlatformRegisters& registers) {
146         SignalContext context(registers);
147
148         if (!isJITPC(context.machinePC))
149             return SignalAction::NotHandled;
150
151         SigillCrashAnalyzer& analyzer = SigillCrashAnalyzer::instance();
152         analyzer.analyze(context);
153         return SignalAction::NotHandled;
154     });
155 #endif
156 }
157
158 #else // OS(DARWIN)
159
160 #define log(format, ...) do { } while (false)
161     
162 struct SignalContext {
163     SignalContext() { }
164
165     void dump() { }
166
167     void* machinePC;
168     void* stackPointer;
169     void* framePointer;
170 };
171
172 static void installCrashHandler()
173 {
174     // Do nothing. Not supported for this platform.
175 }
176
177 #endif // OS(DARWIN)
178
179 SigillCrashAnalyzer& SigillCrashAnalyzer::instance()
180 {
181     static SigillCrashAnalyzer* analyzer;
182     static std::once_flag once;
183     std::call_once(once, [] {
184         installCrashHandler();
185         analyzer = new SigillCrashAnalyzer;
186     });
187     return *analyzer;
188 }
189
190 void enableSigillCrashAnalyzer()
191 {
192     // Just instantiating the SigillCrashAnalyzer will enable it.
193     SigillCrashAnalyzer::instance();
194 }
195
196 auto SigillCrashAnalyzer::analyze(SignalContext& context) -> CrashSource
197 {
198     CrashSource crashSource = CrashSource::Unknown;
199     log("BEGIN SIGILL analysis");
200
201     do {
202         // First, dump the signal context info so that we'll at least have the same info
203         // that the default crash handler would given us in case this crash analyzer
204         // itself crashes.
205         context.dump();
206
207         VMInspector& inspector = VMInspector::instance();
208
209         // Use a timeout period of 2 seconds. The client is about to crash, and we don't
210         // want to turn the crash into a hang by re-trying the lock for too long.
211         auto expectedLocker = inspector.lock(Seconds(2));
212         if (!expectedLocker) {
213             ASSERT(expectedLocker.error() == VMInspector::Error::TimedOut);
214             log("ERROR: Unable to analyze SIGILL. Timed out while waiting to iterate VMs.");
215             break;
216         }
217         auto& locker = expectedLocker.value();
218
219         void* pc = context.machinePC;
220         auto isInJITMemory = inspector.isValidExecutableMemory(locker, pc);
221         if (!isInJITMemory) {
222             log("ERROR: Timed out: not able to determine if pc %p is in valid JIT executable memory", pc);
223             break;
224         }
225         if (!isInJITMemory.value()) {
226             log("pc %p is NOT in valid JIT executable memory", pc);
227             crashSource = CrashSource::Other;
228             break;
229         }
230         log("pc %p is in valid JIT executable memory", pc);
231         crashSource = CrashSource::JavaScriptCore;
232
233 #if CPU(ARM64)
234         size_t pcAsSize = reinterpret_cast<size_t>(pc);
235         if (pcAsSize != roundUpToMultipleOf<sizeof(uint32_t)>(pcAsSize)) {
236             log("pc %p is NOT properly aligned", pc);
237             break;
238         }
239
240         // We know it's safe to read the word at the PC because we're handling a SIGILL.
241         // Otherwise, we would have crashed with a SIGBUS instead.
242         uint32_t wordAtPC = *reinterpret_cast<uint32_t*>(pc);
243         log("instruction bits at pc %p is: 0x%08x", pc, wordAtPC);
244 #endif
245
246         auto expectedCodeBlock = inspector.codeBlockForMachinePC(locker, pc);
247         if (!expectedCodeBlock) {
248             if (expectedCodeBlock.error() == VMInspector::Error::TimedOut)
249                 log("ERROR: Timed out: not able to determine if pc %p is in a valid CodeBlock", pc);
250             else
251                 log("The current thread does not own any VM JSLock");
252             break;
253         }
254         CodeBlock* codeBlock = expectedCodeBlock.value();
255         if (!codeBlock) {
256             log("machine PC %p does not belong to any CodeBlock in the currently entered VM", pc);
257             break;
258         }
259
260         log("pc %p belongs to CodeBlock %p of type %s", pc, codeBlock, JITCode::typeName(codeBlock->jitType()));
261
262         dumpCodeBlock(codeBlock, pc);
263     } while (false);
264
265     log("END SIGILL analysis");
266     return crashSource;
267 }
268
269 void SigillCrashAnalyzer::dumpCodeBlock(CodeBlock* codeBlock, void* machinePC)
270 {
271 #if CPU(ARM64) && ENABLE(JIT)
272     JITCode* jitCode = codeBlock->jitCode().get();
273
274     // Dump the raw bits of the code.
275     uint32_t* start = reinterpret_cast<uint32_t*>(jitCode->start());
276     uint32_t* end = reinterpret_cast<uint32_t*>(jitCode->end());
277     log("JITCode %p [%p-%p]:", jitCode, start, end);
278     if (start < end) {
279         uint32_t* p = start;
280         while (p + 8 <= end) {
281             log("[%p-%p]: %08x %08x %08x %08x %08x %08x %08x %08x", p, p+7, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
282             p += 8;
283         }
284         if (p + 7 <= end)
285             log("[%p-%p]: %08x %08x %08x %08x %08x %08x %08x", p, p+6, p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
286         else if (p + 6 <= end)
287             log("[%p-%p]: %08x %08x %08x %08x %08x %08x", p, p+5, p[0], p[1], p[2], p[3], p[4], p[5]);
288         else if (p + 5 <= end)
289             log("[%p-%p]: %08x %08x %08x %08x %08x", p, p+4, p[0], p[1], p[2], p[3], p[4]);
290         else if (p + 4 <= end)
291             log("[%p-%p]: %08x %08x %08x %08x", p, p+3, p[0], p[1], p[2], p[3]);
292         if (p + 3 <= end)
293             log("[%p-%p]: %08x %08x %08x", p, p+2, p[0], p[1], p[2]);
294         else if (p + 2 <= end)
295             log("[%p-%p]: %08x %08x", p, p+1, p[0], p[1]);
296         else if (p + 1 <= end)
297             log("[%p-%p]: %08x", p, p, p[0]);
298     }
299
300     // Dump the disassembly of the code.
301     log("Disassembly:");
302     uint32_t* currentPC = reinterpret_cast<uint32_t*>(jitCode->executableAddress());
303     size_t byteCount = jitCode->size();
304     while (byteCount) {
305         char pcString[24];
306         if (currentPC == machinePC) {
307             snprintf(pcString, sizeof(pcString), "* 0x%lx", reinterpret_cast<unsigned long>(currentPC));
308             log("%20s: %s    <=========================", pcString, m_arm64Opcode.disassemble(currentPC));
309         } else {
310             snprintf(pcString, sizeof(pcString), "0x%lx", reinterpret_cast<unsigned long>(currentPC));
311             log("%20s: %s", pcString, m_arm64Opcode.disassemble(currentPC));
312         }
313         currentPC++;
314         byteCount -= sizeof(uint32_t);
315     }
316 #else
317     UNUSED_PARAM(codeBlock);
318     UNUSED_PARAM(machinePC);
319     // Not implemented yet.
320 #endif
321 }
322
323 } // namespace JSC