Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Mock Disassembly Adapter

A self-contained debug adapter that reproduces the VS Code Disassembly View source resolution bugs without a real debugger, a real target, or a remote window.

No build step and no dependencies — plain CommonJS, loaded straight from source.

The program

Everything is counted, nothing is realistic, so that wrong output is obvious at a glance:

instruction n  ->  address 0x1000 + n, mnemonic `in`

100 instructions over the 60 lines of demo.c, in two halves.

Lines 1–40 map one to one, two instructions each, with no endLine:

source line L  ->  instructions i(2L-2) and i(2L-1)

/* line 01  ->  i0   i1   */
/* line 02  ->  i2   i3   */
...
/* line 40  ->  i78  i79  */

Lines 41–60 are covered by ranges, so that one row has to reserve several source lines. A block spanning N lines carries N instructions, and the blocks widen from two lines to six:

/* line 41  ->  range 41-42  ->  i80 i81                 */
/* line 43  ->  range 43-45  ->  i82 i83 i84             */
/* line 46  ->  range 46-49  ->  i85 i86 i87 i88         */
/* line 50  ->  range 50-54  ->  i89 i90 i91 i92 i93     */
/* line 55  ->  range 55-60  ->  i94 i95 i96 i97 i98 i99 */

Only the first instruction of a block shows the source, so a block renders as one tall source cell followed by bare instruction rows — which is exactly the shape that has to stay right when the source cannot be loaded.

So a correct view reads i0, i1, i2, … downwards with no gaps and no repeats, and every row sits under the source line or range that names it. Any repeat, any backwards step, any row under the wrong line is the bug — the row is displaying the instruction of whatever element the recycled row template was previously bound to. Instructions outside i0i99 carry no source location, which is legal and keeps the mapping honest.

The session starts at i78 (address 0x104E, line 40), the last one-to-one row, so both halves are on screen at once.

demo.c is generated from MULTI_LINE_BLOCKS in extension.js; changing the blocks means rewriting the matching comments.

Running

code --extensionDevelopmentPath=<this-folder> <this-folder>

Works the same for stock VS Code and for a self-built OSS build (scripts/code.bat / scripts/code.sh instead of code). Then:

  1. Pick one of the four configurations in the Run and Debug dropdown, press F5.
  2. The session stops immediately.
  3. Right-click the frame in the Call Stack view → Open Disassembly View. (Right-clicking inside demo.c works too, since the debugger contribution claims c.)
  4. Scroll the Disassembly View up and down a few screens. Row recycling is what makes the render-order bug visible, so scrolling matters. Scroll down past i79 for the multi-line blocks, which recycle tall rows into short ones and back.

The Mock Disassembly Adapter output channel logs the scenario and every request.

What each scenario reports

The adapter puts the same Source object in its stackTrace and disassemble responses, so any difference between how the editor and the Disassembly View behave is VS Code's alone.

Content served over a source request is tagged with /* from adapter */ on every line. That is the tell: if you see the tag, the view fetched over DAP; if you do not, it read the file from disk.

sourceReference reported path reads content from
A 0 real demo.c
B 0 /nonexistent/build-server/demo.c
C 1234 real demo.c demo.c
D 1234 /nonexistent/build-server/demo.c demo.c

Expected results

The two fixes land in separate PRs, so the middle column is what the render-order fix alone buys.

stock VS Code + render-order fix + sourceReference fix
A source shown, untagged (from disk) — correct unchanged unchanged
B mnemonics out of order / repeated, no source i0, i1, i2, … in order, every reserved source line reads (… unavailable) unchanged
C source shown untagged — wrong, the reference was ignored unchanged source shown tagged — fetched from the adapter
D mnemonics out of order / repeated, no source in order, with the (… unavailable) placeholder source shown tagged, mnemonics in order

In B, the multi-line blocks are where the placeholder earns its keep: the row height is fixed before the source is resolved and cannot shrink afterwards, so a six-line block reserves six source lines whether or not anything can be loaded into them. Stock VS Code leaves all six blank under a mnemonic; the fix names every one of them:

  55: (/nonexistent/build-server/demo.c unavailable)
  56: (/nonexistent/build-server/demo.c unavailable)
  57: (/nonexistent/build-server/demo.c unavailable)
  58: (/nonexistent/build-server/demo.c unavailable)
  59: (/nonexistent/build-server/demo.c unavailable)
  60: (/nonexistent/build-server/demo.c unavailable)
i94

What each scenario proves

A is the control. Everything works, in every build.

B shows the render-order bug on its own: sourceReference is 0, so VS Code builds exactly the URI it should, and the source genuinely is not there. The correct outcome is a row with no source code. Instead the row silently keeps the previous row's address and mnemonic. This needs no remote and no unusual adapter — it is what anyone gets when debugging a binary whose DWARF paths point at a build server.

C shows the wrong-URI bug with nothing failing. The path resolves, so the view happily renders source — but it renders the file from disk rather than the content the adapter is holding, which is what a non-zero sourceReference requires. Compare against the editor, which opens the tagged adapter copy from the same Source object. Two views, one source, two answers.

D is C and B together, and is the WSL case reproduced locally: a non-zero sourceReference plus a path the machine running the UI cannot resolve. The editor opens the file correctly over DAP; the Disassembly View goes to the file system, fails, and corrupts.

Notes

  • The adapter never really runs. Continue and step just move the program counter by one instruction and stop again, which is enough to force the view to re-render.
  • To try other paths without editing the code, set missingPath in the launch configuration.

About

Small demo to reproduce Disassembly View bugs in VS Code

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages