Skip to content

Commit 37cdcdf

Browse files
pfaffeCommit Bot
authored andcommitted
Support .external_debug_info symbol references
Wasm modules generated by emscripten today have two ways to point to debug symbol files, the source mapping url and external debug info custom sections. To support both, this CL extends CDP to appropriately report the symbol type and location. Bug: chromium:1064248 Change-Id: I9076034f6d73901d8a9c5cfd7c2988fb30bb14c1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2116208 Reviewed-by: Clemens Backes <clemensb@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Philip Pfaffe <pfaffe@chromium.org> Cr-Commit-Position: refs/heads/master@{#67571}
1 parent 0c9a007 commit 37cdcdf

15 files changed

Lines changed: 324 additions & 70 deletions

include/js_protocol.pdl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,18 @@ domain Debugger
525525
JavaScript
526526
WebAssembly
527527

528+
# Debug symbols available for a wasm script.
529+
type DebugSymbols extends object
530+
properties
531+
# Type of the debug symbols.
532+
enum type
533+
None
534+
SourceMap
535+
EmbeddedDWARF
536+
ExternalDWARF
537+
# URL of the external symbol source.
538+
optional string externalURL
539+
528540
# Fired when virtual machine fails to parse the script.
529541
event scriptFailedToParse
530542
parameters
@@ -599,6 +611,8 @@ domain Debugger
599611
experimental optional integer codeOffset
600612
# The language of the script.
601613
experimental optional Debugger.ScriptLanguage scriptLanguage
614+
# If the scriptLanguage is WebASsembly, the source of debug symbols for the module.
615+
experimental optional Debugger.DebugSymbols debugSymbols
602616

603617
experimental domain HeapProfiler
604618
depends on Runtime

src/api/api.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9729,6 +9729,37 @@ debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) {
97299729
return static_cast<WasmScript*>(script);
97309730
}
97319731

