Title: [211603] trunk/Source
Revision
211603
Author
[email protected]
Date
2017-02-02 15:32:36 -0800 (Thu, 02 Feb 2017)

Log Message

Add a SIGILL crash analyzer to make debugging SIGILLs easier.
https://bugs.webkit.org/show_bug.cgi?id=167714
<rdar://problem/30318237>

Reviewed by Filip Pizlo.

Source/_javascript_Core:

The current implementation is only for X86_64 and ARM64 on OS(DARWIN).  The
analyzer is not enabled for all other ports.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* API/JSVirtualMachine.mm:
* assembler/ARM64Assembler.h:
(JSC::ARM64Assembler::illegalInstruction):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::illegalInstruction):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::illegalInstruction):
* assembler/X86Assembler.h:
(JSC::X86Assembler::illegalInstruction):
* heap/Heap.cpp:
(JSC::Heap::forEachCodeBlockIgnoringJITPlansImpl):
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::forEachCodeBlockIgnoringJITPlans):
* runtime/Options.cpp:
(JSC::Options::isAvailable):
(JSC::recomputeDependentOptions):
* runtime/Options.h:
* runtime/VM.cpp:
(JSC::VM::VM):
(JSC::VM::~VM):
* runtime/VM.h:
* tools/SigillCrashAnalyzer.cpp: Added.
(JSC::SignalContext::SignalContext):
(JSC::SignalContext::dump):
(JSC::handleCrash):
(JSC::initializeCrashHandler):
(JSC::ensureSigillCrashAnalyzer):
(JSC::SigillCrashAnalyzer::analyze):
(JSC::SigillCrashAnalyzer::dumpCodeBlock):
* tools/SigillCrashAnalyzer.h: Added.
* tools/VMInspector.cpp: Added.
(JSC::VMInspector::instance):
(JSC::VMInspector::add):
(JSC::VMInspector::remove):
(JSC::ensureIsSafeToLock):
* tools/VMInspector.h: Added.
(JSC::VMInspector::iterate):

Source/WTF:

* wtf/StdLibExtras.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSVirtualMachine.mm (211602 => 211603)


--- trunk/Source/_javascript_Core/API/JSVirtualMachine.mm	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/API/JSVirtualMachine.mm	2017-02-02 23:32:36 UTC (rev 211603)
@@ -34,6 +34,7 @@
 #import "JSVirtualMachine.h"
 #import "JSVirtualMachineInternal.h"
 #import "JSWrapperMap.h"
+#import "SigillCrashAnalyzer.h"
 #import "SlotVisitorInlines.h"
 #import <mutex>
 #import <wtf/Lock.h>
@@ -225,6 +226,11 @@
     }
 }
 
+- (void)enableSigillCrashAnalyzer
+{
+    JSC::enableSigillCrashAnalyzer();
+}
+
 @end
 
 @implementation JSVirtualMachine(Internal)

Added: trunk/Source/_javascript_Core/API/JSVirtualMachinePrivate.h (0 => 211603)


--- trunk/Source/_javascript_Core/API/JSVirtualMachinePrivate.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/API/JSVirtualMachinePrivate.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSVirtualMachinePrivate_h
+#define JSVirtualMachinePrivate_h
+
+#if JSC_OBJC_API_ENABLED
+
+@interface JSVirtualMachine(Private)
+
+/*!
+ @method
+ @abstract Enables SIGILL crash analysis for all JSVirtualMachines.
+ @discussion Installs a SIGILL crash handler that will collect additional
+ non-user identifying information about the crash site via os_log_info.
+ */
+- (void)enableSigillCrashAnalyzer;
+
+@end
+
+#endif
+
+#endif // JSVirtualMachinePrivate_h

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (211602 => 211603)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2017-02-02 23:32:36 UTC (rev 211603)
@@ -908,6 +908,8 @@
     tools/FunctionWhitelist.cpp
     tools/JSDollarVM.cpp
     tools/JSDollarVMPrototype.cpp
+    tools/SigillCrashAnalyzer.cpp
+    tools/VMInspector.cpp
 
     wasm/JSWebAssembly.cpp
     wasm/WasmB3IRGenerator.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (211602 => 211603)


--- trunk/Source/_javascript_Core/ChangeLog	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,3 +1,55 @@
+2017-02-02  Mark Lam  <[email protected]>
+
+        Add a SIGILL crash analyzer to make debugging SIGILLs easier.
+        https://bugs.webkit.org/show_bug.cgi?id=167714
+        <rdar://problem/30318237>
+
+        Reviewed by Filip Pizlo.
+
+        The current implementation is only for X86_64 and ARM64 on OS(DARWIN).  The
+        analyzer is not enabled for all other ports.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * API/JSVirtualMachine.mm:
+        * assembler/ARM64Assembler.h:
+        (JSC::ARM64Assembler::illegalInstruction):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::illegalInstruction):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::illegalInstruction):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::illegalInstruction):
+        * heap/Heap.cpp:
+        (JSC::Heap::forEachCodeBlockIgnoringJITPlansImpl):
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::forEachCodeBlockIgnoringJITPlans):
+        * runtime/Options.cpp:
+        (JSC::Options::isAvailable):
+        (JSC::recomputeDependentOptions):
+        * runtime/Options.h:
+        * runtime/VM.cpp:
+        (JSC::VM::VM):
+        (JSC::VM::~VM):
+        * runtime/VM.h:
+        * tools/SigillCrashAnalyzer.cpp: Added.
+        (JSC::SignalContext::SignalContext):
+        (JSC::SignalContext::dump):
+        (JSC::handleCrash):
+        (JSC::initializeCrashHandler):
+        (JSC::ensureSigillCrashAnalyzer):
+        (JSC::SigillCrashAnalyzer::analyze):
+        (JSC::SigillCrashAnalyzer::dumpCodeBlock):
+        * tools/SigillCrashAnalyzer.h: Added.
+        * tools/VMInspector.cpp: Added.
+        (JSC::VMInspector::instance):
+        (JSC::VMInspector::add):
+        (JSC::VMInspector::remove):
+        (JSC::ensureIsSafeToLock):
+        * tools/VMInspector.h: Added.
+        (JSC::VMInspector::iterate):
+
 2017-02-02  Chris Dumez  <[email protected]>
 
         {}.toString.call(crossOriginWindow) should return "[object Object]"

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (211602 => 211603)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2017-02-02 23:32:36 UTC (rev 211603)
@@ -2334,6 +2334,11 @@
 		FE20CE9D15F04A9500DF3430 /* LLIntCLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */; };
 		FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		FE2E6A7B1D6EA62C0060F896 /* ThrowScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE2E6A7A1D6EA5FE0060F896 /* ThrowScope.cpp */; };
+		FE3022D21E3D73A500BAC493 /* SigillCrashAnalyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */; };
+		FE3022D31E3D73A500BAC493 /* SigillCrashAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3022D11E3D739600BAC493 /* SigillCrashAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		FE3022D61E42857300BAC493 /* VMInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE3022D41E42856700BAC493 /* VMInspector.cpp */; };
+		FE3022D71E42857300BAC493 /* VMInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3022D51E42856700BAC493 /* VMInspector.h */; };
+		FE3022D91E43C93400BAC493 /* JSVirtualMachinePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3022D81E43C85500BAC493 /* JSVirtualMachinePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		FE318FDF1CAC982700DFCC54 /* ECMAScriptSpecInternalFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE318FDD1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.cpp */; };
 		FE318FE01CAC982F00DFCC54 /* ECMAScriptSpecInternalFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */; };
 		FE3422121D6B81C30032BE88 /* ThrowScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE3422111D6B818C0032BE88 /* ThrowScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -4875,6 +4880,11 @@
 		FE20CE9B15F04A9500DF3430 /* LLIntCLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntCLoop.cpp; path = llint/LLIntCLoop.cpp; sourceTree = "<group>"; };
 		FE20CE9C15F04A9500DF3430 /* LLIntCLoop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntCLoop.h; path = llint/LLIntCLoop.h; sourceTree = "<group>"; };
 		FE2E6A7A1D6EA5FE0060F896 /* ThrowScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThrowScope.cpp; sourceTree = "<group>"; };
+		FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SigillCrashAnalyzer.cpp; sourceTree = "<group>"; };
+		FE3022D11E3D739600BAC493 /* SigillCrashAnalyzer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SigillCrashAnalyzer.h; sourceTree = "<group>"; };
+		FE3022D41E42856700BAC493 /* VMInspector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMInspector.cpp; sourceTree = "<group>"; };
+		FE3022D51E42856700BAC493 /* VMInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMInspector.h; sourceTree = "<group>"; };
+		FE3022D81E43C85500BAC493 /* JSVirtualMachinePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVirtualMachinePrivate.h; sourceTree = "<group>"; };
 		FE318FDD1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ECMAScriptSpecInternalFunctions.cpp; sourceTree = "<group>"; };
 		FE318FDE1CAC8C5300DFCC54 /* ECMAScriptSpecInternalFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ECMAScriptSpecInternalFunctions.h; sourceTree = "<group>"; };
 		FE3422111D6B818C0032BE88 /* ThrowScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThrowScope.h; sourceTree = "<group>"; };
@@ -5927,6 +5937,7 @@
 				86E3C60F167BAB87006D760A /* JSVirtualMachine.h */,
 				86E3C610167BAB87006D760A /* JSVirtualMachine.mm */,
 				86E3C611167BAB87006D760A /* JSVirtualMachineInternal.h */,
+				FE3022D81E43C85500BAC493 /* JSVirtualMachinePrivate.h */,
 				A7482E37116A697B003B0712 /* JSWeakObjectMapRefInternal.h */,
 				A7482B7A1166CDEA003B0712 /* JSWeakObjectMapRefPrivate.cpp */,
 				A7482B791166CDEA003B0712 /* JSWeakObjectMapRefPrivate.h */,
@@ -6813,8 +6824,12 @@
 				FE384EE21ADDB7AD0055DE2C /* JSDollarVM.h */,
 				FE384EE31ADDB7AD0055DE2C /* JSDollarVMPrototype.cpp */,
 				FE384EE41ADDB7AD0055DE2C /* JSDollarVMPrototype.h */,
+				FE3022D01E3D739600BAC493 /* SigillCrashAnalyzer.cpp */,
+				FE3022D11E3D739600BAC493 /* SigillCrashAnalyzer.h */,
 				86B5822C14D22F5F00A9C306 /* ProfileTreeNode.h */,
 				86B5826A14D35D5100A9C306 /* TieredMMapArray.h */,
