实现一个 JavaScriptCore 的 debugger —— iOS 篇

简介: JSC 的 debugger 是个神奇的东西,在网上资料甚少,几乎完全搜索不到,尤其是 iOS 上,OC 接口没有暴露任何 debugger 信息。 不过好在 JSC 是开源的,通过分析源代码可以找到 JSC::Debugger 这个抽象类,我们继承这个抽象类,然后实现掉虚函数,创建实例并且把它挂载到 global object 即可开启 debug 能力了。

JSC 的 debugger 是个神奇的东西,在网上资料甚少,几乎完全搜索不到,尤其是 iOS 上,OC 接口没有暴露任何 debugger 信息。

不过好在 JSC 是开源的,通过分析源代码可以找到 JSC::Debugger 这个抽象类,我们继承这个抽象类,然后实现掉虚函数,创建实例并且把它挂载到 global object 即可开启 debug 能力了。

思路是简单的,在 iOS 设备上,我们要面临的另一个问题是它的 JavaScriptCore 本身是以 Framework 的形式而非源代码形式提供的,所以我们只有公开的 OC 头文件和静态库文件。

所以要想使用 debugger,我们需要:

1 编译时使用私有的头文件
确保头文件的版本跟 framework 一致
确保编译选项跟 framework 一致
2 链接时链接 framwork 中的方法

如何解决呢?步骤如下:

1 查看 framework 中的 JSC 版本
3 根据 JSC 版本,找到对应的源代码
4 构建 JSC 获取私有头文件
5 建立新项目,引入私有 JSC 头文件
6 调整宏和编译选项
7 编写代码

查看 framework 中的 JSC 版本

framework 是一个文件夹(在 XCode 中右键即可打开),可以从tbd 文件中找到系统中库的路径(一般是 /System/Library/Frameworks/JavaScriptCore.framework/ ),然后从 version.plist 中找到当前版本。

在我的 XCode9.2中,找到的版本是 604.4.7.1.3。

下载源代码

在https://svn.webkit.org/repository/webkit/tags 可以找到对应的源代码。

注意一般 opensource.apple.com 中找不到对应版本。

我们并不需要整个 webkit 代码,所以只要下载 source 目录下的 bmalloc, WTF 和 JavaScriptCore 三个项目就够了。

构建 JSC

首先我们需要建立一个 workspace,然后把三个项目文件拖进 workspace。

依次构建 bmalloc、WTF 和 JavaScriptCore 三个项目即可。

如果配置正确,构建 JSC 应该不会遇到什么困难。

我们只需要构建好的头文件,所以不需要选择 iOS 设备,使用默认的 mac 作为目标就好了。

建立新项目

接下来我们要建立一个 Debugger 项目,随便叫什么名字,选择 iOS 项目。

我们需要调整编译选项:

  • other C++ flags: -std=c++14
  • enable C++ runtime Types: No
  • system header search path: $(PRODUCT_NAME)/
  • Processor Macros:(太多了,建议直接到项目文件源代码里修改)

