Commit 827107a7 authored by Philip Pfaffe's avatar Philip Pfaffe Committed by Commit Bot

[wasm-debug] Let wasm scripts report correct column information.

In the debugger, wasm scripts currently do not contain meaningful column
informations. Fix that by keeping track of the offset and size of the
wasm code section inthe module and reporting that to the debugger.

Bug: chromium:1042636
Change-Id: Ie2b5d3a50952a467d256f815c16e459cb0ae600e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2011083
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Reviewed-by: 's avatarSimon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65913}
parent e56a7edb
......@@ -9731,6 +9731,26 @@ uint32_t debug::WasmScript::GetFunctionHash(int function_index) {
function_bytes.length(), 0);
}
int debug::WasmScript::CodeOffset() const {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::wasm::NativeModule* native_module = script->wasm_native_module();
const i::wasm::WasmModule* module = native_module->module();
return module->code.offset();
}
int debug::WasmScript::CodeLength() const {
i::DisallowHeapAllocation no_gc;
i::Handle<i::Script> script = Utils::OpenHandle(this);
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
i::wasm::NativeModule* native_module = script->wasm_native_module();
const i::wasm::WasmModule* module = native_module->module();
return module->code.length();
}
debug::Location::Location(int line_number, int column_number)
: line_number_(line_number),
column_number_(column_number),
......
......@@ -174,6 +174,9 @@ class WasmScript : public Script {
int GetContainingFunction(int byte_offset) const;
uint32_t GetFunctionHash(int function_index);
int CodeOffset() const;
int CodeLength() const;
};
V8_EXPORT_PRIVATE void GetLoadedScripts(
......
......@@ -121,9 +121,20 @@ class ActualScript : public V8DebuggerScript {
return v8::Just(v8::debug::WasmScript::Cast(*script)->Bytecode());
}
int startLine() const override { return m_startLine; }
int startColumn() const override { return m_startColumn; }
int startColumn() const override {
v8::HandleScope scope(m_isolate);
auto script = this->script();
if (!script->IsWasm()) return m_startColumn;
return v8::debug::WasmScript::Cast(*script)->CodeOffset();
}
int endLine() const override { return m_endLine; }
int endColumn() const override { return m_endColumn; }
int endColumn() const override {
v8::HandleScope scope(m_isolate);
auto script = this->script();
if (!script->IsWasm()) return m_endColumn;
return v8::debug::WasmScript::Cast(*script)->CodeOffset() +
v8::debug::WasmScript::Cast(*script)->CodeLength();
}
bool isSourceLoadedLazily() const override { return false; }
int length() const override {
v8::HandleScope scope(m_isolate);
......
......@@ -2079,6 +2079,7 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
int num_functions, uint32_t offset,
std::shared_ptr<WireBytesStorage> wire_bytes_storage,
int code_section_length) {
DCHECK_GE(code_section_length, 0);
TRACE_STREAMING("Start the code section with %d functions...\n",
num_functions);
if (!decoder_.CheckFunctionsCount(static_cast<uint32_t>(num_functions),
......@@ -2098,6 +2099,8 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
uses_liftoff);
job_->DoImmediately<AsyncCompileJob::PrepareAndStartCompile>(
decoder_.shared_module(), false, code_size_estimate);
decoder_.set_code_section(offset, static_cast<uint32_t>(code_section_length));
auto* compilation_state = Impl(job_->native_module_->compilation_state());
compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage));
DCHECK_EQ(job_->native_module_->module()->origin, kWasmOrigin);
......
......@@ -869,6 +869,8 @@ class ModuleDecoderImpl : public Decoder {
if (failed()) break;
DecodeFunctionBody(i, size, offset, verify_functions);
}
DCHECK_GE(pc_offset(), pos);
set_code_section(pos, pc_offset() - pos);
}
bool CheckFunctionsCount(uint32_t functions_count, uint32_t offset) {
......@@ -1126,6 +1128,10 @@ class ModuleDecoderImpl : public Decoder {
return result;
}
void set_code_section(uint32_t offset, uint32_t size) {
module_->code = {offset, size};
}
// Decodes an entire module.
ModuleResult DecodeModule(Counters* counters, AccountingAllocator* allocator,
bool verify_functions = true) {
......@@ -1958,6 +1964,10 @@ ModuleResult ModuleDecoder::FinishDecoding(bool verify_functions) {
return impl_->FinishDecoding(verify_functions);
}
void ModuleDecoder::set_code_section(uint32_t offset, uint32_t size) {
return impl_->set_code_section(offset, size);
}
SectionCode ModuleDecoder::IdentifyUnknownSection(Decoder* decoder,
const byte* end) {
WireBytesRef string = consume_string(decoder, true, "section name");
......
......@@ -192,6 +192,8 @@ class ModuleDecoder {
ModuleResult FinishDecoding(bool verify_functions = true);
void set_code_section(uint32_t offset, uint32_t size);
const std::shared_ptr<WasmModule>& shared_module() const;
WasmModule* module() const { return shared_module().get(); }
......
......@@ -238,6 +238,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
uint32_t num_declared_functions = 0; // excluding imported
uint32_t num_exported_functions = 0;
uint32_t num_declared_data_segments = 0; // From the DataCount section.
WireBytesRef code = {0, 0};
WireBytesRef name = {0, 0};
std::vector<FunctionSig*> signatures; // by signature index
std::vector<uint32_t> signature_ids; // by signature index
......
......@@ -1215,6 +1215,41 @@ STREAM_TEST(TestCompileErrorFunctionName) {
}
}
STREAM_TEST(TestSetModuleCodeSection) {
StreamTester tester;
uint8_t code[] = {
U32V_1(4), // body size
U32V_1(0), // locals count
kExprLocalGet, 0, kExprEnd // body
};
const uint8_t bytes[] = {
WASM_MODULE_HEADER, // module header
kTypeSectionCode, // section code
U32V_1(1 + SIZEOF_SIG_ENTRY_x_x), // section size
U32V_1(1), // type count
SIG_ENTRY_x_x(kLocalI32, kLocalI32), // signature entry
kFunctionSectionCode, // section code
U32V_1(1 + 1), // section size
U32V_1(1), // functions count
0, // signature index
kCodeSectionCode, // section code
U32V_1(1 + arraysize(code) * 1), // section size
U32V_1(1), // functions count
};
tester.OnBytesReceived(bytes, arraysize(bytes));
tester.OnBytesReceived(code, arraysize(code));
tester.FinishStream();
tester.RunCompilerTasks();
CHECK_EQ(tester.native_module()->module()->code.offset(),
arraysize(bytes) - 1);
CHECK_EQ(tester.native_module()->module()->code.length(),
arraysize(code) + 1);
CHECK(tester.IsPromiseFulfilled());
}
#undef STREAM_TEST
} // namespace wasm
......
Tests how wasm scripts are reported
Check that each inspector gets a wasm script at module creation time.
Session #1: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
Session #2: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL:
Session #1: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #2: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf
Session #1: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #2: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc
Session #1: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #2: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc
Session #1: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #2: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc
Session #1: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL: , code begin: 34, code end: 48
Session #2: Script #0 parsed. URL: wasm://wasm/f608ae1e. Source map URL: , code begin: 34, code end: 48
Session #1: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf, code begin: 34, code end: 48
Session #2: Script #1 parsed. URL: wasm://wasm/74f86b7e. Source map URL: wasm://dwarf, code begin: 34, code end: 48
Session #1: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc, code begin: 34, code end: 48
Session #2: Script #2 parsed. URL: wasm://wasm/3754e3fe. Source map URL: abc, code begin: 34, code end: 48
Session #1: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc, code begin: 34, code end: 48
Session #2: Script #3 parsed. URL: wasm://wasm/2bd2e40e. Source map URL: abc, code begin: 34, code end: 48
Session #1: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc, code begin: 34, code end: 48
Session #2: Script #4 parsed. URL: wasm://wasm/f568e726. Source map URL: abc, code begin: 34, code end: 48
Session #1: Source for wasm://wasm/f608ae1e:
Raw: 00 61 73 6d 01 00 00 00 01 07 02 60 00 00 60 00 00 03 03 02 00 01 07 08 01 04 6d 61 69 6e 00 01 0a 0e 02 03 00 01 0b 08 00 02 40 41 02 1a 0b 0b 00 1b 04 6e 61 6d 65 01 14 02 00 0b 6e 6f 70 46 75 6e 63 74 69 6f 6e 01 04 6d 61 69 6e
Imports: []
......
......@@ -85,9 +85,13 @@ function trackScripts(debuggerParams) {
Protocol.Debugger.enable(debuggerParams);
Protocol.Debugger.onScriptParsed(handleScriptParsed);
async function loadScript({url, scriptId, sourceMapURL}) {
InspectorTest.log(`Session #${sessionId}: Script #${scripts.length} parsed. URL: ${url}. Source map URL: ${sourceMapURL}`);
let {result: {scriptSource, bytecode}} = await Protocol.Debugger.getScriptSource({scriptId});
async function loadScript(
{url, scriptId, sourceMapURL, startColumn, endColumn}) {
InspectorTest.log(`Session #${sessionId}: Script #${
scripts.length} parsed. URL: ${url}. Source map URL: ${
sourceMapURL}, code begin: ${startColumn}, code end: ${endColumn}`);
let {result: {scriptSource, bytecode}} =
await Protocol.Debugger.getScriptSource({scriptId});
if (bytecode) {
if (scriptSource) {
InspectorTest.log('Unexpected scriptSource with bytecode: ');
......@@ -97,10 +101,17 @@ function trackScripts(debuggerParams) {
bytecode = InspectorTest.decodeBase64(bytecode);
// Check that it can be parsed back to a WebAssembly module.
let module = new WebAssembly.Module(bytecode);
scriptSource = `
scriptSource =
`
Raw: ${Array.from(bytecode, b => ('0' + b.toString(16)).slice(-2)).join(' ')}
Imports: [${WebAssembly.Module.imports(module).map(i => `${i.name}: ${i.kind} from "${i.module}"`).join(', ')}]
Exports: [${WebAssembly.Module.exports(module).map(e => `${e.name}: ${e.kind}`).join(', ')}]
Imports: [${
WebAssembly.Module.imports(module)
.map(i => `${i.name}: ${i.kind} from "${i.module}"`)
.join(', ')}]
Exports: [${
WebAssembly.Module.exports(module)
.map(e => `${e.name}: ${e.kind}`)
.join(', ')}]
`.trim();
}
InspectorTest.log(`Session #${sessionId}: Source for ${url}:`);
......
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