js array formdata_js与d8调试原理(1)

js层面和d8调试技巧以及底层原理

这个大主题会分两个小专题叙述,因为js层面的调试和c++的调试有很大不同,这一篇文章会先从js的调试谈起,揭秘我们日常nodejs调试时,发生了什么? 为了与时俱进,我这边就只讲目前最流行的V8 Inspector,在开始之前,我先抛出几个问题,让我们带着疑问去看完这篇文章:

  1. 当我们输入--inspector去启动node进程时,chrome dev tool 或者 开发IDE(比如说VScode)是怎么实现与node内置的debugger端交互通信的?
  2. 交互通信的内容是什么?
  3. 看完了这篇文章后,你是否有能力自己实现一个client代替其他调试客户端(chrome dev tool 或者 开发IDE(比如说VScode))来调试nodejs代码?

ok,让我们带着这几个问题开始揭秘吧。

ps:本文作为先导文不会太深究node::inpector等模块下的实现细节,不会去介绍进程调试session的概念,单纯从发生的现象来谈实现过程,很细节的部分放到后面的文章来叙述。

准备工作

假设我们有一份index.js代码需要被调试,大致内容如下:

console.log(

开始动手

目前为止,我们还没有设置任何断点,为了让脚本可以直接停止被编译执行,我们直接用--inspect-brk暂停脚本:node --inspect-brk=9222 index

这个时候终端上会有类似这样的输出:

Debugger listening on ws://127.0.0.1:9222/8c34ca65-fa52-4fef-81b1-e0e4f8453de0
第一个问题

问: 当我们输入--inspector去启动node进程时,chrome dev tool 或者 开发IDE(比如说VScode)是怎么实现与node内置的debugger端交互通信的?

答:

  1. 第一行的文本的输出:Debugger listening on ws://127.0.0.1:9222/8c34ca65-fa52-4fef-81b1-e0e4f8453de0nodejs启动了一个Debugger端进程,它监听着9222端口,并且应用层协议是ws。我们猜想它是通过ws进行通信的,其实事实上就是基于ws通信的.
  2. 至于为什么要选用ws,这其实和Chrome DevTools Protocol有很大的关系,搞调试的那批人,想要复用Chrome DevToolsnodejs进行调试,这个时候传统的http协议就存在跨域的问题,ws跨域绕过去,所以就选了ws
第二个问题

问:交互通信的内容是什么?

答:我们在上一个问题的回答中提到了V8 Inspector Protocol的诞生其实是为了让nodejs的调试能完美配合Chrome DevTools一起使用,其目的之一是为了增加可移植性。为了证实V8 InspectorChrome DevTools Protocol是息息相关的,我将在接下来的实战中,会向debugger端,发送一些Chrome DevTools Protocol格式的消息,用来启动调试,控制调试等。所以尽管你可能不太了解Chrome DevTools Protocol,没关系,如果在文中看到一些陌生的名词,建议你直接谷歌,八成就是Chrome DevTools Protocol相关的内容。

第一步: 我们先搭一个ws客户端,不管三七二十一,先连上去再说。连上去之后,你会发现什么都没发生,哈哈哈😁。

第二步: 我们先大概给debugger端发送如下内容,具体含义可以自己去官方文档里搜。

     [
      Runtime.enable(),
      Debugger.enable(),
      Runtime.runIfWaitingForDebugger(),
    ];

上面这些js代码转成ws的消息体后,变成这个样子:

[
{"id":1,"method":"Runtime.enable"},
{"id":2,"method":"Debugger.enable"},
{"id":3,"method":"Runtime.runIfWaitingForDebugger"}
];

在你发完这些消息给debugger端后,开始有回音啦,首先我这边收到一条消息:

ce15813a56d37b8ebcf906774cfdbb84.png

我把payload 美化一下大致长这个样子:

{
    "method":"Runtime.executionContextCreated",
    "params":{
        "context":{
            "id":1,
            "origin":"",
            "name":"node[11738]",
            "auxData":{
                "isDefault":true
            }
        }
    }
}

它对应的就是Runtime.enable(),表示一个可执行上下文被创建起来了。当然每次请求,debugger端都会有相应的返回,就像上面这个返回一样,如果你仔细观察返回的内容,你可以发现大概有两种格式:

  1. 一种就是上面的那种,返回一个method和params字段。
{
   "method":"xxxx",
   "params":{...},
}

  1. 另外一种就是带个id和result字段。
{
  id: 1,
  result: {…}
}

我猜想上面第一种返回是告诉我们v8虚拟机正在做什么事情,第二种就是我们请求debugger端后,debugger端做完后返回的结果。

为了验证猜想,我继续调试代码,努力找到一个样本,很快,我找到了一个:

d73d2514130926924e54cdf4a479ab6f.png

熟悉nodejs源码的同学大概知道'internal/bootstrap/loaders.js'nodejs加载内置模块的加载器代码,不管是你主线程还是worker线程,启动一个nodejs实例都会调用到它。

然后我继续debug,因为我们的index.js启动时,在第一行代码上设置了一个断点,所以debugger端会通过ws发送一个类似这样的消息:

4f542f064b1b1cff3ebe696f739816d0.png

告诉我们 file:///Users/huenchao/study/cnm/index.js 这个地方有个断点,此时,我们需要把这部分的代码从debugger端拿过来,所以我就 发送如下信息给debugger端:

"id":

很快,debugger端就返回给我们消息,正是我们想要调试的代码片段:

e23c2318c0e900535788ced8c1928770.png

好了,我已经获得了我们要调试的代码片段,接下来的就是不断的打断点,获取上下文信息,下一步,如此重复下去。。。。。

不如,我简单再演示一下,怎么继续打断点,继续next吧。

我现在给第一行代码设置一个断点:


{"id":6,"method":"Debugger.setBreakpoint","params":{"location":{"scriptId":"66","lineNumber":0}}}

然后debugger端设置好断点后,返回我类似下面的信息,我处理了一下:

fd47ea361baf544bb49800065838ea84.png

然后我想执行next的动作,ok,我再发送这样的信息给debugger端,看看会发生点什么:

"id":

debugger端返回消息:

5caa5f5fc6173fec669a5c57120d74dc.png

然后我们被调试的代码已经跑到下一行了:

fe13970bb830748b2251857231078542.png

后面更多花式技巧,我就不演示了,因为我本人就是一个张嘴就来,有口就行 的工程师,实战的部分留给你们后浪吧~😄

第三个问题

问:看完了这篇文章后,你是否有能力自己实现一个client代替其他调试客户端(chrome dev tool 或者 开发IDE(比如说VScode))来调试nodejs代码?

答:如果你从头到尾看完我这篇文章,做一个调试客户端,起码内置一个ws服务,然后基于CDP通信就行,因为做一个客户端,你起码要实现一个watcherLists吧?你起码要可以追溯上下文吧?你起码要做一下多进程链接调试吧?要有个简单可交互的界面吧?行,有兴趣就做一个呗,有了它,什么云端ide调试,跨端app调试不就弄起来了吗???

最后

这是调试文章的第一篇,其实很简单,后面大概还有会3篇文章,大致介绍Inpector的源码实现,以及编译V8后生成的D8怎么调试,怎么通过 D8观察我们js代码在存储状态,以及可能扩展到GC部分的内容,当然以上内容全部都是我yy的,我有时间就会研究,并写出来分享给大家。😁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值