[wasm] Pretend that DWARF section is a fake source map
Unfortunately, codebase contains lots of places that use one of the two formats as an internal representation for Wasm locations: 1) {line: 0, column: byte offset within entire module} 2) {line: function index, column: byte offset within function} These places choose these formats interchangeably and convert from one to another depending on the presence of source map URL in Wasm. This is not very convenient and makes it hard to add support for DWARF which should behave just like Wasm with source maps - that is, report a raw Wasm script instead of fake scripts per each disassembled function, and use representation (1) instead of (2) internally. I tried to refactor these locations and avoid checking for source map URLs in the previous CL - https://crrev.com/c/v8/v8/+/1833688. However, it quickly got out of hand, and updating code in one place just kept revealing yet another that gets broken by the changes, so I made a decision to abandon it and leave to someone who knows the codebase better. Instead, this CL is based on https://crrev.com/c/v8/v8/+/1809375, but, rather than trying to integrate DWARF separately and only for supported agents, it pretends that encountering DWARF section is the same as encountering a `sourceMappingURL` section with fake URL "wasm://dwarf". This ensures that Wasm with DWARF behaves exactly in the same way as Wasm with source maps, just like we want, with minimal changes to the codebase. The only downside is that frontends without DWARF support won't get even a disassembled version of Wasm that contains DWARF info. This is unfortunate, but, as per previous discussions, should be fine given current state of Wasm debugging. Change-Id: Ia7256075e4bfd2f407d001d02b96883d7267436e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1834341 Commit-Queue: Ingvar Stepanyan <rreverser@google.com> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#64157}
This commit is contained in:
parent
f5e7363561
commit
1b5f3be087
@ -169,8 +169,6 @@ domain Debugger
|
||||
# The maximum size in bytes of collected scripts (not referenced by other heap objects)
|
||||
# the debugger can hold. Puts no limit if paramter is omitted.
|
||||
experimental optional number maxScriptsCacheSize
|
||||
# Whether to report Wasm modules as raw binaries instead of disassembled functions.
|
||||
experimental optional boolean supportsWasmDwarf
|
||||
returns
|
||||
# Unique identifier of the debugger.
|
||||
experimental Runtime.UniqueDebuggerId debuggerId
|
||||
|
@ -9444,14 +9444,6 @@ int debug::WasmScript::NumImportedFunctions() const {
|
||||
return static_cast<int>(module->num_imported_functions);
|
||||
}
|
||||
|
||||
bool debug::WasmScript::HasDwarf() const {
|
||||
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->has_dwarf;
|
||||
}
|
||||
|
||||
MemorySpan<const uint8_t> debug::WasmScript::Bytecode() const {
|
||||
i::Handle<i::Script> script = Utils::OpenHandle(this);
|
||||
i::Vector<const uint8_t> wire_bytes =
|
||||
|
@ -159,7 +159,6 @@ class WasmScript : public Script {
|
||||
|
||||
int NumFunctions() const;
|
||||
int NumImportedFunctions() const;
|
||||
bool HasDwarf() const;
|
||||
MemorySpan<const uint8_t> Bytecode() const;
|
||||
|
||||
std::pair<int, int> GetFunctionRange(int function_index) const;
|
||||
|
@ -350,13 +350,11 @@ void V8DebuggerAgentImpl::enableImpl() {
|
||||
}
|
||||
|
||||
Response V8DebuggerAgentImpl::enable(Maybe<double> maxScriptsCacheSize,
|
||||
Maybe<bool> supportsWasmDwarf,
|
||||
String16* outDebuggerId) {
|
||||
m_maxScriptCacheSize = v8::base::saturated_cast<size_t>(
|
||||
maxScriptsCacheSize.fromMaybe(std::numeric_limits<double>::max()));
|
||||
*outDebuggerId =
|
||||
m_debugger->debuggerIdFor(m_session->contextGroupId()).toString();
|
||||
m_supportsWasmDwarf = supportsWasmDwarf.fromMaybe(false);
|
||||
if (enabled()) return Response::OK();
|
||||
|
||||
if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
|
||||
|
@ -43,7 +43,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
|
||||
|
||||
// Part of the protocol.
|
||||
Response enable(Maybe<double> maxScriptsCacheSize,
|
||||
Maybe<bool> supportsWasmDwarf,
|
||||
String16* outDebuggerId) override;
|
||||
Response disable() override;
|
||||
Response setBreakpointsActive(bool active) override;
|
||||
@ -129,7 +128,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
|
||||
positions) override;
|
||||
|
||||
bool enabled() const { return m_enabled; }
|
||||
bool supportsWasmDwarf() const { return m_supportsWasmDwarf; }
|
||||
|
||||
void setBreakpointFor(v8::Local<v8::Function> function,
|
||||
v8::Local<v8::String> condition,
|
||||
@ -233,8 +231,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
|
||||
std::unordered_map<String16, std::vector<std::pair<int, int>>>
|
||||
m_blackboxedPositions;
|
||||
|
||||
bool m_supportsWasmDwarf = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(V8DebuggerAgentImpl);
|
||||
};
|
||||
|
||||
|
@ -522,19 +522,13 @@ void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
|
||||
&wasmTranslation](V8InspectorSessionImpl* session) {
|
||||
auto agent = session->debuggerAgent();
|
||||
if (!agent->enabled()) return;
|
||||
if (script->IsWasm() && script->SourceMappingURL().IsEmpty() &&
|
||||
!(agent->supportsWasmDwarf() &&
|
||||
script.As<v8::debug::WasmScript>()->HasDwarf())) {
|
||||
if (script->IsWasm() && script->SourceMappingURL().IsEmpty()) {
|
||||
wasmTranslation.AddScript(script.As<v8::debug::WasmScript>(), agent);
|
||||
} else {
|
||||
auto debuggerScript = V8DebuggerScript::Create(
|
||||
isolate, script, is_live_edited, agent, client);
|
||||
if (script->IsWasm() && script->SourceMappingURL().IsEmpty()) {
|
||||
DCHECK(agent->supportsWasmDwarf());
|
||||
DCHECK(script.As<v8::debug::WasmScript>()->HasDwarf());
|
||||
debuggerScript->setSourceMappingURL("wasm://dwarf");
|
||||
}
|
||||
agent->didParseSource(std::move(debuggerScript), !has_compile_error);
|
||||
agent->didParseSource(
|
||||
V8DebuggerScript::Create(isolate, script, is_live_edited, agent,
|
||||
client),
|
||||
!has_compile_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
DecodeSourceMappingURLSection();
|
||||
break;
|
||||
case kDebugInfoSectionCode:
|
||||
module_->has_dwarf = true;
|
||||
module_->source_map_url.assign("wasm://dwarf");
|
||||
consume_bytes(static_cast<uint32_t>(end_ - start_), ".debug_info");
|
||||
break;
|
||||
case kCompilationHintsSectionCode:
|
||||
|
@ -193,7 +193,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
|
||||
bool has_maximum_pages = false; // true if there is a maximum memory size
|
||||
bool has_memory = false; // true if the memory was defined or imported
|
||||
bool mem_export = false; // true if the memory is exported
|
||||
bool has_dwarf = false; // true if .debug_info section is present
|
||||
int start_function_index = -1; // start function, >= 0 if any
|
||||
|
||||
std::vector<WasmGlobal> globals;
|
||||
|
@ -1,16 +1,17 @@
|
||||
Tests how wasm scripts are reported
|
||||
Check that each inspector gets two wasm scripts at module creation time.
|
||||
Session #1: Script #0 parsed. URL: wasm://wasm/wasm-77a937ae/wasm-77a937ae-0
|
||||
Session #1: Script #1 parsed. URL: wasm://wasm/wasm-77a937ae/wasm-77a937ae-1
|
||||
Session #2: Script #0 parsed. URL: wasm://wasm/wasm-77a937ae/wasm-77a937ae-0
|
||||
Session #2: Script #1 parsed. URL: wasm://wasm/wasm-77a937ae/wasm-77a937ae-1
|
||||
Session #3: Script #0 parsed. URL: wasm://wasm/wasm-77a937ae
|
||||
Session #1: Source for wasm://wasm/wasm-77a937ae/wasm-77a937ae-0:
|
||||
Session #1: Script #0 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-0. Source map URL:
|
||||
Session #1: Script #1 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-1. Source map URL:
|
||||
Session #2: Script #0 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-0. Source map URL:
|
||||
Session #2: Script #1 parsed. URL: wasm://wasm/wasm-7b04570e/wasm-7b04570e-1. Source map URL:
|
||||
Session #1: Script #2 parsed. URL: wasm://wasm/wasm-77a937ae. Source map URL: wasm://dwarf
|
||||
Session #2: Script #2 parsed. URL: wasm://wasm/wasm-77a937ae. Source map URL: wasm://dwarf
|
||||
Session #1: Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-0:
|
||||
func $nopFunction
|
||||
nop
|
||||
end
|
||||
|
||||
Session #1: Source for wasm://wasm/wasm-77a937ae/wasm-77a937ae-1:
|
||||
Session #1: Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-1:
|
||||
func $main
|
||||
block
|
||||
i32.const 2
|
||||
@ -18,12 +19,12 @@ func $main
|
||||
end
|
||||
end
|
||||
|
||||
Session #2: Source for wasm://wasm/wasm-77a937ae/wasm-77a937ae-0:
|
||||
Session #2: Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-0:
|
||||
func $nopFunction
|
||||
nop
|
||||
end
|
||||
|
||||
Session #2: Source for wasm://wasm/wasm-77a937ae/wasm-77a937ae-1:
|
||||
Session #2: Source for wasm://wasm/wasm-7b04570e/wasm-7b04570e-1:
|
||||
func $main
|
||||
block
|
||||
i32.const 2
|
||||
@ -31,7 +32,11 @@ func $main
|
||||
end
|
||||
end
|
||||
|
||||
Session #3: Source for wasm://wasm/wasm-77a937ae:
|
||||
Session #1: Source for wasm://wasm/wasm-77a937ae:
|
||||
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 0c 0b 2e 64 65 62 75 67 5f 69 6e 66 6f 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: []
|
||||
Exports: [main: function]
|
||||
Session #2: Source for wasm://wasm/wasm-77a937ae:
|
||||
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 0c 0b 2e 64 65 62 75 67 5f 69 6e 66 6f 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: []
|
||||
Exports: [main: function]
|
||||
|
@ -13,8 +13,6 @@ let sessions = [
|
||||
// Extra session to verify that all inspectors get same messages.
|
||||
// See https://bugs.chromium.org/p/v8/issues/detail?id=9725.
|
||||
trackScripts(),
|
||||
// Another session to check how raw Wasm is reported.
|
||||
trackScripts({ supportsWasmDwarf: true }),
|
||||
];
|
||||
|
||||
utils.load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
@ -26,8 +24,9 @@ builder.addFunction('nopFunction', kSig_v_v).addBody([kExprNop]);
|
||||
builder.addFunction('main', kSig_v_v)
|
||||
.addBody([kExprBlock, kWasmStmt, kExprI32Const, 2, kExprDrop, kExprEnd])
|
||||
.exportAs('main');
|
||||
builder.addCustomSection('.debug_info', []);
|
||||
var module_bytes = builder.toArray();
|
||||
builder.addCustomSection('.debug_info', []);
|
||||
var module_bytes_with_dwarf = builder.toArray();
|
||||
|
||||
function testFunction(bytes) {
|
||||
// Compilation triggers registration of wasm scripts.
|
||||
@ -36,6 +35,7 @@ function testFunction(bytes) {
|
||||
|
||||
contextGroup.addScript(testFunction.toString(), 0, 0, 'v8://test/testFunction');
|
||||
contextGroup.addScript('var module_bytes = ' + JSON.stringify(module_bytes));
|
||||
contextGroup.addScript('var module_bytes_with_dwarf = ' + JSON.stringify(module_bytes_with_dwarf));
|
||||
|
||||
InspectorTest.log(
|
||||
'Check that each inspector gets two wasm scripts at module creation time.');
|
||||
@ -43,7 +43,7 @@ InspectorTest.log(
|
||||
sessions[0].Protocol.Runtime
|
||||
.evaluate({
|
||||
'expression': '//# sourceURL=v8://test/runTestRunction\n' +
|
||||
'testFunction(module_bytes)'
|
||||
'testFunction(module_bytes); testFunction(module_bytes_with_dwarf);'
|
||||
})
|
||||
.then(() => (
|
||||
// At this point all scripts were parsed.
|
||||
@ -86,10 +86,10 @@ function trackScripts(debuggerParams) {
|
||||
Protocol.Debugger.enable(debuggerParams);
|
||||
Protocol.Debugger.onScriptParsed(handleScriptParsed);
|
||||
|
||||
async function loadScript({url, scriptId}, raw) {
|
||||
InspectorTest.log(`Session #${sessionId}: Script #${scripts.length} parsed. URL: ${url}`);
|
||||
async function loadScript({url, scriptId, sourceMapURL}) {
|
||||
InspectorTest.log(`Session #${sessionId}: Script #${scripts.length} parsed. URL: ${url}. Source map URL: ${sourceMapURL}`);
|
||||
let scriptSource;
|
||||
if (raw) {
|
||||
if (sourceMapURL === "wasm://dwarf") {
|
||||
let {result: {bytecode}} = await Protocol.Debugger.getWasmBytecode({scriptId});
|
||||
// Binary value is represented as base64 in JSON, decode it.
|
||||
bytecode = decodeBase64(bytecode);
|
||||
@ -108,9 +108,7 @@ Exports: [${WebAssembly.Module.exports(module).map(e => `${e.name}: ${e.kind}`).
|
||||
}
|
||||
|
||||
function handleScriptParsed({params}) {
|
||||
if (params.sourceMapURL === "wasm://dwarf") {
|
||||
scripts.push(loadScript(params, true));
|
||||
} else if (params.url.startsWith("wasm://")) {
|
||||
if (params.url.startsWith("wasm://")) {
|
||||
scripts.push(loadScript(params));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user