方法一,直接构建d8
d8是v8引擎的独立调试shell,编译速度很快,用于调试v8引擎的内部行为。
autoninja -C out/Default d8
1. 项目结构
|-- src
| |-- out
| | |-- Default
| | | |-- d8.exe
| | | |-- v8.dll
| | | |-- v8.dll.pdb
| |-- example
| | |-- test.js
| |-- .vscode
| | |-- launch.json
如果.pdb文件不存在,无法从二进制文件映射回源码,说明编译的时候没有启用debug模式。
gn gen默认开启debug模式(is_debug = true),symbol_level = 1,代表生成基本符号,但不包括内联函数和局部变量。如果需要生成完整符号,需要设置
gn gen out/Default --args="symbol_level=2"
2. 相关代码
// test.js
function add(a, b) {
return a + b;
}
// %DebugPrint(add); // 打印对象信息
%SystemBreak(); // 触发断点
add(1, 2);
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug d8",
"type": "cppvsdbg", // 使用 Visual Studio 调试器
"request": "launch",
"program": "${workspaceFolder}/out/Default/d8.exe",
"args": [
"--allow-natives-syntax", // 允许内置调试命令(如 %DebugPrint)
"${file}" // 调试当前打开的 JS 文件
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"symbolSearchPath": "out/Default", // 指向调试符号目录
"sourceFileMap": {
"/": "${workspaceFolder}" // 确保源码路径正确映射
},
"console": "externalTerminal", // 显式指定外部终端(部分系统需要)
"internalConsoleOptions": "neverOpen", // 禁用 VSCode 内部控制台
"inputRedirection": true // 允许输入重定向(部分调试器支持)
},
]
}
vscode的C/C++扩展默认配置为MinGW/Cygwin,而chrome基于Calng-cl + MSVC链接器构建,所以需要指定调试器为cppvsdbg(微软调试器)。
3. 执行步骤
1- 安装c/c++扩展
2- 编写.vscode/launch.json
3- 在v8\src\runtime\runtime-test.cc文件中的RUNTIME_FUNCTION(Runtime_SystemBreak)函数内打上断点
4- debug窗口点击运行图标,调试程序会停在RUNTIME_FUNCTION(Runtime_SystemBreak)处。
方法二,构建chrome
包含所有组件,构建速度很慢,调试步骤也会繁琐很多
autoninja -C out/Default chrome
1. 项目结构
|-- src
| |-- out
| | |-- Default
| | | |-- chrome.exe
| | | |-- v8.dll
| | | |-- v8.dll.pdb
| |-- example
| | |-- test.html
| | |-- test.js
| |-- .vscode
| | |-- launch.json
如果.pdb文件不存在,无法从二进制文件映射回源码,说明编译的时候没有启用debug模式。
gn gen默认开启debug模式(is_debug = true),symbol_level = 1,代表生成基本符号,但不包括内联函数和局部变量。如果需要生成完整符号,需要设置
gn gen out/Default --args="symbol_level=2"
2. 相关代码
// test.js
function add(a, b) {
return a + b;
}
// %DebugPrint(add); // 打印对象信息
%SystemBreak(); // 触发断点
add(1, 2);
<!-- test.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="test.js"></script>
</body>
</html>
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Chrome Renderer",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}",
"program": "${workspaceFolder}/out/Debug/chrome.exe",
"symbolSearchPath": "${workspaceFolder}/out/Debug/**/*.pdb"
}
]
}
vscode的C/C++扩展默认配置为MinGW/Cygwin,而chrome基于Calng-cl + MSVC链接器构建,所以需要指定调试器为cppvsdbg(微软调试器)。
3. 执行步骤
1)启动chrome
out/Default/chrome.exe --no-sandbox --renderer-startup-dialog --disable-hang-monitor --js-flags="--allow-natives-syntax"
以下是启动 Chrome 时使用的各个参数及其作用的详细解释:
1. --no-sandbox
• 作用:
禁用 Chrome 的沙盒(Sandbox)安全机制。
• 背景:
Chrome 的沙盒机制通过隔离渲染进程(Renderer)和主进程(Browser)来限制恶意代码对系统的破坏。但调试时,沙盒可能会阻止调试器访问某些资源(如本地文件系统或特定系统调用)。
• 适用场景:
• 调试需要访问本地文件或底层系统调用的代码。
• 解决因沙盒权限限制导致的调试失败问题。
• 风险提示:
禁用沙盒会显著降低安全性,仅限调试环境使用,切勿在生产环境或日常浏览中启用!
2. --renderer-startup-dialog
• 作用:
强制每个新的渲染进程(Renderer)启动时弹出一个对话框,显示进程的 PID(进程 ID)并等待用户确认后才继续执行。
• 适用场景:
• 调试多进程架构下的渲染进程,确保在进程启动后立即附加调试器。
• 精准定位目标进程,避免附加到错误的 Renderer 实例。
• 操作流程:
- 启动 Chrome 后,新开标签页或加载页面时会弹出 PID 对话框。
- 记录 PID,在调试器中附加到该进程。
- 点击对话框的 “OK” 恢复进程执行。
3. --disable-hang-monitor
• 作用:
禁用 Chrome 的“页面无响应”监控功能。
• 背景:
Chrome 默认会检测页面是否卡死(如长时间未响应),并提示用户关闭页面。但在调试过程中,如果代码在断点处暂停或被调试器中断,Chrome 可能误判为页面挂起并强制终止进程。
• 适用场景:
• 调试时需要长时间暂停进程(如断点调试或单步执行)。
• 避免调试会话被意外终止。
4. --js-flags="--allow-natives-syntax"
• 作用:
允许在 JavaScript 中使用 V8 引擎的“内部函数”(以 %
开头的函数)。
• 背景:
V8 引擎提供了一系列内部调试函数(如 %DebugPrint
、%SystemBreak
),但这些函数默认被隐藏,需通过此标志显式启用。
• 适用场景:
• 调试 JavaScript 代码时,调用 V8 内部函数输出调试信息或触发断点。
• 分析对象内存布局、优化行为(如内联缓存状态)。
• 示例代码:
// test.js
function test() {
const obj = { a: 1 };
%DebugPrint(obj); // 输出对象内存地址和内部结构
%SystemBreak(); // 触发调试断点
}
test();
参数使用注意事项
- 调试完成后移除参数:
--no-sandbox
和--disable-hang-monitor
会显著降低安全性或稳定性,调试结束后应从启动命令中移除。 --renderer-startup-dialog
的副作用:
每个新标签页或 iframe 都会触发弹窗,可能导致调试流程中断。建议仅在需要时使用。- V8 内部函数的版本依赖:
%
开头的函数可能因 V8 版本不同而变化,需参考对应版本的文档。
完整命令示例
out/Default/chrome.exe \
--no-sandbox \ # 禁用沙盒
--renderer-startup-dialog \ # 渲染进程启动时弹窗
--disable-hang-monitor \ # 禁用挂起监控
--js-flags="--allow-natives-syntax" # 启用 V8 内部函数
通过合理组合这些参数,可以高效调试 Chrome 的渲染进程和 JavaScript 行为,同时避免调试过程中的干扰。
2)浏览器地址栏输入test.html的绝对路径
3)弹窗弹出pid,阻塞页面渲染
因为chrome是多进程的,如果直接用命令行启动chrome并自动打开test.html,会弹出多个弹窗提示不同的pid,没法确认test.html对应的pid究竟是哪个。用命令行启动chrome,但不自动打开test.html的话,其他无关标签/frame的pid弹窗会先弹出,手动输入test.html后弹出的弹窗就一定是test.html对应的pid。
4)附加调试器到进程
1- 安装c/c++扩展
2- 编写.vscode/launch.json
3- 在v8\src\runtime\runtime-test.cc文件中的RUNTIME_FUNCTION(Runtime_SystemBreak)函数内打上断点
4- debug窗口点击运行图标,选择之前记录下的pid