+				FE3022D41E42856700BAC493 /* VMInspector.cpp */,
+				FE3022D51E42856700BAC493 /* VMInspector.h */,
 			);
 			path = tools;
 			sourceTree = "<group>";
@@ -8298,7 +8313,6 @@
 				0F2FCCFF18A60070001A27F8 /* DFGThreadData.h in Headers */,
 				0FC097A2146B28CC00CF2442 /* DFGThunks.h in Headers */,
 				0FD8A32817D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.h in Headers */,
-				ADFF2F701E319DE3001EA54E /* DFGTierUpEntryTrigger.h in Headers */,
 				0FD8A32A17D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h in Headers */,
 				0FD8A32C17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.h in Headers */,
 				0FE7211E193B9C590031F6ED /* DFGTransition.h in Headers */,
@@ -8440,6 +8454,7 @@
 				0F86A26F1D6F7B3300CB0C92 /* GCTypeMap.h in Headers */,
 				9959E9311BD18272001AA413 /* generate-combined-inspector-json.py in Headers */,
 				C4703CC0192844960013FBEA /* generate-inspector-protocol-bindings.py in Headers */,
+				FE3022D91E43C93400BAC493 /* JSVirtualMachinePrivate.h in Headers */,
 				99DA00AF1BD5994E00F4575C /* generate-js-builtins.py in Headers */,
 				A5EA70EC19F5B3EA0098F5EC /* generate_cpp_alternate_backend_dispatcher_header.py in Headers */,
 				A5EF9B141A1D43F600702E90 /* generate_cpp_backend_dispatcher_header.py in Headers */,
@@ -8793,6 +8808,7 @@
 				FE3913561B794F8F00EDAF71 /* LiveObjectList.h in Headers */,
 				70DE9A091BE7D69E005D89D9 /* LLIntAssembly.h in Headers */,
 				0F0FC45A14BD15F500B81154 /* LLIntCallLinkInfo.h in Headers */,
+				FE3022D31E3D73A500BAC493 /* SigillCrashAnalyzer.h in Headers */,
 				FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
 				0F4680CA14BBB16C00BFE272 /* LLIntCommon.h in Headers */,
 				0F4680D314BBD16700BFE272 /* LLIntData.h in Headers */,
@@ -8852,6 +8868,7 @@
 				A79D3ED9C5064DD0A8466A3A /* ModuleScopeData.h in Headers */,
 				0F1FB3991E1F65FB00A9BE50 /* MutatorScheduler.h in Headers */,
 				0FA762071DB9243300B7A2FD /* MutatorState.h in Headers */,
+				FE3022D71E42857300BAC493 /* VMInspector.h in Headers */,
 				BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */,
 				BC02E9130E1839DB000F9297 /* NativeErrorPrototype.h in Headers */,
 				147341D01DC02DB400AA29BA /* NativeExecutable.h in Headers */,
@@ -9718,6 +9735,7 @@
 				0F9630391D4192C6005609D9 /* AllocatorAttributes.cpp in Sources */,
 				147F39BD107EC37600427A48 /* ArgList.cpp in Sources */,
 				79A228351D35D71E00D8E067 /* ArithProfile.cpp in Sources */,
+				FE3022D61E42857300BAC493 /* VMInspector.cpp in Sources */,
 				0F743BAA16B88249009F9277 /* ARM64Disassembler.cpp in Sources */,
 				86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */,
 				65C02850171795E200351E35 /* ARMv7Disassembler.cpp in Sources */,
@@ -10413,6 +10431,7 @@
 				79B00CBE1C6AB07E0088C65D /* ProxyObject.cpp in Sources */,
 				79160DBD1C8E3EC8008C085A /* ProxyRevoke.cpp in Sources */,
 				0F15CD221BA5F9860031FFD3 /* PutByIdFlags.cpp in Sources */,
