Skip to content

Commit 1942fd6

Browse files
Fix expansion of "floating" WASM variables in repl/watch + readMemory when WASM memory is SharedArrayBuffer (#2199)
* Fix expansion of "floating" WASM variables in repl/watch + readMemory when WASM memory is SharedArrayBuffer * Fix flaky test
1 parent afdb804 commit 1942fd6

File tree

10 files changed

+103
-12
lines changed

10 files changed

+103
-12
lines changed

src/adapter/dwarf/wasmSymbolProvider.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ export interface IWasmSymbols extends IDisposable {
345345
callFrameId: string,
346346
position: IPosition,
347347
expression: string,
348-
): Promise<Cdp.Runtime.RemoteObject | undefined>;
348+
): Promise<IWasmVariableEvaluation>;
349349

350350
/**
351351
* Gets ranges that should be stepped for the given step kind and location.
@@ -681,9 +681,9 @@ class WasmSymbols extends DecompiledWasmSymbols {
681681
callFrameId: string,
682682
position: IPosition,
683683
expression: string,
684-
): Promise<Cdp.Runtime.RemoteObject | undefined> {
684+
): Promise<IWasmVariableEvaluation> {
685685
try {
686-
const r = await this.worker.rpc.sendMessage(
686+
const result = await this.worker.rpc.sendMessage(
687687
'evaluate',
688688
expression,
689689
{
@@ -694,8 +694,7 @@ class WasmSymbols extends DecompiledWasmSymbols {
694694
this.worker.getStopId(callFrameId),
695695
);
696696

697-
// cast since types in dwarf-debugging are slightly different than generated cdp API
698-
return (r as Cdp.Runtime.RemoteObject) ?? undefined;
697+
return result ? new WasmVariableEvaluation(result, this.worker.rpc) : nullType;
699698
} catch (e) {
700699
// errors are expected here if the user tries to evaluate expressions
701700
// the simple lldb-eval can't handle.

src/adapter/templates/readMemory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export const readMemory = remoteFunction(function(
1212
start: number,
1313
count: number,
1414
) {
15-
const { buffer, byteLength, byteOffset } = this instanceof ArrayBuffer
15+
const { buffer, byteLength, byteOffset } = (this instanceof ArrayBuffer
16+
|| (typeof SharedArrayBuffer !== 'undefined' && this instanceof SharedArrayBuffer))
1617
? new DataView(this)
1718
: this instanceof WebAssembly.Memory
1819
? new DataView(this.buffer)

src/adapter/threads.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,11 +524,10 @@ export class Thread implements IVariableStoreLocationProvider {
524524
);
525525

526526
const result = await symbols.evaluate(cfId, position, args.expression);
527-
if (result) {
528-
return await variables
529-
.createFloatingVariable(args.expression, result)
530-
.toDap(args.context as PreviewContextType, args.format);
531-
}
527+
528+
return await variables
529+
.createFloatingWasmVariable(args.expression, result, root, cfId)
530+
.toDap(args.context as PreviewContextType, args.format);
532531
}
533532

534533
/**

src/adapter/variableStore.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ class VariableContext {
287287
return this.createVariable(Variable, ctx, object);
288288
}
289289

290+
public createWasmVariable(
291+
ctx: IContextInit,
292+
evaluation: IWasmVariableEvaluation,
293+
scopeRef: IScopeRef,
294+
) {
295+
return this.createVariable(WasmVariable, ctx, evaluation, scopeRef);
296+
}
297+
290298
/**
291299
* Ensures symbols for custom descriptions are available, must be used
292300
* before getStringProps/getToStringIfCustom
@@ -1432,6 +1440,22 @@ export class VariableStore {
14321440
return ctx.createVariableByType({ name: expression }, value);
14331441
}
14341442

1443+
/** Creates a wasm variable not attached to any specific scope. */
1444+
public createFloatingWasmVariable(
1445+
expression: string,
1446+
evaluation: IWasmVariableEvaluation,
1447+
stackFrame: StackFrame,
1448+
callFrameId: Cdp.Debugger.CallFrameId,
1449+
): IVariable {
1450+
const ctx = this.createFloatingContext();
1451+
const scopeRef: IScopeRef = {
1452+
stackFrame,
1453+
callFrameId,
1454+
scopeNumber: 0, // this is only used for setting variables, which wasm doesn't support
1455+
};
1456+
return ctx.createWasmVariable({ name: expression }, evaluation, scopeRef);
1457+
}
1458+
14351459
/**
14361460
* Returns the variable reference for a complex, object-including output.
14371461
*/

src/test/common/cdpTransport.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ describe('cdp transport', () => {
6161
b.onMessage(([msg]) => actual.push(msg));
6262

6363
for (let i = 0; i < rawData.length;) {
64-
const consume = Math.floor(Math.random() * 20);
64+
const consume = 1 + Math.floor(Math.random() * 20);
6565
const str = rawData.slice(i, i + consume).toString('base64');
6666
expected.push(str);
6767
a.send(str);

src/test/wasm/wasm.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,5 +227,19 @@ describe('webassembly', () => {
227227

228228
r.assertLog();
229229
});
230+
231+
itIntegrates('does lldb evaluation for structs', async ({ r, context }) => {
232+
const p = await prepare(r, context, 'c-with-struct', {
233+
source: { path: 'web/dwarf/c-with-struct.c' },
234+
breakpoints: [{ line: 11 }],
235+
});
236+
237+
const { threadId } = p.log(await p.dap.once('stopped'));
238+
const { id: frameId } = (await p.dap.stackTrace({ threadId })).stackFrames[0];
239+
240+
await p.logger.evaluateAndLog('(data_t*)data', { params: { frameId }, depth: 3 });
241+
242+
r.assertLog();
243+
});
230244
});
231245
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
allThreadsStopped : false
3+
description : Paused on breakpoint
4+
reason : breakpoint
5+
threadId : <number>
6+
}
7+
> result: data_t *
8+
> 0x10408: data_t
9+
> id: char[12]
10+
0: 'H'
11+
1: 'e'
12+
2: 'l'
13+
3: 'l'
14+
4: 'o'
15+
5: ' '
16+
6: 'w'
17+
7: 'o'
18+
8: 'r'
19+
9: 'l'
20+
10: 'd'
21+
11: '\0'
22+
x: 12
23+
y: 34
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
// Compile with:
3+
// clang -O0 -g -fdebug-compilation-dir=. --target=wasm32-unknown-unknown -nostdlib c-with-struct.c -o c-with-struct.wasm
4+
typedef struct data_t {
5+
char id[12];
6+
int x;
7+
int y;
8+
} data_t;
9+
10+
int process(void *data) {
11+
return 0; // Break here and evaluate (data_t*)data in the repl interface
12+
}
13+
14+
int _start() {
15+
data_t data = { .id = "Hello world", .x = 12, .y = 34 };
16+
return process(&data);
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<title>C with struct</title>
5+
<meta charset="utf-8">
6+
</head>
7+
<body>
8+
</body>
9+
<script>
10+
WebAssembly
11+
.instantiateStreaming(fetch('c-with-struct.wasm'))
12+
.then(({ instance }) => instance.exports._start());
13+
</script>
14+
</html>
1.23 KB
Binary file not shown.

0 commit comments

Comments
 (0)