9732+
debug::WasmScript::DebugSymbolsType debug::WasmScript::GetDebugSymbolType()
9733+
const {
9734+
i::Handle<i::Script> script = Utils::OpenHandle(this);
9735+
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
9736+
switch (script->wasm_native_module()->module()->debug_symbols.type) {
9737+
case i::wasm::WasmDebugSymbols::Type::None:
9738+
return debug::WasmScript::DebugSymbolsType::None;
9739+
case i::wasm::WasmDebugSymbols::Type::EmbeddedDWARF:
9740+
return debug::WasmScript::DebugSymbolsType::EmbeddedDWARF;
9741+
case i::wasm::WasmDebugSymbols::Type::ExternalDWARF:
9742+
return debug::WasmScript::DebugSymbolsType::ExternalDWARF;
9743+
case i::wasm::WasmDebugSymbols::Type::SourceMap:
9744+
return debug::WasmScript::DebugSymbolsType::SourceMap;
9745+
}
9746+
}
9747+
9748+
MemorySpan<const char> debug::WasmScript::ExternalSymbolsURL() const {
9749+
i::Handle<i::Script> script = Utils::OpenHandle(this);
9750+
DCHECK_EQ(i::Script::TYPE_WASM, script->type());
9751+
9752+
const i::wasm::WasmDebugSymbols& symbols =
9753+
script->wasm_native_module()->module()->debug_symbols;
9754+
if (symbols.external_url.is_empty()) return {};
9755+
9756+
internal::wasm::ModuleWireBytes wire_bytes(
9757+
script->wasm_native_module()->wire_bytes());
9758+
i::wasm::WasmName external_url =
9759+
wire_bytes.GetNameOrNull(symbols.external_url);
9760+
return {external_url.data(), external_url.size()};
9761+
}
9762+
97329763
int debug::WasmScript::NumFunctions() const {
97339764
i::DisallowHeapAllocation no_gc;
97349765
i::Handle<i::Script> script = Utils::OpenHandle(this);

src/debug/debug-interface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ class WasmScript : public Script {
173173
public:
174174
static WasmScript* Cast(Script* script);
175175

176+
enum class DebugSymbolsType { None, SourceMap, EmbeddedDWARF, ExternalDWARF };
177+
DebugSymbolsType GetDebugSymbolType() const;
178+
MemorySpan<const char> ExternalSymbolsURL() const;
176179
int NumFunctions() const;
177180
int NumImportedFunctions() const;
178181
MemorySpan<const uint8_t> Bytecode() const;

src/inspector/v8-debugger-agent-impl.cc

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,39 @@ static String16 getScriptLanguage(const V8DebuggerScript& script) {
14711471
}
14721472
}
14731473

1474+
static const char* getDebugSymbolTypeName(
1475+
v8::debug::WasmScript::DebugSymbolsType type) {
1476+
switch (type) {
1477+
case v8::debug::WasmScript::DebugSymbolsType::None:
1478+
return v8_inspector::protocol::Debugger::DebugSymbols::TypeEnum::None;
1479+
case v8::debug::WasmScript::DebugSymbolsType::SourceMap:
1480+
return v8_inspector::protocol::Debugger::DebugSymbols::TypeEnum::
1481+
SourceMap;
1482+
case v8::debug::WasmScript::DebugSymbolsType::EmbeddedDWARF:
1483+
return v8_inspector::protocol::Debugger::DebugSymbols::TypeEnum::
1484+
EmbeddedDWARF;
1485+
case v8::debug::WasmScript::DebugSymbolsType::ExternalDWARF:
1486+
return v8_inspector::protocol::Debugger::DebugSymbols::TypeEnum::
1487+
ExternalDWARF;
1488+
}
1489+
}
1490+
1491+
static std::unique_ptr<protocol::Debugger::DebugSymbols> getDebugSymbols(
1492+
const V8DebuggerScript& script) {
1493+
v8::debug::WasmScript::DebugSymbolsType type;
1494+
if (!script.getDebugSymbolsType().To(&type)) return {};
1495+
1496+
std::unique_ptr<protocol::Debugger::DebugSymbols> debugSymbols =
1497+
v8_inspector::protocol::Debugger::DebugSymbols::create()
1498+
.setType(getDebugSymbolTypeName(type))
1499+
.build();
1500+
String16 externalUrl;
1501+
if (script.getExternalDebugSymbolsURL().To(&externalUrl)) {
1502+
debugSymbols->setExternalURL(externalUrl);
1503+
}
1504+
return debugSymbols;
1505+
}
1506+
14741507
void V8DebuggerAgentImpl::didParseSource(
14751508
std::unique_ptr<V8DebuggerScript> script, bool success) {
14761509
v8::HandleScope handles(m_isolate);
@@ -1506,6 +1539,8 @@ void V8DebuggerAgentImpl::didParseSource(
15061539
script->getLanguage() == V8DebuggerScript::Language::JavaScript
15071540
? Maybe<int>()
15081541
: script->codeOffset();
1542+
std::unique_ptr<protocol::Debugger::DebugSymbols> debugSymbols =
1543+
getDebugSymbols(*script);
15091544

15101545
m_scripts[scriptId] = std::move(script);
15111546
// Release the strong reference to get notified when debugger is the only
@@ -1553,16 +1588,17 @@ void V8DebuggerAgentImpl::didParseSource(
15531588
scriptId, scriptURL, 0, 0, 0, 0, contextId, scriptRef->hash(),
15541589
std::move(executionContextAuxDataParam), isLiveEditParam,
15551590
std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam, 0,
1556-
std::move(stackTrace), std::move(codeOffset),
1557-
std::move(scriptLanguage));
1591+
std::move(stackTrace), std::move(codeOffset), std::move(scriptLanguage),
1592+
std::move(debugSymbols));
15581593
} else {
15591594
m_frontend.scriptParsed(
15601595
scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
15611596
scriptRef->endLine(), scriptRef->endColumn(), contextId,
15621597
scriptRef->hash(), std::move(executionContextAuxDataParam),
15631598
isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
15641599
isModuleParam, scriptRef->length(), std::move(stackTrace),
1565-
std::move(codeOffset), std::move(scriptLanguage));
1600+
std::move(codeOffset), std::move(scriptLanguage),
1601+
std::move(debugSymbols));
15661602
}
15671603

