Overview

12 Debugging

This chapter introduces practical strategies for debugging WebAssembly modules in today’s still-maturing tooling landscape. It advocates an iterative workflow—making small changes, compiling, and testing frequently—and demonstrates the approach by extending a browser-based card‑matching game to track and display a “tries” counter. Along the way, it shows how to reason about problems that arise at compile time, link time, and runtime, and how to combine adjustments to both the WebAssembly text format and JavaScript glue code to isolate and fix issues.

The chapter surveys core techniques: enabling verbose Emscripten output (via debug modes) to surface compiler diagnostics; emitting varying levels of debug information with -g flags (including .wast output to inspect imports/exports and linking); using console logging from C/C++ or imported JavaScript to trace execution; and stepping through WebAssembly in browser developer tools. It explains the strengths and limitations of current source‑map support, and contrasts Chrome and Firefox debuggers: function and global indices vs. names, where stack values and globals are visible, and how to set breakpoints and step instructions. Typical failure modes are highlighted, such as type mismatches from outdated import signatures and LinkErrors caused by missing imports in the JavaScript import object.

Through a guided example, the chapter implements the tries feature: updating HTML, extending the JavaScript generateCards function, creating a mutable global for tries in the text format, passing it across the module boundary, resetting it at level start, and exposing an updateTriesTotal import to refresh the UI after the second card is selected. It then debugs two intentional errors—first a compile‑time mismatch due to a missing parameter in an imported function signature, and then a runtime LinkError from an absent import mapping—before using the browser debugger to trace a logic bug where tries incremented by 10 instead of 1 (fixing an i32.const value). Finally, it passes the tries count to the summary screen by updating both the import signature and call site, and closes with exercises and guidance on continuing improvements in WebAssembly and related tooling.

Level 2 of the card-matching game with the subtitle adjusted to include the number of tries.
The high-level steps that will be used to adjust the game to include the number of tries
Adjust the JavaScript and text format code to display the number of tries when the level starts.
Create the $tries global variable in the text format code and pass the value to the generateCards JavaScript function.
Use the WebAssembly Binary Toolkit to generate the cards.wasm file from the text format.
A compilation error with the contents of the cards.wast file.
Copy the cards.wasm file for use by the browser and then test your changes.
The changes you made are working because a value of 0 is shown next to the Tries label.
Add code to increment the number of tries when the player clicks on the second card.
Increment the number of tries value when the player clicks on the second card.
Adjust the text format to increment the $tries value when the player clicks on the second card. Then you’ll pass the value to the new JavaScript function.
Use the WebAssembly Binary Toolkit to generate the WebAssembly file from the text format.
Paste the contents of your cards.wast file into the top-left pane of the tool and then download the WebAssembly file naming it cards.wasm.
Copy the cards.wasm file to the server for use by the browser and then test your changes.
Something isn’t working properly because the game isn’t being displayed.
A JavaScript error is logged about the _UpdateTriesTotal field.
The tries value is increasing in increments of 10 rather than 1.
The areas of Chrome’s developer tools for debugging a WebAssembly module
The areas of Firefox’s developer tools for debugging a WebAssembly module
The Scopes section in Firefox showing the global variables in this function’s scope
The number of tries will be passed to the summary screen when the player completes the level
The steps to include the number of tries in the summary screen’s congratulatory message.
Pass the $tries value to the levelComplete JavaScript function.
Use the WebAssembly Binary Toolkit to generate the Wasm file from the text format.
Paste the contents of your cards.wast file into the top-left pane and then download the WebAssembly file. Give the downloaded file the name cards.wasm.
Copy the cards.wasm file to the server for use by the browser and then test your changes.
The summary screen with the number of tries included.

  Summary

In this chapter, you learned the following:

  • Emscripten offers the EMCC_DEBUG environment variable and the -v flag to control debug mode. When enabled, debug mode causes logs and intermedia files to be output.
  • Emscripten also has several -g flags for progressively more debug information in the compiled output. In addition to the increased debug information, Emscripten also outputs a text format equivalent version (.wast) of the generated binary file that can be helpful in tracking down issues.
  • Logging information to the browser’s console is one way to debug what’s happening in your module.
  • The -g4 flag can be used to instruct Emscripten to generate source maps so that your C or C++ code can be viewed in the browser. At the time of this book’s writing, this feature still needs some work in the browsers.
  • In some browsers you can view the text format version of the binary file that was loaded. You can set breakpoints, step through the code and, depending on the browser either view the variable’s value or view the values that are on the stack.
  • At the moment browser debugging features are not uniform across browsers so you may need to switch between browsers based on your debugging needs.

FAQ

What practical debugging options do I have for WebAssembly modules today?Make small, frequent changes and test often; enable verbose compiler output with EMCC_DEBUG or the -v flag; add logging from the module (via imports, Emscripten macros, or printf) to the browser console; step through code with browser developer tools; and compile with -g flags to emit extra debug info and a text (.wast/.wat) version. The -g4 flag can also emit source maps to view C/C++ in the browser, though support is still imperfect.
How do I turn on verbose output from Emscripten and what does it give me?Set the EMCC_DEBUG environment variable or pass -v to the compiler. You’ll get detailed logs and intermediate files that help trace compilation and linking issues. See Emscripten’s debugging docs for specifics.
What are the Emscripten -g flags and when should I use them?The -g flags (-g0 to -g4) progressively include more debug info; -g is the same as -g3. They also generate a text format file that mirrors the binary, which is useful for diagnosing import/export mismatches and linking problems. -g4 adds source maps to view original C/C++ in the browser, with current limitations.
Why does Chrome or Firefox show function/global indexes instead of my names, and how do I cope?DevTools often display wasm functions and globals by index, not by your symbolic names. Keep your original text format or source code open to map indexes to names. In Firefox, the Scopes pane shows global variables by index; in Chrome, you can inspect the stack values while stepping.
How do I view and step through WebAssembly in browser developer tools?Open DevTools (F12). In Chrome, use the Sources tab and expand the “wasm” section to see modules and functions; set breakpoints on lines. In Firefox, use the Debugger tab, open the wasm file, and set breakpoints; then trigger the code path in the page to step through instructions.
I get “type mismatch in function” from wat2wasm. What typically causes this?This often indicates a mismatch between a function’s declared signature and the arguments on the stack at the call site. A common culprit is forgetting to update an imported function’s signature after adding parameters, which leaves extra values on the stack and breaks validation. Update the import signature and call sites to match.
What is a WebAssembly LinkError and how do I fix a missing import like “_UpdateTriesTotal”?LinkError occurs during module instantiation when imports don’t match (missing, wrong name, or wrong type). Ensure your import object (usually env) provides a property whose name exactly matches the import name and whose value is a function with the expected signature. Then reload and re-test.
How can I log values from my WebAssembly code to help diagnose issues?Use an imported JavaScript function (e.g., one that calls console.log), Emscripten’s logging macros, or printf if stdout is wired to the console. Start with logs near suspected problem areas and expand as you narrow down the cause.
Why does stepping over a line in C/C++ take multiple steps or show odd variable names with -g4?Source maps currently map a single high-level statement to multiple wasm instructions, so “step over” may advance through several ops. Local names may be compiler-generated (like var0), and watches on original identifiers can be unreliable. It’s usable but still maturing.
My counter increments by the wrong amount. How do I track this down?Set a breakpoint in the relevant wasm function, then step through the instructions that update the counter. Inspect get_global and i32.const operands and the i32.add to confirm the intended increment (e.g., 1 vs 10). Correct the constant or logic, rebuild the module, and retest.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • WebAssembly in Action ebook for free