到目前为止
一年前,Chrome 宣布初步支持 。
我们演示了基本单步调试支持,并讨论了未来使用 DWARF 信息(而非源代码映射)为我们带来的机会:
- 解析变量名称
- 美观输出类型
- 评估源语言中的表达式
- …等等!
今天,我们很高兴地展示已承诺的功能的实现情况,以及 Emscripten 和 Chrome DevTools 团队今年取得的进展,尤其是在 C 和 C++ 应用方面。
开始之前,请记住,它目前仍处于测试阶段 您需要使用最新版本的所有工具 风险自负。如果您遇到任何问题,请及时将问题报告给 https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
我们先从上次的简单 C 语言示例开始:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
为了编译该版本,我们使用最新的 Emscripten
并传递 -g
标志(就像在原始博文中一样),以包含调试
信息:
emcc -g temp.c -o temp.html
现在我们可以从本地主机 HTTP 服务器(对于 (使用 serve)以及 在最新的 Chrome Canary 版中打开它。
这次,我们还需要一个能与 Chrome 集成的帮助程序扩展程序 并帮助它理解所有调试信息 编码为 WebAssembly 文件请前往以下网址进行安装: 链接:goo.gle/wasm-debugging-extension
您还需要在 DevTools 的 Experiments 中启用 WebAssembly 调试。打开 Chrome 开发者工具,点击开发者工具窗格的右上角齿轮图标 (⚙),前往实验面板,然后选中 WebAssembly 调试:启用 DWARF 支持。
当您关闭 Settings 时,开发者工具会建议自行重新加载 来应用设置,就这样吧以上就是 设置。
现在,我们可以返回到 Sources 面板,启用 Pause on exceptions(“在出现异常时暂停”图标),然后选中 Pause on caught exceptions(“在捕获到异常时暂停”)并重新加载页面。您应该会看到 DevTools 在遇到异常时暂停:
默认情况下,它会在 Emscripten 生成的粘合代码上停止,但您可以在右侧看到表示错误堆栈轨迹的调用堆栈视图,并可以导航到调用了 abort
的原始 C 代码行:
现在,如果您在 Scope 视图中查看,则可以看到 C/C++ 代码中变量的原始名称和值,而无需再弄清楚 $localN
等经过混淆处理的名称的含义以及它们与您编写的源代码的关系。
这不仅适用于整数等原始值,还适用于复合 例如结构、类、数组等!
丰富的类型支持
我们来看一个更复杂的示例,以展示这些内容。这个 我们将使用下面的模型画一个曼德博分形 以下 C++ 代码:
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
您可以看到,这个应用仍然相当小, 包含 50 行代码的文件 - 但这一次,我还使用了 外部 API,例如用于实现以下目的的 SDL 库: 以及复数 C++ 标准库。
我将使用与上面相同的 -g
标志进行编译,以添加调试信息,同时还会要求 Emscripten 提供 SDL2 库并允许任意大小的内存:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
在浏览器中访问生成的网页时,我可以看到一些随机颜色的美丽分形图形:
当我打开开发者工具时,再次看到原来的 C++ 文件。不过,这次我们的代码中没有错误(呼!),因此我们改为在代码开头设置一些断点。
当我们再次重新加载页面时,调试程序会在我们的 C++ 源代码:
我们已经在右侧看到了所有变量,但目前只有 width
和 height
已初始化,因此没有太多内容可供检查。
我们在主曼德布罗图形循环中再设置一个断点,然后恢复执行以跳过一些内容。
此时,palette
已填充了一些随机颜色,
我们可以展开数组本身
SDL_Color
结构,并检查其组件,以验证
一切正常(例如,始终将“alpha”渠道设置为
设为完全不透明度)。同样,我们可以扩展并检查
存储在 center
变量中的复数的虚部。
如果您想访问深层嵌套的属性(否则很难通过镜重视图导航到该属性),也可以使用控制台评估功能!不过,请注意,目前尚不支持更复杂的 C++ 表达式。
我们来重复几次执行,看看内部 x
是如何变化的,方法是再次查看 Scope 视图、将变量名称添加到监视列表、在控制台中对其进行求值,或在源代码中将鼠标悬停在变量上:
在这里,我们可以步入或调试 C++ 语句,并观察如何 其他变量也会在发生变化:
好的,在有调试信息的情况下,所有这些都非常有效,但如果我们想调试未使用调试选项构建的代码,该怎么办?
原始 WebAssembly 调试
例如,我们要求 Emscripten 为我们提供预构建的 SDL 库,而不是我们自己从源代码编译,因此(至少目前)调试程序无法找到关联的源代码。让我们再次进入 SDL_RenderDrawColor
:
我们将回到原始的 WebAssembly 调试体验。
这看起来有点吓人,而且大多数 Web 开发者都不需要处理这种情况,但有时您可能需要调试未包含调试信息的构建库,原因可能是它是您无法控制的第三方库,或者您遇到了仅在生产环境中出现的某个 bug。
为了帮助您应对这些情况,我们还对基本调试体验进行了一些改进。
首先,如果您以前用过原始的 WebAssembly 调试功能,
请注意,整个拆解过程现在显示在一个文件中
更多猜测 Sources 条目 wasm-53834e3e/
wasm-53834e3e-7
可能对应于哪个函数。
新的名称生成方案
我们还改进了分解视图中的名称。之前,您会看到 而如果是函数,则不必指定名称。
现在,我们要生成与其他反汇编工具类似的名称
使用 WebAssembly name 部分中的提示,
导入/导出路径,最后,如果其他一切都失败,
根据项的类型和索引(例如 $func123
)添加映射。您可以从上图中看到,这已经有助于获得稍微更易读的堆栈轨迹和反汇编。
如果没有可用类型信息,则可能很难检查除了基元之外的任何值。例如,指针将显示为常规整数,无法知道内存中存储在指针后面的内容。
内存检查
以前,您只能展开 WebAssembly 内存对象(在 Scope 视图中用 env.memory
表示)以查找各个字节。这在一些简单场景中可行,但扩展起来并不特别方便,并且不允许以字节值以外的格式重新解释数据。我们新增了一项功能
线性内存检查器。
如果您右键点击 env.memory
,现在应该会看到一个名为检查内存的新选项:
点击后,系统会显示一个 Memory Inspector,位于 您可以采用十六进制和 ASCII 视图来检查 WebAssembly 内存, 导航到特定地址,以及将 不同的格式:
高级场景和注意事项
对 WebAssembly 代码进行性能分析
当您打开开发者工具时,WebAssembly 代码会“向下分层”更改为
启用调试功能。这个版本的网速要慢很多
也就是说,您不能依赖于 console.time
、performance.now
以及使用开发者工具来衡量代码速度的其他方法
您得到的数字并不代表实际效果
您应改用 DevTools 的“性能”面板,该面板会以全速运行代码,并详细说明在不同函数中花费的时间:
或者,您也可以在关闭开发者工具的情况下运行应用,并在运行完成后打开开发者工具以检查 Console。
我们日后会改进性能分析场景,但目前请注意这一限制。如需详细了解 WebAssembly 分层场景,请参阅我们的 WebAssembly 编译流水线文档。
在不同机器(包括 Docker/主机)上构建和调试
在 Docker、虚拟机或远程构建服务器上进行构建时, 您可能会遇到这样的情况 与您自己的文件系统中的路径不匹配,其中 Chrome 开发者工具正在运行。在这种情况下,文件将显示在 Sources 面板,但无法加载。
为了解决此问题,我们在 C/C++ 扩展选项中实现了路径映射功能。您可以使用它来重新映射任意路径, 帮助开发者工具找到源代码。
例如,如果宿主机上的项目位于
C:\src\my_project
,但它是在 Docker 容器内构建的,
该路径表示为 /mnt/c/src/my_project
,您可以重新映射
将这些路径指定为前缀,以便在调试期间返回:
第一个匹配的前缀“wins”。如果您熟悉其他 C++
调试程序,此选项类似于 set substitute-path
命令
或 LLDB 中的 target.source-map
设置。
调试优化型 build
与任何其他语言一样,停用优化功能最有利于调试。优化功能可能会将一个函数内联到另一个函数中, 或者将代码的某些部分一并删除 而使调试器混淆,从而造成用户误解。
如果您不介意调试体验受到较多限制,但仍想
调试优化型 build 之后,大部分优化措施
(函数内嵌除外)。我们计划解决
日后出现类似问题,但请暂时使用 -fno-inline
在使用任何 -O
级别的优化进行编译时将其停用,例如:
emcc -g temp.c -o temp.html \ -O3 -fno-inline
分离调试信息
调试信息会保留有关代码、定义的类型、变量、函数、作用域和位置的大量详细信息,这些信息对调试程序都可能很有用。因此,该值通常会大于 代码本身。
为了加快 WebAssembly 模块的加载和编译速度,您可能需要
您想将此调试信息拆分成单独的 WebAssembly
文件。为此,请在 Emscripten 中传递 -gseparate-dwarf=…
标志,并指定以下内容:
所需文件名:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
在这种情况下,主应用将只存储文件名
temp.debug.wasm
,然后帮助程序扩展程序将能够找到并
请在打开开发者工具时加载它。
与上述优化措施结合使用时,此功能可 甚至可以用于发布经过近乎优化的 应用,稍后使用本地端文件调试它们。在此示例中 我们还需要覆盖存储的网址 找到辅助文件,例如:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
待续…
哇,真是增加了不少新功能!
得益于所有这些新的集成,Chrome 开发者工具成为 功能强大的调试程序,不仅适用于 JavaScript,也适用于 C 和 C++ 应用, 它内置了各种 并将它们引入一个共享的跨平台网络。
然而,我们的征程尚未结束。我们今后将着手解决以下问题:
- 清除了调试体验中的粗糙边缘。
- 添加了对自定义类型格式化程序的支持。
- 我们正努力改进 性能分析功能。
- 添加了对代码覆盖率的支持,以便更轻松地查找未使用的代码。
- 改进了对控制台评估中表达式的支持。
- 增加对更多语言的支持。
- …等等!
与此同时,欢迎您对您自己的代码试用当前的 Beta 版,并报告我们找到的任何 问题至 https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
下载预览渠道
请考虑将 Chrome Canary、开发者版或 Beta 版用作您的默认开发浏览器。通过这些预览渠道,您可以访问最新的开发者工具功能,测试先进的网络平台 API,并在用户之前发现您网站上的问题!
与 Chrome 开发者工具团队联系
使用以下选项讨论博文中的新功能和变更,或与开发者工具相关的任何其他内容。
- 请通过 crbug.com 向我们提交建议或反馈。
- 使用更多选项报告开发者工具问题 >帮助 >在开发者工具中报告开发者工具问题。
- 请发送电子邮件至 @ChromeDevTools。
- 欢迎在我们的 “开发者工具的新变化”YouTube 视频或 “开发者工具提示”YouTube 视频中留言。