翻譯:雲荒杯傾
本文是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如何調試代碼