3 things to do before debugging V8 Link to heading
Build d8 with debug flags from V8 source Link to heading
If you haven’t tried building V8 before, take a look at my other blog on how to
build V8 from source on Ubuntu and
Mac M1. Now we just need to make sure the d8
binary is built with debug
flag instead of release
.
You can run this command gm.py arm64.debug.d8
. Or incase you have built a
release version and don’t want to rebuild everything. Open
out/release/args.gn
file and update following options.
is_debug = true
symbol_level = 2
v8_enable_backtrace = true
v8_optimized_debug = false
And then go to previous build directory and run ninja again.
cd out/release
ninja
Install lldb
Link to heading
Run lldb -v
to check if you have lldb
installed.
lldb -v
lldb-1300.0.42.3
If not. You will be prompt to the installation.
Create a JS file Link to heading
For this first debugging session we will use simple script. Let’s create a file
called debug.js
in the same directory of d8
executable.
let a = 1;
var b = 2;
const c = 3;
console.log(a + b + c);
And we can run d8
with debug.js
script.
$ ./d8 debug.js
6
Cool, it works!
Debug our script Link to heading
Let’s start up lldb
debug session with command above.
$ cd out/arm64.debug
$ lldb -- d8 debug.js
(lldb) target create "d8"
Current executable set to '/Users/sytran/Code/google/v8/out/arm64.debug/d8' (arm64).
(lldb) settings set -- target.run-args "debug.js"
Our target to debug is d8
executable and its only argument is debug.js
. To
start the script, type run
and hit enter
.
(lldb) run
Process 80671 launched: '/Users/sytran/Code/google/v8/out/arm64.debug/d8' (arm64)
6
Process 80671 exited with status = 0 (0x00000000)
Our script is executed and printed out 6
and we expect. Now we need to set a
breakpoint in V8 C++ code for debugging. We use breakpoint set --name main
command to set our first breakpoint.
(lldb) breakpoint set --name main
Breakpoint 1: where = d8`main + 24 at d8.cc:5481:59, address = 0x000000010004ec70
As we are still in debug session, we just need to run
again. But this time we
use shortcut r
for run
.
(lldb) r
Process 80711 launched: '/Users/sytran/Code/google/v8/out/arm64.debug/d8' (arm64)
Process 80711 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x000000010004ec70 d8`main(argc=2, argv=0x000000016fdff330) at d8.cc:5481:59
5478
5479 } // namespace v8
5480
-> 5481 int main(int argc, char* argv[]) { return v8::Shell::Main(argc, argv); }
5482
5483 #undef CHECK
5484 #undef DCHECK
Target 0: (d8) stopped.
d8
process is stopped right at main
function (->
position), and we can see surrounding
lines of C++ code.
To step into v8::Shell:Main
function, run step
or s
.
(lldb) s
Process 80711 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x000000010004d484 d8`v8::Shell::Main(argc=2, argv=0x000000016fdff330) at d8.cc:5140:3
5137 } // namespace
5138
5139 int Shell::Main(int argc, char* argv[]) {
-> 5140 v8::base::EnsureConsoleOutput();
5141 if (!SetOptions(argc, argv)) return 1;
5142
5143 v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
Target 0: (d8) stopped.
This function parses given arguments, for our script, it will go to last else block.
|
|
So let set a breakpoint at that position and continue
(lldb) b d8.cc:5401
Breakpoint 2: where = d8`v8::Shell::Main(int, char**) + 3792 at d8.cc:5401:14, address = 0x000000010004e264
(lldb) continue
Process 80711 resuming
Process 80711 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x000000010004e264 d8`v8::Shell::Main(argc=2, argv=0x000000016fdff330) at d8.cc:5401:14
5397 options.compile_options.Overwrite(
5398 v8::ScriptCompiler::kNoCompileOptions);
5399 } else {
5400 bool last_run = true;
-> 5401 result = RunMain(isolate, last_run);
5402 }
5403
Target 0: (d8) stopped.
Let’s see value of last_run
and isolate
variables. Because isolate
is a
pointer, we need to use *isolate
to view its value.
(lldb) fr v last_run *isolate
(bool) last_run = true
(v8::Isolate) *isolate = {}
So we running new shell with an empty v8::Isolate
(internal state). And our
set up is complete. In order to use other lldb
debug functions, check out their
document.
Now we can dive deeper into V8 core 🤩