LLDB mainline
SymbolFileWasm.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SymbolFileWasm.h"
14#include "lldb/Core/Address.h"
16#include "lldb/Core/Mangled.h"
17#include "lldb/Core/Module.h"
19#include "lldb/Symbol/Symbol.h"
20#include "lldb/Symbol/Symtab.h"
23#include "llvm/ADT/DenseMap.h"
24#include <optional>
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::plugin::dwarf;
29using namespace llvm::dwarf;
30
32 SectionList *dwo_section_list)
33 : SymbolFileDWARF(objfile_sp, dwo_section_list) {}
34
36
37/// Index the code symbols that carry no mangled name by their demangled name.
38/// The value is a symbol table index rather than a Symbol pointer because
39/// pointers do not survive symbols being appended to the table.
40static llvm::DenseMap<ConstString, uint32_t>
42 llvm::DenseMap<ConstString, uint32_t> index;
43 for (size_t i = 0, n = symtab.GetNumSymbols(); i < n; ++i) {
44 Symbol *symbol = symtab.SymbolAtIndex(i);
45 if (!symbol || symbol->GetType() != eSymbolTypeCode)
46 continue;
47 Mangled &mangled = symbol->GetMangled();
48 if (mangled.GetMangledName())
49 continue;
50 if (ConstString demangled = mangled.GetDemangledName())
51 index.try_emplace(demangled, static_cast<uint32_t>(i));
52 }
53 return index;
54}
55
58
59 // The Wasm "name" section names functions but not data, so data symbols are
60 // absent from the symbol table. Recover them from the DWARF. A subprogram's
61 // mangled name goes onto its existing code symbol. A global variable at a
62 // static DW_OP_addr gets a synthesized data symbol so that its address
63 // resolves back to the variable's name. This is how the Itanium C++ runtime
64 // recovers a dynamic type from a vtable ("vtable for X"), and it also lets a
65 // plain C global resolve back to its name.
66 ModuleSP module_sp = GetObjectFile()->GetModule();
67 SectionList *section_list = module_sp ? module_sp->GetSectionList() : nullptr;
68
69 // Built on demand to recover a mangled name from a declaration-only DIE.
70 std::optional<llvm::DenseMap<ConstString, uint32_t>> demangled_index;
71
72 DWARFDebugInfo &debug_info = DebugInfo();
73 const size_t num_units = debug_info.GetNumUnits();
74 for (size_t i = 0; i < num_units; ++i) {
75 DWARFUnit *unit = debug_info.GetUnitAtIndex(i);
76 if (!unit)
77 continue;
78
79 for (const DWARFDebugInfoEntry &entry : unit->dies()) {
80 const dw_tag_t tag = entry.Tag();
81 if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
82 continue;
83
84 DWARFDIE die(unit, &entry);
85
86 if (tag == DW_TAG_subprogram) {
87 // Only a mangled (linkage) name is worth putting onto a code symbol.
88 // The source name is already carried by the Wasm name section.
89 const char *mangled =
90 die.GetMangledName(/*substitute_name_allowed=*/false);
91 if (!mangled)
92 continue;
93
94 // A defining DIE names its symbol by address. A function defined in a
95 // translation unit compiled without debug info has only a declaration
96 // DIE with no address, so match its symbol by the demangled name that
97 // the Wasm name section carries.
98 const addr_t file_addr =
100 Symbol *symbol = nullptr;
101 if (file_addr != LLDB_INVALID_ADDRESS) {
102 symbol = symtab.FindSymbolAtFileAddress(file_addr);
103 } else if (ConstString demangled =
104 Mangled(ConstString(mangled)).GetDemangledName()) {
105 if (!demangled_index)
106 demangled_index = BuildDemangledCodeSymbolIndex(symtab);
107 auto it = demangled_index->find(demangled);
108 if (it != demangled_index->end())
109 symbol = symtab.SymbolAtIndex(it->second);
110 }
111 if (symbol && !symbol->GetMangled().GetMangledName())
112 symbol->GetMangled().SetMangledName(ConstString(mangled));
113 continue;
114 }
115
116 // A global variable has no symbol at all. Use its linkage name, or the
117 // source name when there is none (plain C globals have only a
118 // DW_AT_name).
119 const char *name = die.GetMangledName(/*substitute_name_allowed=*/true);
120 if (!name)
121 continue;
122
123 // A global's location is a plain DW_OP_addr.
124 if (!section_list)
125 continue;
126 DWARFAttributes attributes = die.GetAttributes();
127 DWARFFormValue location;
128 bool has_location = false;
129 for (size_t attr_idx = 0; attr_idx < attributes.Size(); ++attr_idx) {
130 if (attributes.AttributeAtIndex(attr_idx) == DW_AT_location) {
131 has_location = attributes.ExtractFormValueAtIndex(attr_idx, location);
132 break;
133 }
134 }
135 if (!has_location || !DWARFFormValue::IsBlockForm(location.Form()))
136 continue;
137
138 const DWARFDataExtractor &data = die.GetData();
139 DWARFExpression expr(
140 DataExtractor(data, location.BlockData() - data.GetDataStart(),
141 location.Unsigned()));
142 llvm::Expected<addr_t> file_addr = expr.GetLocation_DW_OP_addr(unit);
143 if (!file_addr) {
144 llvm::consumeError(file_addr.takeError());
145 continue;
146 }
147
148 Address addr(*file_addr, section_list);
149 if (!addr.IsSectionOffset())
150 continue;
151
152 // Leave the size unset for Symtab to compute from the gap to the next
153 // symbol. Don't look the address up in the symtab here. That would build
154 // the address index before the remaining vtables are added, mis-sizing
155 // them.
156 symtab.AddSymbol(Symbol(
157 /*symID=*/0, Mangled(ConstString(name)), eSymbolTypeData,
158 /*external=*/true, /*is_debug=*/false, /*is_trampoline=*/false,
159 /*is_artificial=*/false, AddressRange(addr, 0),
160 /*size_is_valid=*/false, /*contains_linker_annotations=*/false,
161 /*flags=*/0));
162 }
163 }
164}
165
168 const lldb::offset_t data_offset,
169 const uint8_t op) const {
170 if (op != llvm::dwarf::DW_OP_WASM_location)
171 return LLDB_INVALID_OFFSET;
172
173 lldb::offset_t offset = data_offset;
174 const uint8_t wasm_op = data.GetU8(&offset);
175 switch (wasm_op) {
176 case 0: // LOCAL
177 case 1: // GLOBAL_FIXED
178 case 2: // OPERAND_STACK
179 data.GetULEB128(&offset);
180 break;
181 case 3: // GLOBAL_RELOC
182 data.GetU32(&offset);
183 break;
184 default:
185 return LLDB_INVALID_OFFSET;
186 }
187
188 return offset - data_offset;
189}
190
192 const llvm::DataExtractor &opcodes,
193 lldb::offset_t &offset,
194 RegisterContext *reg_ctx,
195 lldb::RegisterKind reg_kind,
196 std::vector<Value> &stack) const {
197 if (op != llvm::dwarf::DW_OP_WASM_location)
198 return false;
199
200 uint32_t index = 0;
201 uint8_t tag = eWasmTagNotAWasmLocation;
202
203 /// |DWARF Location Index | WebAssembly Construct |
204 /// |---------------------|-----------------------|
205 /// |0 | Local |
206 /// |1 or 3 | Global |
207 /// |2 | Operand Stack |
208 const uint8_t wasm_op = opcodes.getU8(&offset);
209 switch (wasm_op) {
210 case 0: // LOCAL
211 index = opcodes.getULEB128(&offset);
212 tag = eWasmTagLocal;
213 break;
214 case 1: // GLOBAL_FIXED
215 index = opcodes.getULEB128(&offset);
216 tag = eWasmTagGlobal;
217 break;
218 case 2: // OPERAND_STACK
219 index = opcodes.getULEB128(&offset);
221 break;
222 case 3: // GLOBAL_RELOC
223 index = opcodes.getU32(&offset);
224 tag = eWasmTagGlobal;
225 break;
226 default:
227 return false;
228 }
229
230 const uint32_t reg_num = GetWasmRegister(tag, index);
231
232 Value tmp;
234 reg_ctx, reg_kind, reg_num, tmp);
235 if (error) {
236 LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), std::move(error), "{0}");
237 return false;
238 }
239
240 stack.push_back(tmp);
241 return true;
242}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
static llvm::DenseMap< ConstString, uint32_t > BuildDemangledCodeSymbolIndex(Symtab &symtab)
Index the code symbols that carry no mangled name by their demangled name.
A section + offset based address range class.
A section + offset based address class.
Definition Address.h:62
bool IsSectionOffset() const
Check if an address is section offset.
Definition Address.h:342
A uniqued constant string class.
Definition ConstString.h:40
"lldb/Expression/DWARFExpression.h" Encapsulates a DWARF location expression and interprets it.
llvm::Expected< lldb::addr_t > GetLocation_DW_OP_addr(const Delegate *dwarf_cu) const
Return the address specified by the first DW_OP_{addr, addrx, GNU_addr_index} in the operation stream...
static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, uint32_t reg_num, Value &value)
An data extractor class.
uint64_t GetULEB128(lldb::offset_t *offset_ptr) const
Extract a unsigned LEB128 value from *offset_ptr.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
const uint8_t * GetDataStart() const
Get the data start pointer.
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
A class that handles mangled names.
Definition Mangled.h:34
ConstString GetMangledName() const
Mangled name get accessor.
Definition Mangled.h:174
ConstString GetDemangledName() const
Demangled name get accessor.
Definition Mangled.cpp:284
void SetMangledName(ConstString name)
Definition Mangled.h:165
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
ObjectFile * GetObjectFile() override
Definition SymbolFile.h:582
virtual void AddSymbols(Symtab &symtab)
Definition SymbolFile.h:380
Mangled & GetMangled()
Definition Symbol.h:147
lldb::SymbolType GetType() const
Definition Symbol.h:169
Symbol * SymbolAtIndex(size_t idx)
Definition Symtab.cpp:225
Symbol * FindSymbolAtFileAddress(lldb::addr_t file_addr)
Definition Symtab.cpp:1015
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:61
size_t GetNumSymbols() const
Definition Symtab.cpp:74
dw_attr_t AttributeAtIndex(uint32_t i) const
bool ExtractFormValueAtIndex(uint32_t i, DWARFFormValue &form_value) const
DWARFAttributes GetAttributes(Recurse recurse=Recurse::yes) const
const DWARFDataExtractor & GetData() const
uint64_t GetAttributeValueAsAddress(const dw_attr_t attr, uint64_t fail_value) const
const char * GetMangledName(bool substitute_name_allowed=true) const
Definition DWARFDIE.cpp:212
DWARFDebugInfoEntry objects assume that they are living in one big vector and do pointer arithmetic o...
static bool IsBlockForm(const dw_form_t form)
SymbolFileDWARF(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list)
SymbolFileWasm(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list)
void AddSymbols(Symtab &symtab) override
The Wasm "name" section stores only demangled names, so symbols parsed from it have no mangled name t...
lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op) const override
bool ParseVendorDWARFOpcode(uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, std::vector< Value > &stack) const override
llvm::dwarf::Tag dw_tag_t
Definition dwarf.h:19
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_OFFSET
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:338
uint32_t GetWasmRegister(uint8_t tag, uint32_t index)
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::ObjectFile > ObjectFileSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Module > ModuleSP
RegisterKind
Register numbering types.