ENABLE3DTRANSFORMS, ENABLEACCELERATEDOVERFLOWSCROLLING, ENABLEAPPLEPAY,
ENABLEAPPLEPAYSESSIONV3, ENABLEATTACHMENTELEMENT, ENABLEAVFCAPTIONS, 
ENABLECACHEPARTITIONING, ENABLECANVASPATH, ENABLECANVASPROXY, 
ENABLECHANNELMESSAGING, ENABLECONTENTFILTERING, ENABLECSSANIMATIONSLEVEL2,
ENABLECSSBOXDECORATIONBREAK, ENABLECSSCOMPOSITING, ENABLECSSDEVICEADAPTATION,
ENABLECSSIMAGEORIENTATION, ENABLECSSIMAGERESOLUTION, ENABLECSSREGIONS, 
ENABLECSSSCROLLSNAP, ENABLECSSSELECTORSLEVEL4, ENABLECSSTRAILINGWORD,
ENABLECSS3TEXT, ENABLECURSORVISIBILITY, ENABLECUSTOMSCHEMEHANDLER, 
ENABLEDASHBOARDSUPPORT, ENABLEDATAINTERACTION, ENABLEDATATRANSFERITEMS,
ENABLEDATACUEVALUE, ENABLEDATALISTELEMENT, ENABLEDEVICEORIENTATION,
ENABLEDRAGSUPPORT, ENABLEENCRYPTEDMEDIA, ENABLEFETCHAPI, ENABLEFILTERSLEVEL2,
ENABLEFTLJIT, ENABLEFULLSCREENAPI, ENABLEGAMEPADDEPRECATED, ENABLEGAMEPAD,
ENABLEGEOLOCATION, ENABLEICONDATABASE, ENABLEINDEXEDDATABASEINWORKERS,
ENABLEINDEXEDDATABASE, ENABLEINPUTTYPECOLORPOPOVER, ENABLEINPUTTYPECOLOR,
ENABLEINPUTTYPEDATE, ENABLEINPUTTYPEDATETIMEINCOMPLETE, ENABLEINPUTTYPEDATETIMELOCAL,
ENABLEINPUTTYPEMONTH, ENABLEINPUTTYPETIME, ENABLEINPUTTYPEWEEK, ENABLEINTERSECTIONOBSERVER, 
ENABLEINTL, ENABLEIOSGESTUREEVENTS, ENABLEIOSTOUCHEVENTS, ENABLEJIT, 
ENABLEKEYBOARDKEYATTRIBUTE, ENABLEKEYBOARDCODEATTRIBUTE, ENABLELEGACYCSSVENDORPREFIXES,
ENABLELEGACYENCRYPTEDMEDIA, ENABLELEGACYVENDORPREFIXES, ENABLELETTERPRESS, 
ENABLELINKPREFETCH, ENABLEMACGESTUREEVENTS, ENABLEMATHML, ENABLEMEDIACAPTURE, 
ENABLEMEDIACONTROLSSCRIPT, ENABLEMEDIASESSION, ENABLEMEDIASOURCE, ENABLEMEDIASTATISTICS,
ENABLEMEDIASTREAM, ENABLEMETERELEMENT, ENABLEMHTML, ENABLEMOUSECURSORSCALE,
ENABLENAVIGATORCONTENTUTILS, ENABLENAVIGATORSTANDALONE, ENABLENOTIFICATIONS, 
ENABLEPDFKITPLUGIN, ENABLEPOINTERLOCK, ENABLEPROXIMITYEVENTS, ENABLEPUBLICSUFFIXLIST,
ENABLEQUOTA, ENABLEREMOTEINSPECTOR, ENABLEREQUESTAUTOCOMPLETE, ENABLERESOLUTIONMEDIAQUERY, 
ENABLERESOURCEUSAGE, ENABLERUBBERBANDING, ENABLESERVICECONTROLS, ENABLESPEECHSYNTHESIS, 
ENABLESTREAMSAPI, ENABLESUBTLECRYPTO, ENABLESVGFONTS, ENABLETELEPHONENUMBERDETECTION, 
ENABLETEXTAUTOSIZING, ENABLETOUCHEVENTS, ENABLETOUCHICONLOADING, ENABLEUSERSELECTALL, 
ENABLEVARIATIONFONTS, ENABLEVIDEOPRESENTATIONMODE, ENABLEMACVIDEOTOOLBOX, ENABLEVIDEOTRACK, 
ENABLEVIDEO, ENABLEVIEWMODECSSMEDIA, ENABLEWEBANIMATIONS, ENABLEWEBAUDIO, ENABLEWEBRTC, 
ENABLEWEBSOCKETS, ENABLEWEBTIMING, ENABLEWEBGL, ENABLEWEBGL2, ENABLEWEBGPU, 
ENABLEWIRELESSPLAYBACKTARGET, ENABLEXSLTFASTJITPERMISSIONS

然后我们打开构建好的 JSC 项目目标, 复制其中 PrivateHeaders 目录,到项目目录的 JavaScriptCore 目录。

再打开 WTF 项目目标, 复制目录下 /usr/local/include/wtf

接下来,我们需要对源代码做一下小修改,因为系统的 JSC 是在非 debug 模式下编译的,所以我们强行把头文件中跟 debug 相关的代码改成非 debug 模式:

JavaScriptCore/HandleStack.

