v8/test/inspector/debugger/wasm-step-after-trap.js
Clemens Backes faf3d4c8e4 [debug][liftoff] Test inspection and stepping at trap
Add a test to stop at a trap, inspect values, and step from there.
For inspection, we need to spill all registers, which we usually don't
do because the trap never returns, so the values won't be used
afterwards.

R=thibaudm@chromium.org

Bug: v8:10235
Change-Id: Ia1c21aa0faa3ca656e40aae626e8e912eaf2c233
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2169890
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67477}
2020-04-29 16:05:22 +00:00

103 lines
3.4 KiB
JavaScript

// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const {session, contextGroup, Protocol} =
InspectorTest.start('Test scope inspection and stepping after a trap.');
session.setupScriptMap();
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder();
// Create a function which computes the div of the first two arguments.
builder.addFunction('div', kSig_i_iii)
.addLocals(
{i32_count: 2}, ['a', 'b', 'unused', 'local_zero', 'local_const_11'])
.addBody([
kExprI32Const, 11, // const 11
kExprLocalSet, 4, // set local #4 ('local_const_11')
kExprLocalGet, 0, // param 0
kExprLocalGet, 1, // param 1
kExprI32DivS // div
])
.exportFunc();
const module_bytes = JSON.stringify(builder.toArray());
function instantiate(bytes) {
let buffer = new ArrayBuffer(bytes.length);
let view = new Uint8Array(buffer);
for (let i = 0; i < bytes.length; ++i) {
view[i] = bytes[i] | 0;
}
let module = new WebAssembly.Module(buffer);
return new WebAssembly.Instance(module);
}
function getShortLocationString(location) {
return `${location.lineNumber}:${location.columnNumber}`;
}
let actions =
['stepInto', 'resume', 'stepInto', 'resume', 'stepInfo', 'resume'];
Protocol.Debugger.onPaused(async msg => {
InspectorTest.log('Paused at:');
for (let [nr, frame] of msg.params.callFrames.entries()) {
InspectorTest.log(`--- ${nr} ---`);
await session.logSourceLocation(frame.location);
if (/^wasm/.test(frame.url)) await printLocalScope(frame);
}
InspectorTest.log('-------------');
let action = actions.shift();
InspectorTest.log(`-> ${action}`);
Protocol.Debugger[action]();
});
function call_div() {
instance.exports.div(0, 1, 4711); // does not trap
try {
instance.exports.div(1, 0, 4711); // traps (div by zero)
} catch (e) {
e.stack; // step target of first pause
}
try {
instance.exports.div(0x80000000, -1, 4711); // traps (unrepresentable)
} catch (e) {
e.stack; // step target of second pause
}
}
contextGroup.addScript(instantiate.toString());
contextGroup.addScript(call_div.toString());
(async function test() {
await Protocol.Debugger.enable();
await Protocol.Debugger.setPauseOnExceptions({state: 'all'});
InspectorTest.log('Instantiating.');
await Protocol.Runtime.evaluate(
{'expression': `const instance = instantiate(${module_bytes});`});
InspectorTest.log('Calling div function.');
await Protocol.Runtime.evaluate({'expression': 'call_div()'});
InspectorTest.log('Finished.');
InspectorTest.completeTest();
})();
async function printLocalScope(frame) {
InspectorTest.log(`scope at ${frame.functionName} (${
frame.location.lineNumber}:${frame.location.columnNumber}):`);
for (let scope of frame.scopeChain) {
if (scope.type != 'local') continue;
let properties = await Protocol.Runtime.getProperties(
{'objectId': scope.object.objectId});
for (let value of properties.result.result) {
let msg = await Protocol.Runtime.getProperties(
{objectId: value.value.objectId});
let prop_str = p => `"${p.name}": ${p.value.value}`;
let value_str = msg.result.result.map(prop_str).join(', ');
InspectorTest.log(` ${value.name}: ${value_str}`);
}
}
}