https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/207235
The Wasm "name" section names functions but not data, so data symbols such as C++ vtables have no entry in the symbol table. The Itanium C++ runtime resolves a dynamic type by looking up the symbol at an object's vtable pointer and reading its "vtable for X" name. With no such symbol, dynamic type resolution fails and falls back to the static type. The vtable's address and mangled name are available in the DWARF as a DW_TAG_variable with a DW_OP_addr location and a DW_AT_linkage_name. Extend SymbolFileWasm::AddSymbols to synthesize a data symbol for every global variable of that shape, so its address resolves back to the mangled name such as "vtable for X". The size is computed by Symtab to from the gap to the next symbol. Assisted-by: Claude >From 2e82c03d30ea1556c1f9cb9a5c51ff939d7c69b6 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <[email protected]> Date: Thu, 2 Jul 2026 10:08:14 -0700 Subject: [PATCH] [lldb] Synthesize data symbols for WebAssembly from DWARF The Wasm "name" section names functions but not data, so data symbols such as C++ vtables have no entry in the symbol table. The Itanium C++ runtime resolves a dynamic type by looking up the symbol at an object's vtable pointer and reading its "vtable for X" name. With no such symbol, dynamic type resolution fails and falls back to the static type. The vtable's address and mangled name are available in the DWARF as a DW_TAG_variable with a DW_OP_addr location and a DW_AT_linkage_name. Extend SymbolFileWasm::AddSymbols to synthesize a data symbol for every global variable of that shape, so its address resolves back to the mangled name such as "vtable for X". The size is computed by Symtab to from the gap to the next symbol. Assisted-by: Claude --- .../SymbolFile/DWARF/SymbolFileWasm.cpp | 73 ++++++++++++++++--- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp index 0443d18953e1c..b568e104874a4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp @@ -11,6 +11,10 @@ #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Utility/WasmVirtualRegisters.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/Module.h" +#include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Symtab.h" #include "lldb/Utility/LLDBLog.h" @@ -29,9 +33,15 @@ SymbolFileWasm::~SymbolFileWasm() = default; void SymbolFileWasm::AddSymbols(Symtab &symtab) { SymbolFileDWARF::AddSymbols(symtab); - // Copy each function's mangled name from its DWARF DW_AT_linkage_name onto - // the matching symbol. The match is by file address: a subprogram's - // DW_AT_low_pc resolves to the same code-section file address as its symbol. + // The Wasm "name" section names functions but not data, so data symbols such + // as C++ vtables are absent from the symbol table. Recover them from the + // DWARF. A subprogram's mangled name goes onto its existing code symbol. A + // global variable at a static DW_OP_addr, such as a vtable, gets a + // synthesized data symbol so its address resolves back to "vtable for X", + // which is how the Itanium C++ runtime recovers a dynamic type. + ModuleSP module_sp = GetObjectFile()->GetModule(); + SectionList *section_list = module_sp ? module_sp->GetSectionList() : nullptr; + DWARFDebugInfo &debug_info = DebugInfo(); const size_t num_units = debug_info.GetNumUnits(); for (size_t i = 0; i < num_units; ++i) { @@ -40,7 +50,8 @@ void SymbolFileWasm::AddSymbols(Symtab &symtab) { continue; for (const DWARFDebugInfoEntry &entry : unit->dies()) { - if (entry.Tag() != DW_TAG_subprogram) + const dw_tag_t tag = entry.Tag(); + if (tag != DW_TAG_subprogram && tag != DW_TAG_variable) continue; DWARFDIE die(unit, &entry); @@ -49,14 +60,56 @@ void SymbolFileWasm::AddSymbols(Symtab &symtab) { if (!mangled) continue; - const addr_t file_addr = - die.GetAttributeValueAsAddress(DW_AT_low_pc, LLDB_INVALID_ADDRESS); - if (file_addr == LLDB_INVALID_ADDRESS) + if (tag == DW_TAG_subprogram) { + const addr_t file_addr = + die.GetAttributeValueAsAddress(DW_AT_low_pc, LLDB_INVALID_ADDRESS); + if (file_addr == LLDB_INVALID_ADDRESS) + continue; + Symbol *symbol = symtab.FindSymbolAtFileAddress(file_addr); + if (symbol && !symbol->GetMangled().GetMangledName()) + symbol->GetMangled().SetMangledName(ConstString(mangled)); + continue; + } + + // A vtable's location is a plain DW_OP_addr. + if (!section_list) + continue; + DWARFAttributes attributes = die.GetAttributes(); + DWARFFormValue location; + bool has_location = false; + for (size_t attr_idx = 0; attr_idx < attributes.Size(); ++attr_idx) { + if (attributes.AttributeAtIndex(attr_idx) == DW_AT_location) { + has_location = attributes.ExtractFormValueAtIndex(attr_idx, location); + break; + } + } + if (!has_location || !DWARFFormValue::IsBlockForm(location.Form())) + continue; + + const DWARFDataExtractor &data = die.GetData(); + DWARFExpression expr( + DataExtractor(data, location.BlockData() - data.GetDataStart(), + location.Unsigned())); + llvm::Expected<addr_t> file_addr = expr.GetLocation_DW_OP_addr(unit); + if (!file_addr) { + llvm::consumeError(file_addr.takeError()); + continue; + } + + Address addr(*file_addr, section_list); + if (!addr.IsSectionOffset()) continue; - Symbol *symbol = symtab.FindSymbolAtFileAddress(file_addr); - if (symbol && !symbol->GetMangled().GetMangledName()) - symbol->GetMangled().SetMangledName(ConstString(mangled)); + // Leave the size unset for Symtab to compute from the gap to the next + // symbol. Don't look the address up in the symtab here. That would build + // the address index before the remaining vtables are added, mis-sizing + // them. + symtab.AddSymbol(Symbol( + /*symID=*/0, Mangled(ConstString(mangled)), eSymbolTypeData, + /*external=*/true, /*is_debug=*/false, /*is_trampoline=*/false, + /*is_artificial=*/false, AddressRange(addr, 0), + /*size_is_valid=*/false, /*contains_linker_annotations=*/false, + /*flags=*/0)); } } } _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
