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/Module.h"
18#include "lldb/Symbol/Symbol.h"
19#include "lldb/Symbol/Symtab.h"
21
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::plugin::dwarf;
25using namespace llvm::dwarf;
26
28 SectionList *dwo_section_list)
29 : SymbolFileDWARF(objfile_sp, dwo_section_list) {}
30
32
35
36 // The Wasm "name" section names functions but not data, so data symbols such
37 // as C++ vtables are absent from the symbol table. Recover them from the
38 // DWARF. A subprogram's mangled name goes onto its existing code symbol. A
39 // global variable at a static DW_OP_addr, such as a vtable, gets a
40 // synthesized data symbol so its address resolves back to "vtable for X",
41 // which is how the Itanium C++ runtime recovers a dynamic type.
42 ModuleSP module_sp = GetObjectFile()->GetModule();
43 SectionList *section_list = module_sp ? module_sp->GetSectionList() : nullptr;
44
45 DWARFDebugInfo &debug_info = DebugInfo();
46 const size_t num_units = debug_info.GetNumUnits();
47 for (size_t i = 0; i < num_units; ++i) {
48 DWARFUnit *unit = debug_info.GetUnitAtIndex(i);
49 if (!unit)
50 continue;
51
52 for (const DWARFDebugInfoEntry &entry : unit->dies()) {
53 const dw_tag_t tag = entry.Tag();
54 if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
55 continue;
56
57 DWARFDIE die(unit, &entry);
58 const char *mangled =
59 die.GetMangledName(/*substitute_name_allowed=*/false);
60 if (!mangled)
61 continue;
62
63 if (tag == DW_TAG_subprogram) {
64 const addr_t file_addr =
66 if (file_addr == LLDB_INVALID_ADDRESS)
67 continue;
68 Symbol *symbol = symtab.FindSymbolAtFileAddress(file_addr);
69 if (symbol && !symbol->GetMangled().GetMangledName())
70 symbol->GetMangled().SetMangledName(ConstString(mangled));
71 continue;
72 }
73
74 // A vtable's location is a plain DW_OP_addr.
75 if (!section_list)
76 continue;
77 DWARFAttributes attributes = die.GetAttributes();
78 DWARFFormValue location;
79 bool has_location = false;
80 for (size_t attr_idx = 0; attr_idx < attributes.Size(); ++attr_idx) {
81 if (attributes.AttributeAtIndex(attr_idx) == DW_AT_location) {
82 has_location = attributes.ExtractFormValueAtIndex(attr_idx, location);
83 break;
84 }
85 }
86 if (!has_location || !DWARFFormValue::IsBlockForm(location.Form()))
87 continue;
88
89 const DWARFDataExtractor &data = die.GetData();
90 DWARFExpression expr(
91 DataExtractor(data, location.BlockData() - data.GetDataStart(),
92 location.Unsigned()));
93 llvm::Expected<addr_t> file_addr = expr.GetLocation_DW_OP_addr(unit);
94 if (!file_addr) {
95 llvm::consumeError(file_addr.takeError());
96 continue;
97 }
98
99 Address addr(*file_addr, section_list);
100 if (!addr.IsSectionOffset())
101 continue;
102
103 // Leave the size unset for Symtab to compute from the gap to the next
104 // symbol. Don't look the address up in the symtab here. That would build
105 // the address index before the remaining vtables are added, mis-sizing
106 // them.
107 symtab.AddSymbol(Symbol(
108 /*symID=*/0, Mangled(ConstString(mangled)), eSymbolTypeData,
109 /*external=*/true, /*is_debug=*/false, /*is_trampoline=*/false,
110 /*is_artificial=*/false, AddressRange(addr, 0),
111 /*size_is_valid=*/false, /*contains_linker_annotations=*/false,
112 /*flags=*/0));
113 }
114 }
115}
116
119 const lldb::offset_t data_offset,
120 const uint8_t op) const {
121 if (op != llvm::dwarf::DW_OP_WASM_location)
122 return LLDB_INVALID_OFFSET;
123
124 lldb::offset_t offset = data_offset;
125 const uint8_t wasm_op = data.GetU8(&offset);
126 switch (wasm_op) {
127 case 0: // LOCAL
128 case 1: // GLOBAL_FIXED
129 case 2: // OPERAND_STACK
130 data.GetULEB128(&offset);
131 break;
132 case 3: // GLOBAL_RELOC
133 data.GetU32(&offset);
134 break;
135 default:
136 return LLDB_INVALID_OFFSET;
137 }
138
139 return offset - data_offset;
140}
141
143 const llvm::DataExtractor &opcodes,
144 lldb::offset_t &offset,
145 RegisterContext *reg_ctx,
146 lldb::RegisterKind reg_kind,
147 std::vector<Value> &stack) const {
148 if (op != llvm::dwarf::DW_OP_WASM_location)
149 return false;
150
151 uint32_t index = 0;
152 uint8_t tag = eWasmTagNotAWasmLocation;
153
154 /// |DWARF Location Index | WebAssembly Construct |
155 /// |---------------------|-----------------------|
156 /// |0 | Local |
157 /// |1 or 3 | Global |
158 /// |2 | Operand Stack |
159 const uint8_t wasm_op = opcodes.getU8(&offset);
160 switch (wasm_op) {
161 case 0: // LOCAL
162 index = opcodes.getULEB128(&offset);
163 tag = eWasmTagLocal;
164 break;
165 case 1: // GLOBAL_FIXED
166 index = opcodes.getULEB128(&offset);
167 tag = eWasmTagGlobal;
168 break;
169 case 2: // OPERAND_STACK
170 index = opcodes.getULEB128(&offset);
172 break;
173 case 3: // GLOBAL_RELOC
174 index = opcodes.getU32(&offset);
175 tag = eWasmTagGlobal;
176 break;
177 default:
178 return false;
179 }
180
181 const uint32_t reg_num = GetWasmRegister(tag, index);
182
183 Value tmp;
185 reg_ctx, reg_kind, reg_num, tmp);
186 if (error) {
187 LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), std::move(error), "{0}");
188 return false;
189 }
190
191 stack.push_back(tmp);
192 return true;
193}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:406
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
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
Symbol * FindSymbolAtFileAddress(lldb::addr_t file_addr)
Definition Symtab.cpp:1015
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:61
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:339
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.