+				FE3022D21E3D73A500BAC493 /* SigillCrashAnalyzer.cpp in Sources */,
 				0F9332A314CA7DD70085F3C6 /* PutByIdStatus.cpp in Sources */,
 				0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */,
 				0FF60AC316740F8800029779 /* ReduceWhitespace.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/assembler/ARM64Assembler.h (211602 => 211603)


--- trunk/Source/_javascript_Core/assembler/ARM64Assembler.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/assembler/ARM64Assembler.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014, 2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1084,6 +1084,12 @@
         insn(excepnGeneration(ExcepnOp_HALT, imm, 0));
     }
 
+    // Only used for testing purposes.
+    void illegalInstruction()
+    {
+        insn(0x0);
+    }
+
     template<int datasize>
     ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
     {

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (211602 => 211603)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2014-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012, 2014-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -441,6 +441,12 @@
         m_assembler.clz<64>(dest, dest);
     }
 
+    // Only used for testing purposes.
+    void illegalInstruction()
+    {
+        m_assembler.illegalInstruction();
+    }
+
     void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
     {
         m_assembler.lsl<32>(dest, src, shiftAmount);

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (211602 => 211603)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2014-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2014-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -327,6 +327,12 @@
         ctzAfterBsf<32>(dst);
     }
 
+    // Only used for testing purposes.
+    void illegalInstruction()
+    {
+        m_assembler.illegalInstruction();
+    }
+    
     void lshift32(RegisterID shift_amount, RegisterID dest)
     {
         if (shift_amount == X86Registers::ecx)

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (211602 => 211603)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2012-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -259,6 +259,7 @@
     } OneByteOpcodeID;
 
     typedef enum {
+        OP2_UD2             = 0xB,
         OP2_MOVSD_VsdWsd    = 0x10,
         OP2_MOVSD_WsdVsd    = 0x11,
         OP2_MOVSS_VsdWsd    = 0x10,
@@ -681,6 +682,12 @@
     }
 #endif // CPU(X86_64)
 
+    // Only used for testing purposes.
+    void illegalInstruction()
+    {
+        m_formatter.twoByteOp(OP2_UD2);
+    }
+
     void inc_r(RegisterID dst)
     {
         m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP1_OP_ADD, dst);

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (211602 => 211603)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2017-02-02 23:32:36 UTC (rev 211603)
@@ -2046,6 +2046,11 @@
     return m_codeBlocks->iterate(func);
 }
 
+void Heap::forEachCodeBlockIgnoringJITPlansImpl(const ScopedLambda<bool(CodeBlock*)>& func)
+{
+    return m_codeBlocks->iterate(func);
+}
+
 void Heap::writeBarrierSlowPath(const JSCell* from)
 {
     if (UNLIKELY(mutatorShouldBeFenced())) {

Modified: trunk/Source/_javascript_Core/heap/Heap.h (211602 => 211603)


--- trunk/Source/_javascript_Core/heap/Heap.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/heap/Heap.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -225,6 +225,7 @@
     
     template<typename Functor> void forEachProtectedCell(const Functor&);
     template<typename Functor> void forEachCodeBlock(const Functor&);
+    template<typename Functor> void forEachCodeBlockIgnoringJITPlans(const Functor&);
 
     HandleSet* handleSet() { return &m_handleSet; }
     HandleStack* handleStack() { return &m_handleStack; }
@@ -470,6 +471,7 @@
     size_t bytesVisited();
     
     void forEachCodeBlockImpl(const ScopedLambda<bool(CodeBlock*)>&);
+    void forEachCodeBlockIgnoringJITPlansImpl(const ScopedLambda<bool(CodeBlock*)>&);
     
     void setMutatorShouldBeFenced(bool value);
     

Modified: trunk/Source/_javascript_Core/heap/HeapInlines.h (211602 => 211603)


--- trunk/Source/_javascript_Core/heap/HeapInlines.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/heap/HeapInlines.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -173,6 +173,11 @@
     forEachCodeBlockImpl(scopedLambdaRef<bool(CodeBlock*)>(func));
 }
 
+template<typename Functor> inline void Heap::forEachCodeBlockIgnoringJITPlans(const Functor& func)
+{
+    forEachCodeBlockIgnoringJITPlansImpl(scopedLambdaRef<bool(CodeBlock*)>(func));
+}
+
 template<typename Functor> inline void Heap::forEachProtectedCell(const Functor& functor)
 {
     for (auto& pair : m_protectedValues)

Modified: trunk/Source/_javascript_Core/runtime/Options.cpp (211602 => 211603)


--- trunk/Source/_javascript_Core/runtime/Options.cpp	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/runtime/Options.cpp	2017-02-02 23:32:36 UTC (rev 211603)
@@ -28,6 +28,7 @@
 
 #include "LLIntCommon.h"
 #include "LLIntData.h"
+#include "SigillCrashAnalyzer.h"
 #include <algorithm>
 #include <limits>
 #include <math.h>
@@ -144,6 +145,10 @@
     if (id == maxSingleAllocationSizeID)
         return true;
 #endif
+#if OS(DARWIN)
+    if (id == useSigillCrashAnalyzerID)
+        return true;
+#endif
     return false;
 }
 
@@ -429,6 +434,8 @@
     else
         fastSetMaxSingleAllocationSize(std::numeric_limits<size_t>::max());
 #endif
+    if (Options::useSigillCrashAnalyzer())
+        enableSigillCrashAnalyzer();
 }
 
 void Options::initialize()

Modified: trunk/Source/_javascript_Core/runtime/Options.h (211602 => 211603)


--- trunk/Source/_javascript_Core/runtime/Options.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -399,6 +399,7 @@
     \
     v(bool, useDollarVM, false, Restricted, "installs the $vm debugging tool in global objects") \
     v(optionString, functionOverrides, nullptr, Restricted, "file with debugging overrides for function bodies") \
+    v(bool, useSigillCrashAnalyzer, false, Configurable, "logs data about SIGILL crashes") \
     \
     v(unsigned, watchdog, 0, Normal, "watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)") \
     \

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (211602 => 211603)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2017-02-02 23:32:36 UTC (rev 211603)
@@ -102,6 +102,7 @@
 #include "TypeProfilerLog.h"
 #include "UnlinkedCodeBlock.h"
 #include "VMEntryScope.h"
+#include "VMInspector.h"
 #include "Watchdog.h"
 #include "WeakGCMapInlines.h"
 #include "WeakMapData.h"
@@ -349,10 +350,14 @@
         Watchdog& watchdog = ensureWatchdog();
         watchdog.setTimeLimit(timeoutMillis);
     }
+
+    VMInspector::instance().add(this);
 }
 
 VM::~VM()
 {
+    VMInspector::instance().remove(this);
+
     // Never GC, ever again.
     heap.incrementDeferralDepth();
 

Modified: trunk/Source/_javascript_Core/runtime/VM.h (211602 => 211603)


--- trunk/Source/_javascript_Core/runtime/VM.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -61,6 +61,7 @@
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/DateMath.h>
 #include <wtf/Deque.h>
+#include <wtf/DoublyLinkedList.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
@@ -241,7 +242,7 @@
 #pragma warning(pop)
 #endif
 
-class VM : public ThreadSafeRefCounted<VM> {
+class VM : public ThreadSafeRefCounted<VM>, public DoublyLinkedListNode<VM> {
 public:
     // WebCore has a one-to-one mapping of threads to VMs;
     // either create() or createLeaked() should only be called once
@@ -778,11 +779,15 @@
     std::unique_ptr<ShadowChicken> m_shadowChicken;
     std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
 
+    VM* m_prev; // Required by DoublyLinkedListNode.
+    VM* m_next; // Required by DoublyLinkedListNode.
+
     // Friends for exception checking purpose only.
     friend class Heap;
     friend class CatchScope;
     friend class ExceptionScope;
     friend class ThrowScope;
+    friend class WTF::DoublyLinkedListNode<VM>;
 };
 
 #if ENABLE(GC_VALIDATION)

Added: trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.cpp (0 => 211603)


--- trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.cpp	2017-02-02 23:32:36 UTC (rev 211603)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SigillCrashAnalyzer.h"
+
+#include "CallFrame.h"
+#include "CodeBlock.h"
+#include "VMInspector.h"
+#include <mutex>
+#include <wtf/StdLibExtras.h>
+
+#if USE(ARM64_DISASSEMBLER)
+#include "A64DOpcode.h"
+#endif
+
+#if HAVE(SIGNAL_H)
+#include <signal.h>
+#endif
+
+namespace JSC {
+
+struct SignalContext;
+
+class SigillCrashAnalyzer {
+public:
+    static SigillCrashAnalyzer& instance();
+    void analyze(SignalContext&);
+
+private:
+    SigillCrashAnalyzer() { }
+    void dumpCodeBlock(CodeBlock*, void* machinePC);
+
+#if USE(ARM64_DISASSEMBLER)
+    A64DOpcode m_arm64Opcode;
+#endif
+};
+
+#if OS(DARWIN)
+
+#if USE(OS_LOG)
+
+#define log(format, ...) \
+    os_log_info(OS_LOG_DEFAULT, format, ##__VA_ARGS__)
+
+#else // USE(OS_LOG)
+
+#define log(format, ...) \
+    dataLogF(format, ##__VA_ARGS__)
+    
+#endif // USE(OS_LOG)
+
+#if CPU(X86_64)
+struct SignalContext {
+    SignalContext(mcontext_t& mcontext)
+        : mcontext(mcontext)
+        , machinePC(reinterpret_cast<void*>(mcontext->__ss.__rip))
+        , stackPointer(reinterpret_cast<void*>(mcontext->__ss.__rsp))
+        , framePointer(reinterpret_cast<CallFrame*>(mcontext->__ss.__rbp))
+    { }
+
+    void dump()
+    {
+#define FOR_EACH_REGISTER(v) \
+        v(rax) \
+        v(rbx) \
+        v(rcx) \
+        v(rdx) \
+        v(rdi) \
+        v(rsi) \
+        v(rbp) \
+        v(rsp) \
+        v(r8) \
+        v(r9) \
+        v(r10) \
+        v(r11) \
+        v(r12) \
+        v(r13) \
+        v(r14) \
+        v(r15) \
+        v(rip) \
+        v(rflags) \
+        v(cs) \
+        v(fs) \
+        v(gs)
+
+#define DUMP_REGISTER(__reg) \
+        log("Register " #__reg ": %p", reinterpret_cast<void*>(mcontext->__ss.__##__reg));
+        FOR_EACH_REGISTER(DUMP_REGISTER)
+#undef FOR_EACH_REGISTER
+    }
+
+    mcontext_t& mcontext;
+    void* machinePC;
+    void* stackPointer;
+    void* framePointer;
+};
+
+#elif CPU(ARM64)
+
+struct SignalContext {
+    SignalContext(mcontext_t& mcontext)
+        : mcontext(mcontext)
+        , machinePC(reinterpret_cast<void*>(mcontext->__ss.__pc))
+        , stackPointer(reinterpret_cast<void*>(mcontext->__ss.__sp))
+        , framePointer(reinterpret_cast<CallFrame*>(mcontext->__ss.__fp))
+    { }
+
+    void dump()
+    {
+        int i;
+        for (i = 0; i < 28; i += 4) {
+            log("x%d: %016llx x%d: %016llx x%d: %016llx x%d: %016llx",
+                i, mcontext->__ss.__x[i],
+                i+1, mcontext->__ss.__x[i+1],
+                i+2, mcontext->__ss.__x[i+2],
+                i+3, mcontext->__ss.__x[i+3]);
+        }
+        ASSERT(i < 29);
+        log("x%d: %016llx fp: %016llx lr: %016llx",
+            i, mcontext->__ss.__x[i], mcontext->__ss.__fp, mcontext->__ss.__lr);
+        log("sp: %016llx pc: %016llx cpsr: %08x",
+            mcontext->__ss.__sp, mcontext->__ss.__pc, mcontext->__ss.__cpsr);
+    }
+
+    mcontext_t& mcontext;
+    void* machinePC;
+    void* stackPointer;
+    void* framePointer;
+};
+
+#else
+
+struct SignalContext {
+    SignalContext(mcontext_t&) { }
+    
+    void dump() { }
+    
+    void* machinePC;
+    void* stackPointer;
+    void* framePointer;
+};
+    
+#endif
+
+struct sigaction oldSigIllAction;
+
+static void handleCrash(int, siginfo_t*, void* uap)
+{
+    sigaction(SIGILL, &oldSigIllAction, nullptr);
+
+    SignalContext context(static_cast<ucontext_t*>(uap)->uc_mcontext);
+    SigillCrashAnalyzer& analyzer = SigillCrashAnalyzer::instance();
+    analyzer.analyze(context);
+}
+
+static void installCrashHandler()
+{
+#if CPU(X86_64) || CPU(ARM64)
+    struct sigaction action;
+    action.sa_sigaction = reinterpret_cast<void (*)(int, siginfo_t *, void *)>(handleCrash);
+    sigfillset(&action.sa_mask);
+    action.sa_flags = SA_SIGINFO;
+    sigaction(SIGILL, &action, &oldSigIllAction);
+#else
+    UNUSED_PARAM(handleCrash);
+#endif
+}
+
+#else // OS(DARWIN)
+
+#define log(format, ...) do { } while (false)
+    
+struct SignalContext {
+    SignalContext() { }
+
+    void dump() { }
+
+    void* machinePC;
+    void* stackPointer;
+    void* framePointer;
+};
+
+static void installCrashHandler()
+{
+    // Do nothing. Not supported for this platform.
+}
+
+#endif // OS(DARWIN)
+
+SigillCrashAnalyzer& SigillCrashAnalyzer::instance()
+{
+    static SigillCrashAnalyzer* analyzer;
+    static std::once_flag once;
+    std::call_once(once, [] {
+        installCrashHandler();
+        analyzer = new SigillCrashAnalyzer;
+    });
+    return *analyzer;
+}
+
+void enableSigillCrashAnalyzer()
+{
+    // Just instantiating the SigillCrashAnalyzer will enable it.
+    SigillCrashAnalyzer::instance();
+}
+
+void SigillCrashAnalyzer::analyze(SignalContext& context)
+{
+    log("BEGIN SIGILL analysis");
+
+    [&] () {
+        // First, dump the signal context info so that we'll at least have the same info
+        // that the default crash handler would given us in case this crash analyzer
+        // itself crashes.
+        context.dump();
+
+        VMInspector& inspector = VMInspector::instance();
+
+        // Use a timeout period of 2 seconds. The client is about to crash, and we don't
+        // want to turn the crash into a hang by re-trying the lock for too long.
+        auto expectedLockToken = inspector.lock(Seconds(2));
+        if (!expectedLockToken) {
+            ASSERT(expectedLockToken.error() == VMInspector::Error::TimedOut);
+            log("ERROR: Unable to analyze SIGILL. Timed out while waiting to iterate VMs.");
+            return;
+        }
+        auto lockToken = expectedLockToken.value();
+
+        void* pc = context.machinePC;
+        auto isInJITMemory = inspector.isValidExecutableMemory(lockToken, pc);
+        if (!isInJITMemory) {
+            log("ERROR: Timed out: not able to determine if pc %p is in valid JIT executable memory", pc);
+            return;
+        }
+        if (!isInJITMemory.value()) {
+            log("pc %p is NOT in valid JIT executable memory", pc);
+            return;
+        }
+        log("pc %p is in valid JIT executable memory", pc);
+
+#if CPU(ARM64)
+        size_t pcAsSize = reinterpret_cast<size_t>(pc);
+        if (pcAsSize != roundUpToMultipleOf<sizeof(uint32_t)>(pcAsSize)) {
+            log("pc %p is NOT properly aligned", pc);
+            return;
+        }
+
+        // We know it's safe to read the word at the PC because we're handling a SIGILL.
+        // Otherwise, we would have crashed with a SIGBUS instead.
+        uint32_t wordAtPC = *reinterpret_cast<uint32_t*>(pc);
+        log("instruction bits at pc %p is: 0x%08x", pc, wordAtPC);
+#endif
+
+        auto expectedCodeBlock = inspector.codeBlockForMachinePC(lockToken, pc);
+        if (!expectedCodeBlock) {
+            if (expectedCodeBlock.error() == VMInspector::Error::TimedOut)
+                log("ERROR: Timed out: not able to determine if pc %p is in a valid CodeBlock", pc);
+            else
+                log("The current thread does not own any VM JSLock");
+            return;
+        }
+        CodeBlock* codeBlock = expectedCodeBlock.value();
+        if (!codeBlock) {
+            log("machine PC %p does not belong to any CodeBlock in the currently entered VM", pc);
+            return;
+        }
+
+        log("pc %p belongs to CodeBlock %p of type %s", pc, codeBlock, JITCode::typeName(codeBlock->jitType()));
+
+        dumpCodeBlock(codeBlock, pc);
+    } ();
+
+    log("END SIGILL analysis");
+}
+
+void SigillCrashAnalyzer::dumpCodeBlock(CodeBlock* codeBlock, void* machinePC)
+{
+#if CPU(ARM64)
+    JITCode* jitCode = codeBlock->jitCode().get();
+
+    // Dump the raw bits of the code.
+    uint32_t* start = reinterpret_cast<uint32_t*>(jitCode->start());
+    uint32_t* end = reinterpret_cast<uint32_t*>(jitCode->end());
+    log("JITCode %p [%p-%p]:", jitCode, start, end);
+    if (start < end) {
+        uint32_t* p = start;
+        while (p + 8 <= end) {
+            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]);
+            p += 8;
+        }
+        if (p + 7 <= end)
+            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]);
+        else if (p + 6 <= end)
+            log("[%p-%p]: %08x %08x %08x %08x %08x %08x", p, p+5, p[0], p[1], p[2], p[3], p[4], p[5]);
+        else if (p + 5 <= end)
+            log("[%p-%p]: %08x %08x %08x %08x %08x", p, p+4, p[0], p[1], p[2], p[3], p[4]);
+        else if (p + 4 <= end)
+            log("[%p-%p]: %08x %08x %08x %08x", p, p+3, p[0], p[1], p[2], p[3]);
+        if (p + 3 <= end)
+            log("[%p-%p]: %08x %08x %08x", p, p+2, p[0], p[1], p[2]);
+        else if (p + 2 <= end)
+            log("[%p-%p]: %08x %08x", p, p+1, p[0], p[1]);
+        else if (p + 1 <= end)
+            log("[%p-%p]: %08x", p, p, p[0]);
+    }
+
+    // Dump the disassembly of the code.
+    log("Disassembly:");
+    uint32_t* currentPC = reinterpret_cast<uint32_t*>(jitCode->executableAddress());
+    size_t byteCount = jitCode->size();
+    while (byteCount) {
+        char pcString[24];
+        if (currentPC == machinePC) {
+            snprintf(pcString, sizeof(pcString), "* 0x%lx", reinterpret_cast<unsigned long>(currentPC));
+            log("%20s: %s    <=========================", pcString, m_arm64Opcode.disassemble(currentPC));
+        } else {
+            snprintf(pcString, sizeof(pcString), "0x%lx", reinterpret_cast<unsigned long>(currentPC));
+            log("%20s: %s", pcString, m_arm64Opcode.disassemble(currentPC));
+        }
+        currentPC++;
+        byteCount -= sizeof(uint32_t);
+    }
+#else
+    UNUSED_PARAM(codeBlock);
+    UNUSED_PARAM(machinePC);
+    // Not implemented yet.
+#endif
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.h (0 => 211603)


--- trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/tools/SigillCrashAnalyzer.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+namespace JSC {
+
+// Enables the SIGILL crash analyzer. This is a one way trip. There's no going back.
+void enableSigillCrashAnalyzer();
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/tools/VMInspector.cpp (0 => 211603)


--- trunk/Source/_javascript_Core/tools/VMInspector.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/tools/VMInspector.cpp	2017-02-02 23:32:36 UTC (rev 211603)
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "VMInspector.h"
+
+#include "CodeBlock.h"
+#include "CodeBlockSet.h"
+#include "HeapInlines.h"
+#include <mutex>
+#include <wtf/Expected.h>
+
+#if !OS(WINDOWS)
+#include <unistd.h>
+#endif
+
+namespace JSC {
+
+VMInspector& VMInspector::instance()
+{
+    static VMInspector* manager;
+    static std::once_flag once;
+    std::call_once(once, [] {
+        manager = new VMInspector();
+    });
+    return *manager;
+}
+
+void VMInspector::add(VM* vm)
+{
+    auto locker = holdLock(m_lock);
+    m_list.append(vm);
+}
+
+void VMInspector::remove(VM* vm)
+{
+    auto locker = holdLock(m_lock);
+    m_list.remove(vm);
+}
+
+auto VMInspector::lock(Seconds timeout) -> Expected<LockToken, Error>
+{
+    // This function may be called from a signal handler (e.g. via visit()). Hence,
+    // it should only use APIs that are safe to call from signal handlers. This is
+    // why we use unistd.h's sleep() instead of its alternatives.
+
+    // We'll be doing sleep(1) between tries below. Hence, sleepPerRetry is 1.
+    unsigned maxRetries = (timeout < Seconds::infinity()) ? timeout.value() : UINT_MAX;
+
+    bool locked = m_lock.tryLock();
+    unsigned tryCount = 0;
+    while (!locked && tryCount < maxRetries) {
+        // We want the version of sleep from unistd.h. Cast to disambiguate.
+#if !OS(WINDOWS)
+        (static_cast<unsigned (*)(unsigned)>(sleep))(1);
+#endif
+        locked = m_lock.tryLock();
+    }
+
+    if (!locked)
+        return makeUnexpected(Error::TimedOut);
+    return LockToken::LockedValue;
+}
+
+static bool ensureIsSafeToLock(Lock& lock)
+{
+    unsigned maxRetries = 2;
+    unsigned tryCount = 0;
+    while (tryCount <= maxRetries) {
+        bool success = lock.tryLock();
+        if (success) {
+            lock.unlock();
+            return true;
+        }
+        tryCount++;
+    }
+    return false;
+};
+
+auto VMInspector::isValidExecutableMemory(VMInspector::LockToken, void* machinePC) -> Expected<bool, Error>
+{
+    bool found = false;
+    bool hasTimeout = false;
+    iterate([&] (VM& vm) -> FunctorStatus {
+        auto allocator = vm.executableAllocator;
+        auto& lock = allocator.getLock();
+
+        bool isSafeToLock = ensureIsSafeToLock(lock);
+        if (!isSafeToLock) {
+            hasTimeout = true;
+            return FunctorStatus::Continue; // Skip this VM.
+        }
+
+        LockHolder executableAllocatorLocker(lock);
+        if (allocator.isValidExecutableMemory(executableAllocatorLocker, machinePC)) {
+            found = true;
+            return FunctorStatus::Done;
+        }
+        return FunctorStatus::Continue;
+    });
+
+    if (!found && hasTimeout)
+        return makeUnexpected(Error::TimedOut);
+    return found;
+}
+
+auto VMInspector::codeBlockForMachinePC(VMInspector::LockToken, void* machinePC) -> Expected<CodeBlock*, Error>
+{
+    CodeBlock* codeBlock = nullptr;
+    bool hasTimeout = false;
+    iterate([&] (VM& vm) {
+        if (!vm.apiLock().currentThreadIsHoldingLock())
+            return FunctorStatus::Continue;
+
+        // It is safe to call Heap::forEachCodeBlockIgnoringJITPlans here because:
+        // 1. CodeBlocks are added to the CodeBlockSet from the main thread before
+        //    they are handed to the JIT plans. Those codeBlocks will have a null jitCode,
+        //    but we check for that in our lambda functor.
+        // 2. CodeBlockSet::iterate() will acquire the CodeBlockSet lock before iterating.
+        //    This ensures that a CodeBlock won't be GCed while we're iterating.
+        // 3. We do a tryLock on the CodeBlockSet's lock first to ensure that it is
+        //    safe for the current thread to lock it before calling
+        //    Heap::forEachCodeBlockIgnoringJITPlans(). Hence, there's no risk of
+        //    re-entering the lock and deadlocking on it.
+
+        auto& lock = vm.heap.codeBlockSet().getLock();
+        bool isSafeToLock = ensureIsSafeToLock(lock);
+        if (!isSafeToLock) {
+            hasTimeout = true;
+            return FunctorStatus::Continue; // Skip this VM.
+        }
+
+        vm.heap.forEachCodeBlockIgnoringJITPlans([&] (CodeBlock* cb) {
+            JITCode* jitCode = cb->jitCode().get();
+            if (!jitCode) {
+                // If the codeBlock is a replacement codeBlock which is in the process of being
+                // compiled, its jitCode will be null, and we can disregard it as a match for
+                // the machinePC we're searching for.
+                return false;
+            }
+
+            if (!JITCode::isJIT(jitCode->jitType()))
+                return false;
+
+            if (jitCode->contains(machinePC)) {
+                codeBlock = cb;
+                return true;
+            }
+            return false;
+        });
+        if (codeBlock)
+            return FunctorStatus::Done;
+        return FunctorStatus::Continue;
+    });
+
+    if (!codeBlock && hasTimeout)
+        return makeUnexpected(Error::TimedOut);
+    return codeBlock;
+}
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/tools/VMInspector.h (0 => 211603)


--- trunk/Source/_javascript_Core/tools/VMInspector.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/tools/VMInspector.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "VM.h"
+#include <wtf/DoublyLinkedList.h>
+#include <wtf/Expected.h>
+#include <wtf/Lock.h>
+
+namespace JSC {
+
+class VMInspector {
+public:
+    enum class Error {
+        None,
+        TimedOut
+    };
+
+    enum class LockToken { LockedValue };
+
+    static VMInspector& instance();
+
+    void add(VM*);
+    void remove(VM*);
+
+    Expected<LockToken, Error> lock(Seconds timeout = Seconds::infinity());
+
+    Expected<bool, Error> isValidExecutableMemory(LockToken, void*);
+    Expected<CodeBlock*, Error> codeBlockForMachinePC(LockToken, void*);
+
+private:
+    enum class FunctorStatus {
+        Continue,
+        Done
+    };
+    template <typename Functor> void iterate(const Functor& functor)
+    {
+        for (VM* vm = m_list.head(); vm; vm = vm->next()) {
+            FunctorStatus status = functor(*vm);
+            if (status == FunctorStatus::Done)
+                return;
+        }
+    }
+
+    Lock m_lock;
+    DoublyLinkedList<VM> m_list;
+};
+
+} // namespace JSC

Modified: trunk/Source/WTF/ChangeLog (211602 => 211603)


--- trunk/Source/WTF/ChangeLog	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/WTF/ChangeLog	2017-02-02 23:32:36 UTC (rev 211603)
@@ -1,3 +1,13 @@
+2017-02-02  Mark Lam  <[email protected]>
+
+        Add a SIGILL crash analyzer to make debugging SIGILLs easier.
+        https://bugs.webkit.org/show_bug.cgi?id=167714
+        <rdar://problem/30318237>
+
+        Reviewed by Filip Pizlo.
+
+        * wtf/StdLibExtras.h:
+
 2017-02-02  Commit Queue  <[email protected]>
 
         Unreviewed, rolling out r211571 and r211582.

Modified: trunk/Source/WTF/wtf/StdLibExtras.h (211602 => 211603)


--- trunk/Source/WTF/wtf/StdLibExtras.h	2017-02-02 23:31:02 UTC (rev 211602)
+++ trunk/Source/WTF/wtf/StdLibExtras.h	2017-02-02 23:32:36 UTC (rev 211603)
@@ -489,6 +489,7 @@
 using WTF::isPointerAligned;
 using WTF::isStatelessLambda;
 using WTF::is8ByteAligned;
+using WTF::roundUpToMultipleOf;
 using WTF::safeCast;
 using WTF::tryBinarySearch;
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to