Commit beaf1073 authored by Guanzhong Chen's avatar Guanzhong Chen Committed by Commit Bot

[wasm] use standard WebAssembly stack trace format

Currently, in wasm-function stack traces, v8 displays the decimal offset
from the start of the function. However, the WebAssembly WebAPI
specification says that it should be a hex offset into the module.

This change makes the stack trace display with hex module offsets, as
well as fixing all the unit tests that depended on the old behaviour.

R=fgm@chromium.org, titzer@chromium.org, yangguo@chromium.org

Bug: v8:9172
Change-Id: I73737a319a42dd665521ab8a4b825199ae11c87f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1646846Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Guanzhong Chen <gzchen@google.com>
Cr-Commit-Position: refs/heads/master@{#62103}
parent af927dac
...@@ -769,7 +769,11 @@ void WasmStackFrame::ToString(IncrementalStringBuilder& builder) { ...@@ -769,7 +769,11 @@ void WasmStackFrame::ToString(IncrementalStringBuilder& builder) {
DCHECK(wasm_func_index_ <= kMaxInt); DCHECK(wasm_func_index_ <= kMaxInt);
builder.AppendInt(static_cast<int>(wasm_func_index_)); builder.AppendInt(static_cast<int>(wasm_func_index_));
builder.AppendCString("]:"); builder.AppendCString("]:");
builder.AppendInt(GetPosition());
int function_offset = module_object->GetFunctionOffset(wasm_func_index_);
char buffer[16];
SNPrintF(ArrayVector(buffer), "0x%x", function_offset + GetPosition());
builder.AppendCString(buffer);
if (has_name) builder.AppendCString(")"); if (has_name) builder.AppendCString(")");
......
...@@ -18,8 +18,8 @@ end ...@@ -18,8 +18,8 @@ end
Getting current stack trace via "new Error().stack". Getting current stack trace via "new Error().stack".
Error Error
at v8://test/getStack:1:1 at v8://test/getStack:1:1
at func (wasm-function[0]:1) at func (wasm-function[0]:0x21)
at main (wasm-function[1]:1) at main (wasm-function[1]:0x2f)
at v8://test/runWasm:1:22 at v8://test/runWasm:1:22
exports.main returned. exports.main returned.
Finished. Finished.
...@@ -12,8 +12,8 @@ Result of evaluate (string): ...@@ -12,8 +12,8 @@ Result of evaluate (string):
Error: this is your stack trace: Error: this is your stack trace:
-- skipped -- -- skipped --
at call_debugger (<anonymous>:3:5) at call_debugger (<anonymous>:3:5)
at call_func (wasm-function[1]:1) at call_func (wasm-function[1]:0x37)
at main (wasm-function[2]:3) at main (wasm-function[2]:0x3e)
at testFunction (<anonymous>:15:20) at testFunction (<anonymous>:15:20)
at <anonymous>:1:1 at <anonymous>:1:1
Finished! Finished!
wasm-function[0]:5: RuntimeError: wasm exception wasm-function[0]:5: RuntimeError: wasm exception
RuntimeError: wasm exception RuntimeError: wasm exception
at rethrow0 (wasm-function[0]:5) at rethrow0 (wasm-function[0]:0x32)
at *%(basename)s:21:18 at *%(basename)s:21:18
wasm-function[0]:3: RuntimeError: wasm exception wasm-function[0]:3: RuntimeError: wasm exception
RuntimeError: wasm exception RuntimeError: wasm exception
at throw0 (wasm-function[0]:3) at throw0 (wasm-function[0]:0x2e)
at *%(basename)s:17:18 at *%(basename)s:17:18
wasm-function[0]:1: RuntimeError: unreachable wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable RuntimeError: unreachable
at main (wasm-function[0]:1) at main (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:31 at *%(basename)s:{NUMBER}:31
wasm-function[0]:1: RuntimeError: unreachable wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable RuntimeError: unreachable
at test-module.main (wasm-function[0]:1) at test-module.main (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:31 at *%(basename)s:{NUMBER}:31
wasm-function[0]:1: RuntimeError: unreachable wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable RuntimeError: unreachable
at test-module (wasm-function[0]:1) at test-module (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:31 at *%(basename)s:{NUMBER}:31
wasm-function[0]:1: RuntimeError: unreachable wasm-function[0]:1: RuntimeError: unreachable
RuntimeError: unreachable RuntimeError: unreachable
at wasm-function[0]:1 at wasm-function[0]:0x22
at *%(basename)s:{NUMBER}:31 at *%(basename)s:{NUMBER}:31
wasm-function[0]:5: RuntimeError: divide by zero wasm-function[0]:5: RuntimeError: divide by zero
RuntimeError: divide by zero RuntimeError: divide by zero
at main (wasm-function[0]:5) at main (wasm-function[0]:0x26)
at *%(basename)s:{NUMBER}:16 at *%(basename)s:{NUMBER}:16
RuntimeError: unreachable RuntimeError: unreachable
at main (wasm-function[0]:1) at main (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:27 at *%(basename)s:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at main (wasm-function[0]:1) at main (wasm-function[0]:0x22)
at test/message/wasm-function-name-async.js:{NUMBER}:27 at test/message/wasm-function-name-async.js:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at test-module.main (wasm-function[0]:1) at test-module.main (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:27 at *%(basename)s:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at test-module.main (wasm-function[0]:1) at test-module.main (wasm-function[0]:0x22)
at test/message/wasm-module-and-function-name-async.js:{NUMBER}:27 at test/message/wasm-module-and-function-name-async.js:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at test-module (wasm-function[0]:1) at test-module (wasm-function[0]:0x22)
at *%(basename)s:{NUMBER}:27 at *%(basename)s:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at test-module (wasm-function[0]:1) at test-module (wasm-function[0]:0x22)
at test/message/wasm-module-name-async.js:{NUMBER}:27 at test/message/wasm-module-name-async.js:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at wasm-function[0]:1 at wasm-function[0]:0x22
at *%(basename)s:{NUMBER}:27 at *%(basename)s:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
RuntimeError: unreachable RuntimeError: unreachable
at wasm-function[0]:1 at wasm-function[0]:0x22
at test/message/wasm-no-name-async.js:{NUMBER}:27 at test/message/wasm-no-name-async.js:{NUMBER}:27
at test/mjsunit/mjsunit.js:* at test/mjsunit/mjsunit.js:*
...@@ -184,8 +184,8 @@ function redirectToInterpreter( ...@@ -184,8 +184,8 @@ function redirectToInterpreter(
checkStack(stripPath(e.stack), [ checkStack(stripPath(e.stack), [
'Error: i=8', // - 'Error: i=8', // -
/^ at imp \(file:\d+:29\)$/, // - /^ at imp \(file:\d+:29\)$/, // -
' at plus_one (wasm-function[1]:6)', // - ' at plus_one (wasm-function[1]:0x3b)', // -
' at plus_two (wasm-function[1]:3)', // - ' at plus_two (wasm-function[1]:0x3e)', // -
/^ at testStackTraceThroughCWasmEntry \(file:\d+:25\)$/, // - /^ at testStackTraceThroughCWasmEntry \(file:\d+:25\)$/, // -
/^ at file:\d+:3$/ /^ at file:\d+:3$/
]); ]);
......
...@@ -39,7 +39,7 @@ function checkStack(stack, expected_lines) { ...@@ -39,7 +39,7 @@ function checkStack(stack, expected_lines) {
checkStack(stripPath(stack), [ checkStack(stripPath(stack), [
'Error: test imported stack', // - 'Error: test imported stack', // -
/^ at func \(interpreter.js:\d+:28\)$/, // - /^ at func \(interpreter.js:\d+:28\)$/, // -
' at main (wasm-function[1]:1)', // - ' at main (wasm-function[1]:0x32)', // -
/^ at testCallImported \(interpreter.js:\d+:22\)$/, // - /^ at testCallImported \(interpreter.js:\d+:22\)$/, // -
/^ at interpreter.js:\d+:3$/ /^ at interpreter.js:\d+:3$/
]); ]);
...@@ -103,8 +103,8 @@ function checkStack(stack, expected_lines) { ...@@ -103,8 +103,8 @@ function checkStack(stack, expected_lines) {
assertEquals(interpreted_before + 2, %WasmNumInterpretedCalls(instance)); assertEquals(interpreted_before + 2, %WasmNumInterpretedCalls(instance));
checkStack(stripPath(stack), [ checkStack(stripPath(stack), [
'RuntimeError: unreachable', // - 'RuntimeError: unreachable', // -
' at foo (wasm-function[0]:3)', // - ' at foo (wasm-function[0]:0x27)', // -
' at main (wasm-function[1]:2)', // - ' at main (wasm-function[1]:0x2c)', // -
/^ at testTrap \(interpreter.js:\d+:24\)$/, // - /^ at testTrap \(interpreter.js:\d+:24\)$/, // -
/^ at interpreter.js:\d+:3$/ /^ at interpreter.js:\d+:3$/
]); ]);
...@@ -136,7 +136,7 @@ function checkStack(stack, expected_lines) { ...@@ -136,7 +136,7 @@ function checkStack(stack, expected_lines) {
checkStack(stripPath(stack), [ checkStack(stripPath(stack), [
'Error: thrown from imported function', // - 'Error: thrown from imported function', // -
/^ at func \(interpreter.js:\d+:11\)$/, // - /^ at func \(interpreter.js:\d+:11\)$/, // -
' at main (wasm-function[1]:1)', // - ' at main (wasm-function[1]:0x32)', // -
/^ at testThrowFromImport \(interpreter.js:\d+:24\)$/, // - /^ at testThrowFromImport \(interpreter.js:\d+:24\)$/, // -
/^ at interpreter.js:\d+:3$/ /^ at interpreter.js:\d+:3$/
]); ]);
...@@ -218,10 +218,10 @@ function checkStack(stack, expected_lines) { ...@@ -218,10 +218,10 @@ function checkStack(stack, expected_lines) {
for (var e = 0; e < stacks.length; ++e) { for (var e = 0; e < stacks.length; ++e) {
expected = ['Error: reentrant interpreter test #' + e]; expected = ['Error: reentrant interpreter test #' + e];
expected.push(/^ at func \(interpreter.js:\d+:17\)$/); expected.push(/^ at func \(interpreter.js:\d+:17\)$/);
expected.push(' at main (wasm-function[1]:3)'); expected.push(' at main (wasm-function[1]:0x36)');
for (var k = e; k > 0; --k) { for (var k = e; k > 0; --k) {
expected.push(/^ at func \(interpreter.js:\d+:33\)$/); expected.push(/^ at func \(interpreter.js:\d+:33\)$/);
expected.push(' at main (wasm-function[1]:3)'); expected.push(' at main (wasm-function[1]:0x36)');
} }
expected.push( expected.push(
/^ at testReentrantInterpreter \(interpreter.js:\d+:22\)$/); /^ at testReentrantInterpreter \(interpreter.js:\d+:22\)$/);
...@@ -296,8 +296,8 @@ function checkStack(stack, expected_lines) { ...@@ -296,8 +296,8 @@ function checkStack(stack, expected_lines) {
if (!(e instanceof TypeError)) throw e; if (!(e instanceof TypeError)) throw e;
checkStack(stripPath(e.stack), [ checkStack(stripPath(e.stack), [
'TypeError: ' + kTrapMsgs[kTrapTypeError], // - 'TypeError: ' + kTrapMsgs[kTrapTypeError], // -
' at direct (wasm-function[1]:1)', // - ' at direct (wasm-function[1]:0x55)', // -
' at main (wasm-function[3]:3)', // - ' at main (wasm-function[3]:0x64)', // -
/^ at testIllegalImports \(interpreter.js:\d+:22\)$/, // - /^ at testIllegalImports \(interpreter.js:\d+:22\)$/, // -
/^ at interpreter.js:\d+:3$/ /^ at interpreter.js:\d+:3$/
]); ]);
...@@ -309,8 +309,8 @@ function checkStack(stack, expected_lines) { ...@@ -309,8 +309,8 @@ function checkStack(stack, expected_lines) {
if (!(e instanceof TypeError)) throw e; if (!(e instanceof TypeError)) throw e;
checkStack(stripPath(e.stack), [ checkStack(stripPath(e.stack), [
'TypeError: ' + kTrapMsgs[kTrapTypeError], // - 'TypeError: ' + kTrapMsgs[kTrapTypeError], // -
' at indirect (wasm-function[2]:3)', // - ' at indirect (wasm-function[2]:0x5c)', // -
' at main (wasm-function[3]:3)', // - ' at main (wasm-function[3]:0x64)', // -
/^ at testIllegalImports \(interpreter.js:\d+:22\)$/, // - /^ at testIllegalImports \(interpreter.js:\d+:22\)$/, // -
/^ at interpreter.js:\d+:3$/ /^ at interpreter.js:\d+:3$/
]); ]);
...@@ -358,8 +358,8 @@ function checkStack(stack, expected_lines) { ...@@ -358,8 +358,8 @@ function checkStack(stack, expected_lines) {
if (!(e instanceof RangeError)) throw e; if (!(e instanceof RangeError)) throw e;
checkStack(stripPath(e.stack), [ checkStack(stripPath(e.stack), [
'RangeError: Maximum call stack size exceeded', 'RangeError: Maximum call stack size exceeded',
' at main (wasm-function[0]:0)' ' at main (wasm-function[0]:0x20)'
].concat(Array(9).fill(' at main (wasm-function[0]:2)'))); ].concat(Array(9).fill(' at main (wasm-function[0]:0x22)')));
} }
})(); })();
......
...@@ -23,7 +23,7 @@ function verifyStack(frames, expected) { ...@@ -23,7 +23,7 @@ function verifyStack(frames, expected) {
assertContains(exp[4], frames[i].getFileName(), "["+i+"].getFileName()"); assertContains(exp[4], frames[i].getFileName(), "["+i+"].getFileName()");
var toString; var toString;
if (exp[0]) { if (exp[0]) {
toString = "wasm-function[" + exp[2] + "]:" + exp[3]; toString = "wasm-function[" + exp[2] + "]:" + exp[5];
if (exp[1] !== null) toString = exp[1] + " (" + toString + ")"; if (exp[1] !== null) toString = exp[1] + " (" + toString + ")";
} else { } else {
toString = exp[4] + ":" + exp[2] + ":"; toString = exp[4] + ":" + exp[2] + ":";
...@@ -70,7 +70,7 @@ var module = builder.instantiate({mod: {func: STACK}}); ...@@ -70,7 +70,7 @@ var module = builder.instantiate({mod: {func: STACK}});
var expected_string = 'Error\n' + var expected_string = 'Error\n' +
// The line numbers below will change as this test gains / loses lines.. // The line numbers below will change as this test gains / loses lines..
' at STACK (stack.js:38:11)\n' + // -- ' at STACK (stack.js:38:11)\n' + // --
' at main (wasm-function[1]:1)\n' + // -- ' at main (wasm-function[1]:0x86)\n' + // --
' at testSimpleStack (stack.js:77:18)\n' + // -- ' at testSimpleStack (stack.js:77:18)\n' + // --
' at stack.js:79:3'; // -- ' at stack.js:79:3'; // --
...@@ -88,9 +88,9 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -88,9 +88,9 @@ Error.prepareStackTrace = function(error, frames) {
module.exports.main(); module.exports.main();
verifyStack(stack, [ verifyStack(stack, [
// isWasm function line pos file // isWasm function line pos file offset
[ false, "STACK", 38, 0, "stack.js"], [ false, "STACK", 38, 0, "stack.js"],
[ true, "main", 1, 1, null], [ true, "main", 1, 1, null, '0x86'],
[ false, "testStackFrames", 88, 0, "stack.js"], [ false, "testStackFrames", 88, 0, "stack.js"],
[ false, null, 97, 0, "stack.js"] [ false, null, 97, 0, "stack.js"]
]); ]);
...@@ -103,8 +103,8 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -103,8 +103,8 @@ Error.prepareStackTrace = function(error, frames) {
} catch (e) { } catch (e) {
assertContains("unreachable", e.message); assertContains("unreachable", e.message);
verifyStack(e.stack, [ verifyStack(e.stack, [
// isWasm function line pos file // isWasm function line pos file offset
[ true, "exec_unreachable", 2, 1, null], [ true, "exec_unreachable", 2, 1, null, '0x8b'],
[ false, "testWasmUnreachable", 101, 0, "stack.js"], [ false, "testWasmUnreachable", 101, 0, "stack.js"],
[ false, null, 112, 0, "stack.js"] [ false, null, 112, 0, "stack.js"]
]); ]);
...@@ -118,9 +118,9 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -118,9 +118,9 @@ Error.prepareStackTrace = function(error, frames) {
} catch (e) { } catch (e) {
assertContains("out of bounds", e.message); assertContains("out of bounds", e.message);
verifyStack(e.stack, [ verifyStack(e.stack, [
// isWasm function line pos file // isWasm function line pos file offset
[ true, null, 3, 3, null], [ true, null, 3, 3, null, '0x91'],
[ true, "call_mem_out_of_bounds", 4, 1, null], [ true, "call_mem_out_of_bounds", 4, 1, null, '0x97'],
[ false, "testWasmMemOutOfBounds", 116, 0, "stack.js"], [ false, "testWasmMemOutOfBounds", 116, 0, "stack.js"],
[ false, null, 128, 0, "stack.js"] [ false, null, 128, 0, "stack.js"]
]); ]);
...@@ -147,11 +147,11 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -147,11 +147,11 @@ Error.prepareStackTrace = function(error, frames) {
assertEquals("Maximum call stack size exceeded", e.message, "trap reason"); assertEquals("Maximum call stack size exceeded", e.message, "trap reason");
assertTrue(e.stack.length >= 4, "expected at least 4 stack entries"); assertTrue(e.stack.length >= 4, "expected at least 4 stack entries");
verifyStack(e.stack.splice(0, 4), [ verifyStack(e.stack.splice(0, 4), [
// isWasm function line pos file // isWasm function line pos file offset
[ true, "recursion", 0, 0, null], [ true, "recursion", 0, 0, null, '0x34'],
[ true, "recursion", 0, 3, null], [ true, "recursion", 0, 3, null, '0x37'],
[ true, "recursion", 0, 3, null], [ true, "recursion", 0, 3, null, '0x37'],
[ true, "recursion", 0, 3, null] [ true, "recursion", 0, 3, null, '0x37']
]); ]);
} }
})(); })();
...@@ -173,11 +173,12 @@ Error.prepareStackTrace = function(error, frames) { ...@@ -173,11 +173,12 @@ Error.prepareStackTrace = function(error, frames) {
fail('expected wasm exception'); fail('expected wasm exception');
} catch (e) { } catch (e) {
assertEquals('unreachable', e.message, 'trap reason'); assertEquals('unreachable', e.message, 'trap reason');
let hexOffset = '0x' + (unreachable_pos + 0x25).toString(16);
verifyStack(e.stack, [ verifyStack(e.stack, [
// isWasm, function, line, pos, file // isWasm, function, line, pos, file, offset
[true, 'main', 0, unreachable_pos + 1, null], // - [true, 'main', 0, unreachable_pos + 1, null, hexOffset], // -
[false, 'testBigOffset', 172, 0, 'stack.js'], //- [false, 'testBigOffset', 172, 0, 'stack.js'], //-
[false, null, 183, 0, 'stack.js'] [false, null, 184, 0, 'stack.js']
]); ]);
} }
})(); })();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment