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;