Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WASM Support #290

Closed
2 tasks
mitsuhiko opened this issue Nov 23, 2020 · 0 comments
Closed
2 tasks

Add WASM Support #290

mitsuhiko opened this issue Nov 23, 2020 · 0 comments

Comments

@mitsuhiko
Copy link
Member

mitsuhiko commented Nov 23, 2020

This is a formal issue as follow up to the initial investigations in #166. The goal is to enable WASM DWARF handling to the extent this is possible with the current state of affairs in the WASM world. This issue is to figure out best next steps since we need to operate within the realities of what runtime environments are likely to have access to.

WASM DWARF

Compilers place DWARF in custom sections directly in the WASM file, which can be accessed and read through the browser API. Similar to Linux, the section names are prefixed with ., for instance .debug_info. WASM files do not currently contain debug IDs (WebAssembly/tool-conventions#133).

Wherever a code address is used, it is the offset of an instruction relative within the Code section of the WebAssembly file. The DWARF is considered malformed if a PC offset is between instruction boundaries within the Code section. (See https://yurydelendik.github.io/webassembly-dwarf/#pc). Note that in browser stack traces the instruction offsets are absolute to the WASM file start (See https://webassembly.github.io/spec/web-api/index.html#conventions).

DW_TAG_namespace
  DW_AT_name                  lib1

  DW_TAG_subprogram
    DW_AT_low_pc                0x00000002
    DW_AT_high_pc               <offset-from-lowpc>9
    DW_AT_name                  calls_import1
    DW_AT_decl_file             0x00000001 /Users/jauer/Coding/wasm-test/lib1/src/lib.rs
    DW_AT_decl_line             0x00000008
    DW_AT_external              yes
  
  DW_TAG_subprogram
    DW_AT_low_pc                0x00000000
    DW_AT_high_pc               <offset-from-lowpc>35
    DW_AT_linkage_name          rust_begin_unwind
    DW_AT_name                  my_panic
    DW_AT_decl_file             0x00000001 /Users/jauer/Coding/wasm-test/lib1/src/lib.rs
    DW_AT_decl_line             0x0000000f
    DW_AT_noreturn              yes

    DW_TAG_formal_parameter
      DW_AT_location              len 0x0002: 910c: DW_OP_fbreg 12
      DW_AT_name                  _info
      DW_AT_decl_file             0x00000001 /Users/jauer/Coding/wasm-test/lib1/src/lib.rs
      DW_AT_decl_line             0x0000000f
      DW_AT_type                  0x000003dd<.debug_info+0x000003dd>

Browser Limitations

Browsers currently expose WASM in two ways. On the one hand through the limited WebAssembly API and on the other hand through the stack trace string.

The browser API exposes two objects when loading a web assembly module:

  • WebAssembly.Module: object representing the compiled WebAssembly module. This Module can be instantiated again or shared via postMessage().
  • WebAssembly.Instance: object that contains all the Exported WebAssembly functions.

Contents of the file can be accessed from the Module via three methods:

Neither object gives access to the full URI from which it was loaded, nor to the full contents. Browsers also do not offer an API to list or locate loaded wasm modules. While custom sections can be accessed if the WASM module handle is provided it is challenging to map a stack trace file name to a WASM module. Likely the solution would be to monkey patch the WASM loader or to ask users to register modules explicitly.

In Chrome 86, the stack trace for the above renders like this:

Error: whoops
    at crash (http://localhost:8088/index.js:1:9)
    at calls_import1 (http://localhost:8088/lib1.wasm:wasm-function[1]:0x86)
    at http://localhost:8088/index.js:15:5

Firefox observes similar output. Details of the second frame are:

  • calls_import1: Name of the wasm export function
  • http://localhost:8088/lib1.wasm: URI of the WASM module. We noticed that if two modules with identical contents are loaded, they always render the same URI of the first loaded module. This suggests that at least Chrome internally stores the URIs in an internal mapping.
  • wasm-function[1]: Indication of the WASM function. The number seems to be a 1-based index into the functions section of the WASM file.
  • 0x86: Byte offset into the WASM file where the function starts, relative to the start of the file.

Notes:

  • The URL field may be interpreted differently depending on the context. When the response-based instantiation API is used in a browser, the associated URL should be used; or when the ArrayBuffer-based instantiation API is used, the browser should represent the location of the API call. This kind of instantiation is analogous to executing JavaScript using eval; therefore if the browser has an existing method to represent the location of the eval call it can use a similar one for WebAssembly.instantiate.

  • The browser does not expose any function addresses or standard sections, so the start of the code section is hidden to SDKs. This means the most likely input for symbolic is the absolute address within the WASM file.

Proposed Next Steps

Based on the above investigation:

  • introduce the concept of a section offset to the DWARF code so that all instruction addresses are offset by the code section offset.
  • push for build_id custom sections to be added to files (Build ID Section for WASM WebAssembly/tool-conventions#133)
  • push for a browser API to map file names to WASM modules (or even provide build IDs directly in the stack trace string)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants