[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: Simon Zünd <szuend@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65913}
This commit is contained in:
Philip Pfaffe 2020-01-22 13:10:10 +01:00 committed by Commit Bot
parent e56a7edbed
commit 827107a7dc
10 changed files with 114 additions and 18 deletions

View File

@ -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),

View File

@ -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(

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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(); }

View File

@ -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

View File

@ -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

View File

@ -1,15 +1,15 @@
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: []

View File

@ -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}:`);