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

First version of DebuggingFramework.md. #708

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions DebuggingFramework.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#WebAssembly Debugging

This is a design proposal for enabling source-level debugging of WebAssembly
modules.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit redundant, given that we're in the design repo ;-)


## Introduction

There are several entities involved in debugging a source program compiled into
WebAssembly:

- the compiled code being executed, called the _debuggee_
- the browser engine executing the debuggee
- the browser devtools
- the source-program listing, usually split into multiple source files
- the description of how the debuggee code maps to the source program and vice
versa (e.g., WebAssembly code locations to source code locations, source
variables to WebAssembly memory, WebAssembly call stack to source functions,
etc.), called the _debug info_

These entities carry information and interact in particular ways to enable a
user to perform debugging actions at the source-code level. For example, the
browser devtools offer a UI allowing the user to step through the source code,
requiring partial execution of the debuggee chunk corresponding to each step,
and displaying the source file containing the stepped-through program.

Specifying the debugging framework means describing how these entities interact,
what they need from each other, and how they access it; all in order to execute
the user's commands.

## Debugger as a Procedural Interface

A crucial element of this design proposal is to omit specifying a particular
format for the debug info. Instead, we introduce a separate entity we call the
debugger; its job is to act as a procedural intermediary between the devtools
and the debug info. Devtools execute user actions by leveraging debugger
methods we will specify here.

Thus any debug-info format is acceptable, as long as the debugger can correctly
interpret it. The format is, in effect, a convention between the front-end
parsing the source and the debugger.

What the design _does_ specify is two interaction protocols:

1. between the devtools and the debugger, and
2. between the debugger and the wasm execution engine

## Action Flow

For reference, the entities are charted in the figure below:

![Entities making up the debug framework](wasm-debug-chart.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice chart! I'd put the "Debugger" box inside the browser box since it's executing JS or wasm code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt that the wasm module and the debugger should be shown outside, because they don't come with the browser but are downloaded. Then I try to explain in the text how they are used by the browser when obtained.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC 4. and 5. are what you're specifying here, right? It sounds like @lukewagner wants to drop 3. from the diagram, but you'd rather keep it because it can be separate (not being specified in this doc)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this aims to specify 3 and 5, while leaving 4 unspecified (other than saying how the debugger can find the debug info and source files). The way the debugger interprets the debug info will be hidden from other actors in this picture, freeing the debugger implementers to choose whatever suits them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point and just noticed that "wasm module" is also, symmetrically, outside the box.


(The figure uses the conventional phrase "wasm module" to refer to a debuggee.
For now, we overlook the complexities of multiple wasm modules or mixing JS and
wasm on the same call stack.)

Black arrows in the figure indicate the action flow and timeline:

1. When the page is first rendered, the debuggee is loaded into the browser and
sent to the wasm execution engine.
2. The user interacts with the browser's devtools UI (eg, requesting a source
listing for a function to set a breakpoint).
3. Devtools call on the debugger to execute operation(s) necessary to fulfilling
the user's request. After going through steps 4 and/or 5, the debugger
returns a result for the devtools to display.
4. The debugger consults the debug info and/or source files to obtain the proper
mapping between the source code and the wasm.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the chart lacks an arrow from the source files to the debugger.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I felt the extra arrow would clutter the picture without adding much information value. I glommed the debug info and source files rectangles together to suggest that they act in unison.

5. Optionally, the debugger requests information from the browser, such as
examining the wasm memory or call stack in the execution engine.

Note that 3 and 5 are bidirectional arrows: sometimes the flow of action goes
from the browser through the debugger to devtools. For instance, this will
happen when a breakpoint is hit and the wasm execution is paused. The browser
will then notify the debugger, who will in turn notify devtools after
translating the wasm program counter to the corresponding source line.

## About the Debugger

We propose that the debugger be a JavaScript library providing the interface
described in the next section. This allows for easy access to the browser, as
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd s/JavaScript library/JavaScript API/ and then note that in the future (perhaps linking to GC.md), wasm would be able to access the API directly so that the debugger could be compiled wasm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd also be good to point out the option of having this same API debug JS (maybe not in the initial version of the API, but after some iteration).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

well as ease of implementation because JavaScript is widely known and supported.

This also makes it possible for the debuggee to contain a URL for the debugger
to be used on it. This URL can point to any server, allowing debugger reuse
among many debuggees.

## UI -> Debugger Protocol Operations

First, we list the basic debugger operations that the UI can invoke:

- get a source location given a mangled function name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To understand what are the right set of primitives/operations here, it'd be nice to outline some end-to-end flows from user action to UI response to the action.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm working on a Chrome prototype that does just that. Armed with that experience, I'll summarize here some of the end-to-end flows.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

- get a function signature given a mangled function name
- get the source given a location
- set a breakpoint at a given location
- interrupt the ongoing debuggee execution
- get the source location for the current debuggee execution point
- step into the next source line, descending into function calls
- step over the next source line
- get the current value of a given identifier (descending into struct members)
- set the current value of a given identifier (descending into struct members)
- get the type of a given identifier (descending into struct members)
- get the current call stack as a list of source locations
- return a given value from the current function

(TODO: specify parameters and results for the above operations; also describe
custom types like "source location")

## Debugger -> UI Notifications

- a step into/over has completed
- a breakpoint was hit
- an uncaught exception was thrown
- `abort()` was called
- `exit()` was called

(TODO: specify parameters and results)

## About Debug Info and Source Files

The debugger will need to access the debug info and source files for the current
debuggee. The debuggee can specify URLs for these items. Their format is not
specified -- it can be anything that the debugger knows how to interpret.

## Debugger -> Debuggee Protocol Operations

- interrupt execution
- set a breakpoint at a given byte offset
- get the current call stack
- execute the current wasm instruction and move on to the next one
- get the value of a wasm memory location
- set the value of a wasm memory location

(TODO: specify parameters and results)

## Debuggee -> Debugger Notifications

- an uncaught exception was thrown

(TODO: specify parameters and results)
Binary file added wasm-debug-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.