翻译:云荒杯倾
本文是Emscripten-WebAssembly专栏系列文章之一,更多文章请查看专栏。
也能够去做者的博客阅读文章。
欢迎加入Wasm和emscripten技术交流群,群聊号码:939206522。html
调试Emscripten代码的主要优势之一是,源代码既能够在本地平台上进行调试,也可使用web浏览器日益强大的工具集——包括调试器、分析器和其余工具。c++
Emscripten提供了许多帮助调试的功能和工具:git
本文描述了由Emscripten提供的用于调试的主要工具和设置,以及如何调试一些Emscripten特有的问题。github
默认下,若是是优化编译,Emcc会删除大部分调试信息。Optimisation级-01和以上删除LLVM调试信息,也禁用了运行时断言检查。优化级别-02以上,代码被压缩编译器改编,变得几乎不可读。web
emcc -g标志可用于在编译的输出中保存调试信息。默认状况下,此选项保护空白、函数名和变量名。segmentfault
你可使用五个级别中的一个来指定标记:-g0、-g一、-g二、-g3和-g4。每一个级别都在最后编译,以在编译后的输出中逐步提供更多的调试信息。g3标志提供与-g标志相同级别的调试信息。浏览器
g4选项提供了最多的调试信息—--—它生成了源映射(source map),容许您在Firefox、Chrome或Safari浏览器的调试器中查看和调试C/C++源代码。安全
note: 当你既用调试flag又用优化flag时,有些优化可能会被禁掉,好比,若是你使用-O3 -g4 编译,为了给你提供足够多的调试信息,有一些-O3的优化就得禁用掉。
EMCC_DEBUG环境变量能够用来设置启用/不启用Emscripten的调试模式:函数
# Linux or Mac OS X EMCC_DEBUG=1 ./emcc tests/hello_world.cpp -o hello.html # Windows set EMCC_DEBUG=1 emcc tests/hello_world.cpp -o hello.html set EMCC_DEBUG=0
使用EMCC_DEBUG = 1设置,emcc会产生调试输出文件,并为编译器的各个编译阶段生成中间文件。
EMCC_DEBUG= 2还为每趟JavaScript优化器遍历(pass)生成中间文件。工具
调试日志和中间文件输出到TEMP_DIR/emscripten_temp,其中TEMP_DIR默认在/tmp(/tmp的位置在.emscripten配置文件定义)。
能够对调试日志进行分析,以对每一个步骤中所作的更改进行分析和检查。
Emscripten有许多能够用于调试的编译器设置。使用emcc -s选项选择这些设置,他们将覆盖任何优化标志。例如:
./emcc -01 -s ASSERTIONS=1 tests/hello_world
最重要的设置是:
在src/settings.js中定义了许多其余有用的调试设置。有关更多信息,请搜索“check”和“debug”关键字的文件。
用emcc -v选项编译,将-v传递给LLVM,而后在工具链上运行Emscripten的内部完整性检查。
verbose模式还能启动Emscripten的调试模式(EMCC_DEBUG)以生成编译器的各个阶段的中间文件。
您还能够用printf()语句手工编写源代码,而后编译并运行代码来研究问题。
若是你对问题行有很好的了解,你能够在JavaScript添加print(新的Error().stack)代码,以获得堆栈跟踪。另外还有stackTrace(),它发出堆栈跟踪,并尝试使用c++的去除改编的函数名(若是你不想或者不须要让c++ 函数名去除改编,你能够调用jsStackTrace())。
调试打印输出甚至能够执行任意的JavaScript。例如:
function _addAndPrint($left, $right) { $left = $left | 0; $right = $right | 0; //--- if ($left < $right) console.log('l<r at ' + stackTrace()); //--- _printAnInteger($left + $right | 0); }
有时候,编译的时候,禁用LLVM优化(llvm-opts)或禁用JavaScript优化(js-opts)是颇有用的。
好比说,如下命令即容许调试信息又使用-O2优化(既llvm和js都优化),可是又明显关闭了js的优化器。
./emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp
这样就能产生相对于llvm优化的代码来讲更易调试的js代码:
function _main() { var label = 0; var $puts=_puts(((8)|0)); //@line 4 "tests/hello_world.c" return 1; //@line 5 "tests/hello_world.c" }
Emscripten内存表示假定加载和存储是对齐的。在未对齐的地址上执行正常的加载或存储可能会失败。
SAFE_HEAP能够用来显示内存对齐问题。
通常来讲,最好避免不对齐的读写-----他们一般是因为未定义的行为致使的。然而,在某些状况下,它们是不可避免的—----例如,若是要移植的代码从一些预先存在的数据格式的打包结构(packed structure)中读取int。
Emscripten支持未对齐的读写,但它们要慢得多,并且必须在绝对必要时使用。执行一个不对齐的读或写你能够:
若是你的函数指针调用获得一个abort(),那么问题是在调用时,没有在预期的函数指针表中找到这个函数指针。
note: nullFunc是函数指针表中用于填充空索引的函数(b0和b1是优化编译下它的别名)。指向无效索引的函数指针会调用这个函数,而后调用abort().
有几个可能的缘由:
为了调试这些问题:
aliasing_function_pointer = 0也颇有用,由于它确保调用错误表中的指针地址会致使明显的错误。若是没有这样的设置,这样的调用只执行地址上的任何函数,这将很难进行调试。
无限循环致使您的页面挂起。在一段时间以后,浏览器将通知用户该页面被卡住并提供中止或关闭它的选择。
若是您的代码中有无限循环,那么找到问题代码的一个简单方法就是使用JavaScript profiler。在Firefox profiler中,若是代码进入无限循环,您将看到在profiler的末尾有一块代码重复执行相同的操做。
警告: 这个选项主要为Emscripten核心开发者提供使用。
Emscripten代码移植主题系列文章是emscripten中文站点的一部份内容。
本文是第三个主题第二篇文章。
第一个主题介绍代码可移植性与限制
第二个主题介绍Emscripten的运行时环境
第三个主题第一篇文章介绍链接C++和JavaScript
第三个主题第二篇文章介绍embind
第四个主题介绍文件和文件系统
第六个主题介绍Emscripten如何调试代码