一个比较笨拙的调试v8 bytecode的方法
d8
--print-bytecode
参数是必须的,不然都不知道d8生成了啥bytecode,接着是下断点:
找到src/d8/d8.cc目录下的Shell::Main(int argc, char* argv[])
函数里初始化Isolate的那一句(不同版本可能在不一样的位置):
1 | Isolate* isolate = Isolate::New(create_params); |
在初始化好isolate之后我们在gdb中:
1 | p &((v8::internal::Isolate*)isolate)->interpreter_->dispatch_table_ |
这里就能拿到bytecode的handler函数表了,然后只要根据src/interpreter/bytecodes.h
里定义的list:
1 | // The list of bytecodes which are interpreted by the interpreter. |
找到你要调试的那个bytecode的名字相对应的偏移,根据这个偏移去 dispatch_table_ 里找到相对应handler函数的地址,下断点就能断下来了
更简单的方法可以是用--print-bytecode
把字节码打印出来,然后各个字节码的第一个数值就是偏移,如下面例子里的:
1 | 0 : 12 00 LdaConstant [0] |
0x12就是LdaConstant的偏移
示例
js代码:
1 | var aa = {foo:"bar"}; |
用d8查看其bytecode:
1 | ./d8 --print-bytecode ./layout.js |
然后要是想从头开始调试直接下LdaConstantHandler函数的断点就好,或者你想要调试CreateObjectLiteralHandler就下它的断点,跳过前面的bytecode
这些bytecode的handler都定义在src/interpreter/interpreter-generator.cc
下
后记
上面所使用的d8版本是8.7.242,那个dispatch_table_是带符号的,像下面这样:
1 | pwndbg> p isolate |
我也不知道为啥有些版本好像是有带符号的,一开始9.3.x版本调试的时候没有这个符号。。。
还有就是9.3.x版本的star1,star2这些bytecode不知道为什么下了断点有时候能断下,有时候不行,实属迷惑,不过这个指令只是存储数据到寄存器,问题不大
在编译d8的时候好像还可以选择啥flag,编译为之后就能显示出每一步bytecode的执行结果好像,不太清楚就是了,我这是主要为了想弄懂类似CreateObjectLiteral
这种bytecode到底调用了啥cpp函数才这么搞的