獲取 C++ WebAssembly 的 stacktrace
搜尋 C++ Stacktrace
一開始對 WebAssembly 一無所知。認為 C++ 和其他語言一樣應該能提供一個語言自帶的 stacktrace 吧。但是各種 libunwind 的庫在 emscripten 上怎麼使用,沒一篇文章說明。
The Pain of Debugging WebAssembly 根據這篇文章 At present, WASM does not support stack unwinding. 也就是說 native 平臺上那套主動發起 unwind 去拿 stacktrace 的做法在 wasm 上是行不通的。
-fwasm-exceptions
搜尋 emscripten 的文件,發現了 "-fwasm-exceptions"。但是並不明白這個開關實際做了什麼,就用上了。
實際上這個開關乾的事情是把 throw std::runtime_error 這樣的 throw 語法,編譯成了 throw opcode,是一個 WebAssembly VM 的擴充套件指令。然後 chrome 的 v8 就會根據這個 opcode,丟擲一個 WebAssembly.Exception。
但是問題是 WebAssembly.Exception.prototype.stack - WebAssembly | MDN 說明 Exceptions from WebAssembly code do not include a stack trace by default. If WebAssembly code needs to provide a stack trace, it must call a JavaScript function to create the exception
注意這裡的 must call。然而 llvm 直接就把 throw 編譯成 throw opcode 了,怎麼編譯成 call javascript function 來拋這個異常呢?沒找到辦法。結果就是 throw 出來的異常可以在 chrome 的 console 裡打出異常棧來,但是沒法用 error.stack 從 js 側獲取到,也就沒法上報給 sentry 了。
-fexceptions
實際 emscripten 的 -fexceptions 是最簡單的。它直接把 cxxabi 提供的 __cxa_throw 給偽造了 http:// github.com/emscripten-c ore/emscripten/blob/main/src/library_exceptions.js 。在 C++ 裡的 throw,實際上調到了 js 的函式裡。然後我們就可以很容易通過 --js-library 的方式來提供自己的 __cxa_throw 來從 js 丟擲 WebAssembly.RuntimeException,從而獲得異常棧了。
這麼做的代價就是沒法在 C++ 裡 catch 了。emscripten 預設的實現是把 ptr 這個整數直接 throw 了,這樣丟擲的不是 Error 物件,也就是無法獲得異常棧的。所以這個預設實現把我給矇蔽了,以為 v8 沒有獲得異常棧的能力。實際上仔細實驗一下就可以發現,如果在 C++ WASM 裡呼叫了一個 js 方法,然後 js 方法裡拋了異常,這個時候是可以看到異常棧的。也就是我們有的時候可以看到異常棧,有的時候看不到原因。
- 獲取 C WebAssembly 的 stacktrace
- 單向資料流的真正甜蜜
- To B SaaS 的兩類技術問題
- 不啟動整個應用,單獨預覽某一個 vue 元件
- 程式碼稽核的兩種方向
- 程式設計師為什麼不喜歡低程式碼
- 如何做好抽象?
- 如果一個好主意50年了還沒有落地,那它也不是那麼好的注意
- 什麼是耦合,什麼是內聚
- 程式碼無可避免腐化是因為這 5 個原因
- 在提賦能之前,先想想這5個問題
- 軟體開發提效哪有那麼容易,都是坑啊~
- 寫自動化運維指令碼的前途是什麼?
- 容易效仿的做法往往沒有用,有用的事情從來不容易
- 不要以 DRY 之名,發明低程式碼 DSL 去殘害你的同事
- 程式碼寫得不好,不要總覺得是自己抽象得不好
- 多 git 倉庫開發如何維護 package.json
- 打造傑出軟體開發團隊的12條指導建議
- 程式設計就是壓縮
- 研發效能可以度量麼?