How to Enable and Use JavaScriptCore Debugger on iOS: A Step‑by‑Step Guide
Learn how to unlock JavaScriptCore's hidden debugger on iOS by locating the framework version, building the source with private headers, creating a custom Debugger subclass, and integrating it into an Xcode project, complete with code examples and configuration tips.
JSC's debugger is a little‑known feature, especially on iOS where the Objective‑C interface does not expose any debugger information.
Because JavaScriptCore is open source, you can locate the
JSC::Debuggerabstract class, subclass it, implement the required virtual methods, instantiate it, and attach the instance to the global object to gain debugging capabilities.
On iOS the JavaScriptCore library is delivered as a framework, so only public headers and a static library are available. To use the debugger you must:
Compile with the private headers that match the framework version and use identical compile options.
Link against the framework's internal methods.
Solution steps:
Check the JSC version inside the framework.
Find the matching source code for that version.
Build JavaScriptCore to obtain the private headers.
Create a new Xcode project and add the private headers.
Adjust macros and compile options.
Write the debugger subclass and integration code.
Check JSC Version in the Framework
The framework resides in
/System/Library/Frameworks/JavaScriptCore.framework/. Open the
version.plistfile to read the current version (e.g., 604.4.7.1.3 in Xcode 9.2).
Download Source Code
Visit https://svn.webkit.org/repository/webkit/tags and download the source tree for the identified version. You only need the
bmalloc,
WTF, and
JavaScriptCoredirectories.
Build JSC
Create an Xcode workspace, drag the three projects into it, and build them in order:
bmalloc,
WTF, then
JavaScriptCore. Build for the macOS target (the default) to obtain the headers; you do not need an iOS build.
Create New Project
Start a new iOS project (any name) and add the private headers you copied from the built JSC project (
PrivateHeadersand
WTF/include/wtf) to your project’s include path.
Other C++ flags:
-std=c++14Enable C++ runtime types:
NoSystem header search path:
$(PRODUCT_NAME)/Set the required preprocessor macros (e.g.,
ENABLE_3D_TRANSFORMS,
ENABLE_ACCELERATED_OVERFLOW_SCROLLING, …) to match the framework build.
Write the Debugger Subclass
<code>#import <JavaScriptCore/JavaScriptCore.h>
#import "JavaScriptCore/HeapInlines.h"
#import "JavaScriptCore/HeapCellInlines.h"
#import "JavaScriptCore/APICast.h"
#import "JavaScriptCore/Debugger.h"
#import "JavaScriptCore/SourceProvider.h"
#import "JavaScriptCore/JSRunLoopTimer.h"
#import "JavaScriptCore/JSVirtualMachineInternal.h"
class MyDebugger : public JSC::Debugger {
public:
MyDebugger(JSC::VM& vm) : JSC::Debugger(vm) {}
virtual ~MyDebugger() { JSC::Debugger::~Debugger(); }
virtual void sourceParsed(JSC::ExecState* state, JSC::SourceProvider* sourceProvider, int errorLineNumber, const WTF::String& errorMessage) {
// Custom handling of parsed source
NSLog(@"sourceParsed");
}
virtual void handleBreakpointHit(JSC::JSGlobalObject*, const JSC::Breakpoint&) {
NSLog(@"handleBreakpointHit");
}
virtual void handleExceptionInBreakpointCondition(JSC::ExecState*, JSC::Exception*) const {
NSLog(@"handleExceptionInBreakpointCondition");
}
virtual void handlePause(JSC::JSGlobalObject* globalObject, ReasonForPause reason) {
NSLog(@"handlePause");
}
virtual void notifyDoneProcessingDebuggerEvents() {
NSLog(@"notifyDoneProcessingDebuggerEvents");
}
};
</code>Use the debugger in your code:
<code>JSContext* jsContext = [[JSContext alloc] init];
JSGlobalContextRef globalContext = [jsContext JSGlobalContextRef];
JSC::ExecState* es = toJS(globalContext);
JSC::JSGlobalObject* globalObject = es->vmEntryGlobalObject();
MyDebugger* debugger = new MyDebugger(globalObject->vm());
globalObject->setDebugger(static_cast<JSC::Debugger*>(debugger));
debugger->setPauseOnNextStatement(true);
globalObject->vm().heap().acquireAccess();
debugger->activateBreakpoints();
globalObject->vm().heap().releaseAccess();
[jsContext evaluateScript:@"debugger;"];
</code>This sequence creates a JavaScript context, retrieves the underlying JSC objects, installs the custom debugger, enables breakpoints, and finally runs a script that triggers the debugger.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.