摘要:值啟用了更詳細的堆棧保護檢查,它以犧牲一些性能的代價提供更精確的。這種可以由任何類型的編碼錯誤引起,但表現為函數指針錯誤,因為在運行時的預期表中無法找到函數。
翻譯:云荒杯傾
本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。
也可以去作者的博客閱讀文章。
歡迎加入Wasm和emscripten技術交流群,群聊號碼:939206522。
調試Emscripten代碼的主要優點之一是,源代碼既可以在本地平臺上進行調試,也可以使用web瀏覽器日益強大的工具集——包括調試器、分析器和其他工具。
Emscripten提供了許多幫助調試的功能和工具:
編譯器調試信息flags,允許您在已編譯的代碼中保存調試信息,甚至創建源映射,以便在瀏覽器中調試時可以單步調試c++源代碼。
調試模式,它產生調試日志和存儲 編譯時產生的中間文件 進行分析。
編譯器設置,使運行時檢查內存訪問和公共分配錯誤。
還支持手動打印調試emscripten生成代碼,這在某些方面甚至比本地平臺工作效果更好。
自動調試器,它會自動地使用LLVM的中間代碼寫到內存。
本文描述了由Emscripten提供的用于調試的主要工具和設置,以及如何調試一些Emscripten特有的問題。
調試信息默認下,如果是優化編譯,Emcc會刪除大部分調試信息。Optimisation級-01和以上刪除LLVM調試信息,也禁用了運行時斷言檢查。優化級別-02以上,代碼被壓縮編譯器改編,變得幾乎不可讀。
emcc -g標志可用于在編譯的輸出中保存調試信息。默認情況下,此選項保護空白、函數名和變量名。
你可以使用五個級別中的一個來指定標記:-g0、-g1、-g2、-g3和-g4。每個級別都在最后編譯,以在編譯后的輸出中逐步提供更多的調試信息。g3標志提供與-g標志相同級別的調試信息。
g4選項提供了最多的調試信息—--—它生成了源映射(source map),允許您在Firefox、Chrome或Safari瀏覽器的調試器中查看和調試C/C++源代碼。
note: 當你既用調試flag又用優化flag時,有些優化可能會被禁掉,比如,如果你使用-O3 -g4 編譯,為了給你提供足夠多的調試信息,有一些-O3的優化就得禁用掉。調試模式(EMCC_DEBUG)
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
最重要的設置是:
ASSERTIONS=1 用于為內存分配錯誤啟用運行時檢查(例如,寫入比分配更多的內存)。它還定義了Emscripten如何處理程序流中的錯誤。可以將值設置為ASSERTIONS=2,以便運行額外的測試。
不優化編譯時,ASSERTIONS=1是默認開啟的。對于優化編譯的代碼(-01和以上級別)它是關閉的。
SAFE_HEAP= 1增加了額外的內存訪問檢查,并將為諸如非內聯化0(dereferencing 0)和內存對齊等問題提供清晰的錯誤。你也可以設置SAFE_HEAP_LOG以打印SAFE_HEAP操作。
通過STACK_OVERFLOW_CHECK =1 標記在堆棧的末尾添加一個運行時的令牌值,令牌值會在某些位置被檢查,以驗證用戶代碼是否意外地寫出了堆棧的末尾。雖然溢出Emscripten堆棧不是一個安全問題(JavaScript已經被沙箱化了),但寫出堆棧將會導致全局數據內存損壞和Emscripten堆中動態分配的內存碎片化,這使得應用程序以意想不到的方式失敗。值STACK_OVERFLOW_CHECK = 2啟用了更詳細的堆棧保護檢查,它以犧牲一些性能的代價提供更精確的callstack。如果ASSERTIONS= 1,STACK_OVERFLOW_CHECK默認值為2,ASSERTIONS為其他值時STACK_OVERFLOW_CHECK默認不啟用。
在src/settings.js中定義了許多其他有用的調試設置。有關更多信息,請搜索“check”和“debug”關鍵字的文件。
emcc詳細輸出用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禁止優化 有時候,編譯的時候,禁用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特有問題 內存對齊問題Emscripten內存表示假定加載和存儲是對齊的。在未對齊的地址上執行正常的加載或存儲可能會失敗。
SAFE_HEAP可以用來顯示內存對齊問題。一般來說,最好避免不對齊的讀寫-----他們通常是由于未定義的行為導致的。然而,在某些情況下,它們是不可避免的—----例如,如果要移植的代碼從一些預先存在的數據格式的打包結構(packed structure)中讀取int。
Emscripten支持未對齊的讀寫,但它們要慢得多,而且必須在絕對必要時使用。執行一個不對齊的讀或寫你可以:
手動讀取單個字節并重新構造全部值
使用emscripten_align*類型,它定義了基本類型的不對齊版本(short,int,float,double)。這些類型的所有操作都是不完全對齊的(在大多數情況下使用1個variants,這意味著沒有任何對齊)。
函數指針問題如果你的函數指針調用得到一個abort(),那么問題是在調用時,沒有在預期的函數指針表中找到這個函數指針。
note: nullFunc是函數指針表中用于填充空索引的函數(b0和b1是優化編譯下它的別名)。指向無效索引的函數指針會調用這個函數,然后調用abort().有幾個可能的原因:
您的代碼調用了一個從另一個類型轉換來的函數指針(這是未定義的行為,但它確實發生在真實的代碼中)。在優化的Emscripten輸出中,每個函數指針類型都基于它的原始簽名,存儲在一個多帶帶的表中,因此您必須調用具有相同簽名的函數指針以獲得正確的行為(更多信息參見代碼可移植性部分中的函數指針問題)。
您的代碼在空指針或者dereferencing 0上調用方法。這種bug可以由任何類型的編碼錯誤引起,但表現為函數指針錯誤,因為在運行時的預期表中無法找到函數。
為了調試這些問題:
使用-Werror編譯。這就把警告變成了錯誤,這些錯誤可能有用,因為一些未定義行為的情況會顯示警告。
使用-s ASSERTIONS=2,得到一些 關于被調用的函數指針和它的類型 有用的信息。
查看瀏覽器堆棧跟蹤,查看錯誤發生的地方以及應該調用哪個函數。
使用SAFE_HEAP=1和禁用函數指針別名(aliasing_function_pointer = 0)編譯。這使得錯誤類型的函數指針 不可能在不引起錯誤的情況下 調用,換句話說就是這樣編譯會使 錯誤類型的函數指針調用 一定會報錯。調用命令:-s SAFE_HEAP=1 -s aliasing_function_pointer =0
aliasing_function_pointer = 0也很有用,因為它確保調用錯誤表中的指針地址會導致明顯的錯誤。如果沒有這樣的設置,這樣的調用只執行地址上的任何函數,這將很難進行調試。
死循環無限循環導致您的頁面掛起。在一段時間之后,瀏覽器將通知用戶該頁面被卡住并提供停止或關閉它的選擇。
如果您的代碼中有無限循環,那么找到問題代碼的一個簡單方法就是使用JavaScript profiler。在Firefox profiler中,如果代碼進入無限循環,您將看到在profiler的末尾有一塊代碼重復執行相同的操作。
AutoDebugger警告: 這個選項主要為Emscripten核心開發者提供使用。Emscripten代碼移植系列文章Emscripten代碼移植主題系列文章是emscripten中文站點的一部分內容。
本文是第三個主題第二篇文章。
第一個主題介紹代碼可移植性與限制
第二個主題介紹Emscripten的運行時環境
第三個主題第一篇文章介紹連接C++和JavaScript
第三個主題第二篇文章介紹embind
第四個主題介紹文件和文件系統
第六個主題介紹Emscripten如何調試代碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/91969.html
摘要:教程之代碼可移植性與限制一翻譯云荒杯傾本文是專欄系列文章之一,更多文章請查看專欄。下面是正文代碼可移植性與限制幾乎可以編譯任何可移植的代碼到。如果標準機構將共享狀態添加到中,支持多線程代碼將成為可能。 Emscripten教程之代碼可移植性與限制(一) 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作者的博客閱讀文章。歡迎...
摘要:優化級別越高,編譯時間越長啟用的。允許優化,有兩個值不允許優化器允許使用優化器。規定是否單獨生成一個內存初始化文件。使生成的代碼能夠感知命令行工具。設置一個絕對路徑的白名單,以防止關于絕對路徑的警告。 emcc(Emscripten Compiler Frontend)介紹 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作...
摘要:優化級別越高,編譯時間越長啟用的。允許優化,有兩個值不允許優化器允許使用優化器。規定是否單獨生成一個內存初始化文件。使生成的代碼能夠感知命令行工具。設置一個絕對路徑的白名單,以防止關于絕對路徑的警告。 emcc(Emscripten Compiler Frontend)介紹 翻譯:云荒杯傾本文是Emscripten-WebAssembly專欄系列文章之一,更多文章請查看專欄。也可以去作...
閱讀 1496·2023-04-26 01:28
閱讀 3315·2021-11-22 13:53
閱讀 1420·2021-09-04 16:40
閱讀 3189·2019-08-30 15:55
閱讀 2677·2019-08-30 15:54
閱讀 2489·2019-08-30 13:47
閱讀 3366·2019-08-30 11:27
閱讀 1146·2019-08-29 13:21