所有
 
#ifdef
 NDEBUG

WTF/hashtable.h


#ifdef
 NDEBUG

#define
 CHECK_HASHTABLE_ITERATORS 
0

#define
 CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 
0

#else


#define
 CHECK_HASHTABLE_ITERATORS 
0


#define
 CHECK_HASHTABLE_USE_AFTER_DESTRUCTION 
0


#endif

编写代码

代码必须使用 .mm 文件。

我们需要在项目的 build phases 中加入 JavaScriptCore.framework。


#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
::
Debugger
(
vm
){


    
}



    
virtual
 
~
MyDebugger
(){

        JSC
::
Debugger
::~
Debugger
();

    
}


    
/*virtual void recompileAllJSFunctions() {

        //JSC::Debugger::recompileAllJSFunctions();

    }*/

    
virtual
 
void
 sourceParsed
(
JSC
::
ExecState
*
 state
,
 JSC
::
SourceProvider
*
 sourceProvider
,
 
int
 errorLineNumber
,
 
const
 WTF
::
String
&
 errorMessage
)
 
{

        
//StringView sourceString = sourceProvider->source();


        
//NSLog(@"sourceParsed:%@", (NSString*)sourceString.toString());

        
NSLog
(@
"sourceParsed"
);

        
return
;

    
};

    
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"
);

    
}

};


使用示例:



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;"
];





原文发布时间为:2018-02-06

本文作者:寒泉

本文来自云栖社区合作伙伴“淘宝技术”,了解相关信息可以关注“淘宝技术”微信公众号

相关文章
|
27天前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
83 3
|
3月前
|
存储 iOS开发
iOS 开发,如何进行应用的本地化(Localization)?
iOS 开发,如何进行应用的本地化(Localization)?
122 2
|
3月前
|
存储 数据建模 数据库
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
38 0
|
3月前
|
安全 编译器 Swift
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
IOS开发基础知识: 对比 Swift 和 Objective-C 的优缺点。
89 2
|
3月前
|
API 开发工具 iOS开发
iOS 开发高效率工具包:10 大必备工具
iOS 开发高效率工具包:10 大必备工具
42 1
|
3月前
|
API 数据安全/隐私保护 iOS开发
利用uni-app 开发的iOS app 发布到App Store全流程
利用uni-app 开发的iOS app 发布到App Store全流程
52 1
|
1天前
|
API 定位技术 iOS开发
IOS开发基础知识:什么是 Cocoa Touch?它在 iOS 开发中的作用是什么?
【4月更文挑战第18天】**Cocoa Touch** 是iOS和Mac OS X应用的核心框架,包含面向对象库、运行时系统和触摸优化工具。它提供Mac验证的开发模式,强调触控接口和性能,涵盖3D图形、音频、网络及设备访问API,如相机和GPS。是构建高效iOS应用的基础,对开发者至关重要。
8 0
|
16天前
|
开发工具 Swift iOS开发
利用SwiftUI构建动态用户界面:iOS开发新范式
【4月更文挑战第3天】 随着苹果不断推进其软件开发工具的边界,SwiftUI作为一种新兴的编程框架,已经逐渐成为iOS开发者的新宠。不同于传统的UIKit,SwiftUI通过声明式语法和强大的功能组合,为创建动态且响应式的用户界面提供了一种更加简洁高效的方式。本文将深入探讨如何利用SwiftUI技术构建具有高度自定义能力和响应性的用户界面,并展示其在现代iOS应用开发中的优势和潜力。
|
2月前
|
监控 API Swift
用Swift开发iOS平台上的上网行为管理监控软件
在当今数字化时代,随着智能手机的普及,人们对于网络的依赖日益增加。然而,对于一些特定场景,如家庭、学校或者企业,对于iOS设备上的网络行为进行管理和监控显得尤为重要。为了满足这一需求,我们可以利用Swift语言开发一款iOS平台上的上网行为管理监控软件。
181 2
|
3月前
|
数据可视化 iOS开发
iOS 开发,什么是 Interface Builder(IB)?如何使用 IB 构建用户界面?
iOS 开发,什么是 Interface Builder(IB)?如何使用 IB 构建用户界面?
40 4