15681604
std::vector<protocol::DictionaryValue*> potentialBreakpoints;

src/inspector/v8-debugger-script.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,21 @@ class ActualScript : public V8DebuggerScript {
122122
return v8::Just(v8::debug::WasmScript::Cast(*script)->Bytecode());
123123
}
124124
Language getLanguage() const override { return m_language; }
125+
v8::Maybe<v8::debug::WasmScript::DebugSymbolsType> getDebugSymbolsType()
126+
const override {
127+
auto script = this->script();
128+
if (!script->IsWasm())
129+
return v8::Nothing<v8::debug::WasmScript::DebugSymbolsType>();
130+
return v8::Just(v8::debug::WasmScript::Cast(*script)->GetDebugSymbolType());
131+
}
132+
v8::Maybe<String16> getExternalDebugSymbolsURL() const override {
133+
auto script = this->script();
134+
if (!script->IsWasm()) return v8::Nothing<String16>();
135+
v8::MemorySpan<const char> external_url =
136+
v8::debug::WasmScript::Cast(*script)->ExternalSymbolsURL();
137+
if (external_url.size() == 0) return v8::Nothing<String16>();
138+
return v8::Just(String16(external_url.data(), external_url.size()));
139+
}
125140
int startLine() const override { return m_startLine; }
126141
int startColumn() const override { return m_startColumn; }
127142
int endLine() const override { return m_endLine; }

src/inspector/v8-debugger-script.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class V8DebuggerScript {
6161
virtual String16 source(size_t pos, size_t len = UINT_MAX) const = 0;
6262
virtual v8::Maybe<v8::MemorySpan<const uint8_t>> wasmBytecode() const = 0;
6363
virtual Language getLanguage() const = 0;
64+
virtual v8::Maybe<String16> getExternalDebugSymbolsURL() const = 0;
65+
virtual v8::Maybe<v8::debug::WasmScript::DebugSymbolsType>
66+
getDebugSymbolsType() const = 0;
6467
virtual const String16& hash() const = 0;
6568
virtual int startLine() const = 0;
6669
virtual int startColumn() const = 0;

src/wasm/module-compiler.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,10 +1684,13 @@ void AsyncCompileJob::FinishCompile(bool is_after_cache_hit) {
16841684
DCHECK(!isolate_->context().is_null());
16851685
// Finish the wasm script now and make it public to the debugger.
16861686
Handle<Script> script(module_object_->script(), isolate_);
1687+
const WasmModule* module = module_object_->module();
16871688
if (script->type() == Script::TYPE_WASM &&
1688-
module_object_->module()->source_map_url.size() != 0) {
1689+
module->debug_symbols.type == WasmDebugSymbols::Type::SourceMap &&
1690+
!module->debug_symbols.external_url.is_empty()) {
1691+
ModuleWireBytes wire_bytes(module_object_->native_module()->wire_bytes());
16891692
MaybeHandle<String> src_map_str = isolate_->factory()->NewStringFromUtf8(
1690-
CStrVector(module_object_->module()->source_map_url.c_str()),
1693+
wire_bytes.GetNameOrNull(module->debug_symbols.external_url),
16911694
AllocationType::kOld);
16921695
script->set_source_mapping_url(*src_map_str.ToHandleChecked());
16931696
}
@@ -1702,11 +1705,10 @@ void AsyncCompileJob::FinishCompile(bool is_after_cache_hit) {
17021705
Handle<FixedArray> export_wrappers;
17031706
if (is_after_cache_hit) {
17041707
// TODO(thibaudm): Look into sharing wrappers.
1705-
CompileJsToWasmWrappers(isolate_, module_object_->module(),
1706-
&export_wrappers);
1708+
CompileJsToWasmWrappers(isolate_, module, &export_wrappers);
17071709
} else {
1708-
compilation_state->FinalizeJSToWasmWrappers(
1709-
isolate_, module_object_->module(), &export_wrappers);
1710+
compilation_state->FinalizeJSToWasmWrappers(isolate_, module,
1711+
&export_wrappers);
17101712
}
17111713
module_object_->set_export_wrappers(*export_wrappers);
17121714
}

src/wasm/module-decoder.cc

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ constexpr char kNameString[] = "name";
3333
constexpr char kSourceMappingURLString[] = "sourceMappingURL";
3434
constexpr char kCompilationHintsString[] = "compilationHints";
3535
constexpr char kDebugInfoString[] = ".debug_info";
36+
constexpr char kExternalDebugInfoString[] = ".external_debug_info";
3637

3738
template <size_t N>
3839
constexpr size_t num_chars(const char (&)[N]) {
@@ -93,6 +94,8 @@ const char* SectionName(SectionCode code) {
9394
return kSourceMappingURLString;
9495
case kDebugInfoSectionCode:
9596
return kDebugInfoString;
97+
case kExternalDebugInfoSectionCode:
98+
return kExternalDebugInfoString;
9699
case kCompilationHintsSectionCode:
97100
return kCompilationHintsString;
98101
default:
@@ -182,6 +185,11 @@ SectionCode IdentifyUnknownSectionInternal(Decoder* decoder) {
182185
strncmp(reinterpret_cast<const char*>(section_name_start),
183186
kDebugInfoString, num_chars(kDebugInfoString)) == 0) {
184187
return kDebugInfoSectionCode;
188+
} else if (string.length() == num_chars(kExternalDebugInfoString) &&
189+
strncmp(reinterpret_cast<const char*>(section_name_start),
190+
kExternalDebugInfoString,
191+
num_chars(kExternalDebugInfoString)) == 0) {
192+
return kExternalDebugInfoSectionCode;
185193
}
186194
return kUnknownSectionCode;
187195
}
@@ -452,6 +460,9 @@ class ModuleDecoderImpl : public Decoder {
452460
// .debug_info is a custom section containing core DWARF information
453461
// if produced by compiler. Its presence likely means that Wasm was
454462
// built in a debug mode.
463+
case kExternalDebugInfoSectionCode:
464+
// .external_debug_info is a custom section containing a reference to an
465+
// external symbol file.
455466
case kCompilationHintsSectionCode:
456467
// TODO(frgossen): report out of place compilation hints section as a
457468
// warning.
@@ -508,11 +519,14 @@ class ModuleDecoderImpl : public Decoder {
508519
break;
509520
case kDebugInfoSectionCode:
510521
// If there is an explicit source map, prefer it over DWARF info.
511-
if (!has_seen_unordered_section(kSourceMappingURLSectionCode)) {
512-
module_->source_map_url.assign("wasm://dwarf");
522+
if (module_->debug_symbols.type == WasmDebugSymbols::Type::None) {
523+
module_->debug_symbols = {WasmDebugSymbols::Type::EmbeddedDWARF, {}};
513524
}
514525
consume_bytes(static_cast<uint32_t>(end_ - start_), ".debug_info");
515526
break;
527+
case kExternalDebugInfoSectionCode:
528+
DecodeExternalDebugInfoSection();
529+
break;
516530
case kCompilationHintsSectionCode:
517531
if (enabled_features_.has_compilation_hints()) {
518532
DecodeCompilationHintsSection();
@@ -1063,12 +1077,22 @@ class ModuleDecoderImpl : public Decoder {
10631077
Decoder inner(start_, pc_, end_, buffer_offset_);
10641078
WireBytesRef url = wasm::consume_string(&inner, true, "module name");
10651079
if (inner.ok() &&
1066-
!has_seen_unordered_section(kSourceMappingURLSectionCode)) {
1067-
const byte* url_start =
1068-
inner.start() + inner.GetBufferRelativeOffset(url.offset());
1069-
module_->source_map_url.assign(reinterpret_cast<const char*>(url_start),
1070-
url.length());
1071-
set_seen_unordered_section(kSourceMappingURLSectionCode);
1080+
module_->debug_symbols.type != WasmDebugSymbols::Type::SourceMap) {
1081+
module_->debug_symbols = {WasmDebugSymbols::Type::SourceMap, url};
1082+
}
1083+
set_seen_unordered_section(kSourceMappingURLSectionCode);
1084+
consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
1085+
}
1086+
1087+
void DecodeExternalDebugInfoSection() {
1088+
Decoder inner(start_, pc_, end_, buffer_offset_);
1089+
WireBytesRef url =
1090+
wasm::consume_string(&inner, true, "external symbol file");
1091+
// If there is an explicit source map, prefer it over DWARF info.
1092+
if (inner.ok() &&
1093+
module_->debug_symbols.type != WasmDebugSymbols::Type::SourceMap) {
1094+
module_->debug_symbols = {WasmDebugSymbols::Type::ExternalDWARF, url};
1095+
set_seen_unordered_section(kExternalDebugInfoSectionCode);
10721096
}
10731097
consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
10741098
}
@@ -2157,8 +2181,8 @@ FunctionResult DecodeWasmFunctionForTesting(
21572181
const byte* function_end, Counters* counters) {
21582182
size_t size = function_end - function_start;
21592183
CHECK_LE(function_start, function_end);
2160-
auto size_histogram = SELECT_WASM_COUNTER(counters, module->origin, wasm,
2161-
function_size_bytes);
2184+
auto size_histogram =
2185+
SELECT_WASM_COUNTER(counters, module->origin, wasm, function_size_bytes);
21622186
// TODO(bradnelson): Improve histogram handling of ptrdiff_t.
21632187
size_histogram->AddSample(static_cast<int>(size));
21642188
if (size > kV8MaxWasmFunctionSize) {

src/wasm/wasm-code-manager.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,14 +221,19 @@ void WasmCode::LogCode(Isolate* isolate) const {
221221
VectorOf(native_module()->module()->export_table));
222222
WasmName name = wire_bytes.GetNameOrNull(name_ref);
223223

224-
const std::string& source_map_url = native_module()->module()->source_map_url;
224+
const WasmDebugSymbols& debug_symbols =
225+
native_module()->module()->debug_symbols;
225226
auto load_wasm_source_map = isolate->wasm_load_source_map_callback();
226227
auto source_map = native_module()->GetWasmSourceMap();
227-
if (!source_map && !source_map_url.empty() && load_wasm_source_map) {
228+
if (!source_map && debug_symbols.type == WasmDebugSymbols::Type::SourceMap &&
229+
!debug_symbols.external_url.is_empty() && load_wasm_source_map) {
230+
WasmName external_url =
231+
wire_bytes.GetNameOrNull(debug_symbols.external_url);
232+
std::string external_url_string(external_url.data(), external_url.size());
228233
HandleScope scope(isolate);
229234
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
230235
Local<v8::String> source_map_str =
231-
load_wasm_source_map(v8_isolate, source_map_url.c_str());
236+
load_wasm_source_map(v8_isolate, external_url_string.c_str());
232237
native_module()->SetWasmSourceMap(
233238
std::make_unique<WasmModuleSourceMap>(v8_isolate, source_map_str));
234239
}

src/wasm/wasm-constants.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,11 @@ enum SectionCode : int8_t {
8787
// The following sections are custom sections, and are identified using a
8888
// string rather than an integer. Their enumeration values are not guaranteed
8989
// to be consistent.
90-
kNameSectionCode, // Name section (encoded as a string)
91-
kSourceMappingURLSectionCode, // Source Map URL section
92-
kDebugInfoSectionCode, // DWARF section .debug_info
93-
kCompilationHintsSectionCode, // Compilation hints section
90+
kNameSectionCode, // Name section (encoded as a string)
91+
kSourceMappingURLSectionCode, // Source Map URL section
92+
kDebugInfoSectionCode, // DWARF section .debug_info
93+
kExternalDebugInfoSectionCode, // Section encoding the external symbol path
94+
kCompilationHintsSectionCode, // Compilation hints section
9495

9596
// Helper values
9697
kFirstSectionInModule = kTypeSectionCode,

0 commit comments

Comments
 (0)