Using Browsers To Debug Webassembly

Debugging is an inevitable development step. Browsers already have some support for Webassembly debugging, Firefox Developer Edition has the best capabilities, while Chrome has features that complement Firefox. In this post, I will present how to enable debugging during the compilation process, and what we can do with Firefox and Chrome. In a future post, I will focus on poor man’s debugging, or how to instrument your Webassembly code to log debugging messages.

Did you hear that one about a CEO debugging code late at night? Me neither.

Example Code Used

The following is the content of xor.c file content used for this test case:


unsigned int xor( unsigned int a, unsigned int b)
{
    return a^b;
}

The xor.c file is going to be compiled as a shared library, that way we can avoid all the auxiliary heavy javascript code that is generated by Emscripten and focus on debugging.

Here is the content of xor.html file that exercises the xor function:


<html>
<head>
  <script>
    // Currently a Webassembly shared library needs to be fed a memory for its
    // internal stack (see xor.wast exports)
    // In the code below, 256 are Webassembly pages, each with 64KB, which is insane,
    // but this is the default emscripten value used when compiling a wasm shared library,
    // it maybe changed though, but the default is good for our purpose here.
    // Memory base serves the purpose of allowing multiple modules to share the same
    // memory, so each would have its own portion in memory.
    const importObj = {
        env: {
            memory: new WebAssembly.Memory({initial: 256, maximum: 256}),
            memoryBase: 0,
        }
    };

    // Load the module using the newest Streaming API
    WebAssembly.instantiateStreaming(fetch('xor.wasm'), importObj)
    .then(obj => {
        var exports = obj.instance.exports; // the exports of that instance
        var xor = exports._xor; // Rename _xor to xor 🙂
        // Add a listener to the button so we can execute the xor function when the button is pressed.
        var button = document.getElementById('run');
        button.addEventListener('click', function() {
          var input1 = 0x55;
          var input2 = 0xAA;
          alert('XOR('+input1+','+input2+')=='+xor(input1,input2));
        }, false);
      }
    );
  </script>
</head>
<body>
  <input type="button" id="run" value="click for wasm xor"/>
</body>
</html>

Enabling Debug in Xor.c

Webassembly debug happens through source maps. Source maps is already the method used to debug Javascript. To enable source map, compile xor.c with the following options: -g4 and –source-map-base http://localhost:8080/

Where:

-g4 enables source map.

–source-map-base http://localhost:8080/ tells the browser where to look for the source map file. In our test case, the source map file is located at the same place where xor.html is located:http://localhost:8080/, which is the URL that I use to launch the test code.

Following is how I have compiled xor.c:


emcc xor.c -O1 -g4 -s WASM=1 -s SIDE_MODULE=1 -o xor.wasm --source-map-base http://localhost:8080/

How to Run the Example Code:

The xor.html file above uses the newest instantiateStreaming() API to load a Webassembly module, the instantiateStreaming() function requires a server to serve the Webassembly module. I use the following emrun command to serve the Webassembly module:


emrun --no_browser --port 8080 .

How To Debug Webassembly Using Firefox Developer Edition (version 60.0b2)

Here is the Firefox Debug View for the high-level source code(shortcut is CTRL+SHIFT+S):

Firefox-Wasm-Debug-SourceView

Lots to unpack:

The left area contains the Source tab. Double click in one of the files to see the file content in the middle area. The above picture shows the xor.c file and a breakpoint in line 3. The program is paused because of the breakpoint. To set a breakpoint, just click in the line you want to set it.

The right area contains the debugger features. As you can see in Watch expressions, we can’t inspect variables, variable a is marked as (unavailable). The Breakpoints panel shows our breakpoint on line 3 in xor.c.

The Scopes panel is interesting for the Webassembly view, to be shown later.

What can we do here? Basically, step through the code and resume execution.

Here is the Firefox Debug View for the Webassembly code:

Firefox-Wasm-Debug-WasmView

Above we have the xor.wasm file opened. Now the Scopes panel makes sense, var0, var1, and var2 are the wasm variables used inside the xor function. You can step through Webassembly instructions, and see the variables changing their values.

Although it is not currently possible to inspect high-level variables, it is possible to inspect Webassembly variables. It is not as easy though, but it is already something.

How To Debug Webassembly Using Chrome (version 65.0.3325.162)

Chrome Debug View (shortcut is CTRL+SHIFT+I):

Chrome-Wasm-Debug-WasmView

In general, the current state of Webassembly debug in Chrome is inferior to Firefox Developer Edition. There is no high-level source code view, the wasm view has weird names with several numbers in them, it takes a while to figure out where to go.

But it has a cool feature, which is not present in Firefox: it shows the stack. In the above picture, the code is stopped right before the execution of the xor instruction. There you can see that the local variables are loaded into the stack ready for the instruction to be executed: 0:170 1:85. This is a nice way to understand what the Webassembly instructions do.

Conclusion

Although preliminary, there is already a useful support for debugging Webassembly in Firefox and Chrome. Not ideal yet, but clearly they are evolving to a usable debug experience. Future post will demonstrate how to debug Webassembly without the help of a browser debug.

Post MindMap

mindmap-in-browser-debugging-webassemblycode

Leave a message below. Webassembly is evolving rapidly, please let me know if this post got outdated.

Enjoyed this post?

Don't miss new posts: Share it with your friends:

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *