1cfca06d7SDimitry Andric //===-- ObjectFileWasm.cpp ------------------------------------------------===//
2cfca06d7SDimitry Andric //
3cfca06d7SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cfca06d7SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5cfca06d7SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cfca06d7SDimitry Andric //
7cfca06d7SDimitry Andric //===----------------------------------------------------------------------===//
8cfca06d7SDimitry Andric
9cfca06d7SDimitry Andric #include "ObjectFileWasm.h"
10cfca06d7SDimitry Andric #include "lldb/Core/Module.h"
11cfca06d7SDimitry Andric #include "lldb/Core/ModuleSpec.h"
12cfca06d7SDimitry Andric #include "lldb/Core/PluginManager.h"
13cfca06d7SDimitry Andric #include "lldb/Core/Section.h"
14cfca06d7SDimitry Andric #include "lldb/Target/Process.h"
15cfca06d7SDimitry Andric #include "lldb/Target/SectionLoadList.h"
16cfca06d7SDimitry Andric #include "lldb/Target/Target.h"
17cfca06d7SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
18145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
19cfca06d7SDimitry Andric #include "lldb/Utility/Log.h"
20cfca06d7SDimitry Andric #include "llvm/ADT/ArrayRef.h"
21cfca06d7SDimitry Andric #include "llvm/ADT/SmallVector.h"
22cfca06d7SDimitry Andric #include "llvm/ADT/StringRef.h"
23cfca06d7SDimitry Andric #include "llvm/BinaryFormat/Magic.h"
24cfca06d7SDimitry Andric #include "llvm/BinaryFormat/Wasm.h"
25cfca06d7SDimitry Andric #include "llvm/Support/Endian.h"
26cfca06d7SDimitry Andric #include "llvm/Support/Format.h"
27e3b55780SDimitry Andric #include <optional>
28cfca06d7SDimitry Andric
29cfca06d7SDimitry Andric using namespace lldb;
30cfca06d7SDimitry Andric using namespace lldb_private;
31cfca06d7SDimitry Andric using namespace lldb_private::wasm;
32cfca06d7SDimitry Andric
33cfca06d7SDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileWasm)
34cfca06d7SDimitry Andric
35cfca06d7SDimitry Andric static const uint32_t kWasmHeaderSize =
36cfca06d7SDimitry Andric sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
37cfca06d7SDimitry Andric
38cfca06d7SDimitry Andric /// Checks whether the data buffer starts with a valid Wasm module header.
ValidateModuleHeader(const DataBufferSP & data_sp)39cfca06d7SDimitry Andric static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
40cfca06d7SDimitry Andric if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
41cfca06d7SDimitry Andric return false;
42cfca06d7SDimitry Andric
43cfca06d7SDimitry Andric if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
44cfca06d7SDimitry Andric llvm::file_magic::wasm_object)
45cfca06d7SDimitry Andric return false;
46cfca06d7SDimitry Andric
47145449b1SDimitry Andric const uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
48cfca06d7SDimitry Andric
49cfca06d7SDimitry Andric uint32_t version = llvm::support::endian::read32le(Ptr);
50cfca06d7SDimitry Andric return version == llvm::wasm::WasmVersion;
51cfca06d7SDimitry Andric }
52cfca06d7SDimitry Andric
53e3b55780SDimitry Andric static std::optional<ConstString>
GetWasmString(llvm::DataExtractor & data,llvm::DataExtractor::Cursor & c)54cfca06d7SDimitry Andric GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
55cfca06d7SDimitry Andric // A Wasm string is encoded as a vector of UTF-8 codes.
56cfca06d7SDimitry Andric // Vectors are encoded with their u32 length followed by the element
57cfca06d7SDimitry Andric // sequence.
58cfca06d7SDimitry Andric uint64_t len = data.getULEB128(c);
59cfca06d7SDimitry Andric if (!c) {
60cfca06d7SDimitry Andric consumeError(c.takeError());
61e3b55780SDimitry Andric return std::nullopt;
62cfca06d7SDimitry Andric }
63cfca06d7SDimitry Andric
64cfca06d7SDimitry Andric if (len >= (uint64_t(1) << 32)) {
65e3b55780SDimitry Andric return std::nullopt;
66cfca06d7SDimitry Andric }
67cfca06d7SDimitry Andric
68cfca06d7SDimitry Andric llvm::SmallVector<uint8_t, 32> str_storage;
69cfca06d7SDimitry Andric data.getU8(c, str_storage, len);
70cfca06d7SDimitry Andric if (!c) {
71cfca06d7SDimitry Andric consumeError(c.takeError());
72e3b55780SDimitry Andric return std::nullopt;
73cfca06d7SDimitry Andric }
74cfca06d7SDimitry Andric
75e3b55780SDimitry Andric llvm::StringRef str = toStringRef(llvm::ArrayRef(str_storage));
76cfca06d7SDimitry Andric return ConstString(str);
77cfca06d7SDimitry Andric }
78cfca06d7SDimitry Andric
79cfca06d7SDimitry Andric char ObjectFileWasm::ID;
80cfca06d7SDimitry Andric
Initialize()81cfca06d7SDimitry Andric void ObjectFileWasm::Initialize() {
82cfca06d7SDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
83cfca06d7SDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
84cfca06d7SDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
85cfca06d7SDimitry Andric }
86cfca06d7SDimitry Andric
Terminate()87cfca06d7SDimitry Andric void ObjectFileWasm::Terminate() {
88cfca06d7SDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
89cfca06d7SDimitry Andric }
90cfca06d7SDimitry Andric
91cfca06d7SDimitry Andric ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)92145449b1SDimitry Andric ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
93cfca06d7SDimitry Andric offset_t data_offset, const FileSpec *file,
94cfca06d7SDimitry Andric offset_t file_offset, offset_t length) {
95145449b1SDimitry Andric Log *log = GetLog(LLDBLog::Object);
96cfca06d7SDimitry Andric
97cfca06d7SDimitry Andric if (!data_sp) {
98cfca06d7SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
99cfca06d7SDimitry Andric if (!data_sp) {
100cfca06d7SDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
101cfca06d7SDimitry Andric file->GetPath().c_str());
102cfca06d7SDimitry Andric return nullptr;
103cfca06d7SDimitry Andric }
104cfca06d7SDimitry Andric data_offset = 0;
105cfca06d7SDimitry Andric }
106cfca06d7SDimitry Andric
107cfca06d7SDimitry Andric assert(data_sp);
108cfca06d7SDimitry Andric if (!ValidateModuleHeader(data_sp)) {
109cfca06d7SDimitry Andric LLDB_LOGF(log,
110cfca06d7SDimitry Andric "Failed to create ObjectFileWasm instance: invalid Wasm header");
111cfca06d7SDimitry Andric return nullptr;
112cfca06d7SDimitry Andric }
113cfca06d7SDimitry Andric
114cfca06d7SDimitry Andric // Update the data to contain the entire file if it doesn't contain it
115cfca06d7SDimitry Andric // already.
116cfca06d7SDimitry Andric if (data_sp->GetByteSize() < length) {
117cfca06d7SDimitry Andric data_sp = MapFileData(*file, length, file_offset);
118cfca06d7SDimitry Andric if (!data_sp) {
119cfca06d7SDimitry Andric LLDB_LOGF(log,
120cfca06d7SDimitry Andric "Failed to create ObjectFileWasm instance: cannot read file %s",
121cfca06d7SDimitry Andric file->GetPath().c_str());
122cfca06d7SDimitry Andric return nullptr;
123cfca06d7SDimitry Andric }
124cfca06d7SDimitry Andric data_offset = 0;
125cfca06d7SDimitry Andric }
126cfca06d7SDimitry Andric
127cfca06d7SDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
128cfca06d7SDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length));
129cfca06d7SDimitry Andric ArchSpec spec = objfile_up->GetArchitecture();
130cfca06d7SDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec)) {
131cfca06d7SDimitry Andric LLDB_LOGF(log,
132cfca06d7SDimitry Andric "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
133cfca06d7SDimitry Andric static_cast<void *>(objfile_up.get()),
134cfca06d7SDimitry Andric static_cast<void *>(objfile_up->GetModule().get()),
135cfca06d7SDimitry Andric objfile_up->GetModule()->GetSpecificationDescription().c_str(),
136cfca06d7SDimitry Andric file ? file->GetPath().c_str() : "<NULL>");
137cfca06d7SDimitry Andric return objfile_up.release();
138cfca06d7SDimitry Andric }
139cfca06d7SDimitry Andric
140cfca06d7SDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
141cfca06d7SDimitry Andric return nullptr;
142cfca06d7SDimitry Andric }
143cfca06d7SDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)144cfca06d7SDimitry Andric ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
145145449b1SDimitry Andric WritableDataBufferSP data_sp,
146cfca06d7SDimitry Andric const ProcessSP &process_sp,
147cfca06d7SDimitry Andric addr_t header_addr) {
148cfca06d7SDimitry Andric if (!ValidateModuleHeader(data_sp))
149cfca06d7SDimitry Andric return nullptr;
150cfca06d7SDimitry Andric
151cfca06d7SDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up(
152cfca06d7SDimitry Andric new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
153cfca06d7SDimitry Andric ArchSpec spec = objfile_up->GetArchitecture();
154cfca06d7SDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec))
155cfca06d7SDimitry Andric return objfile_up.release();
156cfca06d7SDimitry Andric return nullptr;
157cfca06d7SDimitry Andric }
158cfca06d7SDimitry Andric
DecodeNextSection(lldb::offset_t * offset_ptr)159cfca06d7SDimitry Andric bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
160cfca06d7SDimitry Andric // Buffer sufficient to read a section header and find the pointer to the next
161cfca06d7SDimitry Andric // section.
162cfca06d7SDimitry Andric const uint32_t kBufferSize = 1024;
163cfca06d7SDimitry Andric DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
164cfca06d7SDimitry Andric
165cfca06d7SDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM();
166cfca06d7SDimitry Andric llvm::DataExtractor::Cursor c(0);
167cfca06d7SDimitry Andric
168cfca06d7SDimitry Andric // Each section consists of:
169cfca06d7SDimitry Andric // - a one-byte section id,
170cfca06d7SDimitry Andric // - the u32 size of the contents, in bytes,
171cfca06d7SDimitry Andric // - the actual contents.
172cfca06d7SDimitry Andric uint8_t section_id = data.getU8(c);
173cfca06d7SDimitry Andric uint64_t payload_len = data.getULEB128(c);
174cfca06d7SDimitry Andric if (!c)
175cfca06d7SDimitry Andric return !llvm::errorToBool(c.takeError());
176cfca06d7SDimitry Andric
177cfca06d7SDimitry Andric if (payload_len >= (uint64_t(1) << 32))
178cfca06d7SDimitry Andric return false;
179cfca06d7SDimitry Andric
180cfca06d7SDimitry Andric if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
181cfca06d7SDimitry Andric // Custom sections have the id 0. Their contents consist of a name
182cfca06d7SDimitry Andric // identifying the custom section, followed by an uninterpreted sequence
183cfca06d7SDimitry Andric // of bytes.
184cfca06d7SDimitry Andric lldb::offset_t prev_offset = c.tell();
185e3b55780SDimitry Andric std::optional<ConstString> sect_name = GetWasmString(data, c);
186cfca06d7SDimitry Andric if (!sect_name)
187cfca06d7SDimitry Andric return false;
188cfca06d7SDimitry Andric
189cfca06d7SDimitry Andric if (payload_len < c.tell() - prev_offset)
190cfca06d7SDimitry Andric return false;
191cfca06d7SDimitry Andric
192cfca06d7SDimitry Andric uint32_t section_length = payload_len - (c.tell() - prev_offset);
193cfca06d7SDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
194cfca06d7SDimitry Andric section_id, *sect_name});
195cfca06d7SDimitry Andric *offset_ptr += (c.tell() + section_length);
196145449b1SDimitry Andric } else if (section_id <= llvm::wasm::WASM_SEC_LAST_KNOWN) {
197cfca06d7SDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
198cfca06d7SDimitry Andric static_cast<uint32_t>(payload_len),
199cfca06d7SDimitry Andric section_id, ConstString()});
200cfca06d7SDimitry Andric *offset_ptr += (c.tell() + payload_len);
201cfca06d7SDimitry Andric } else {
202cfca06d7SDimitry Andric // Invalid section id.
203cfca06d7SDimitry Andric return false;
204cfca06d7SDimitry Andric }
205cfca06d7SDimitry Andric return true;
206cfca06d7SDimitry Andric }
207cfca06d7SDimitry Andric
DecodeSections()208cfca06d7SDimitry Andric bool ObjectFileWasm::DecodeSections() {
209cfca06d7SDimitry Andric lldb::offset_t offset = kWasmHeaderSize;
210cfca06d7SDimitry Andric if (IsInMemory()) {
211cfca06d7SDimitry Andric offset += m_memory_addr;
212cfca06d7SDimitry Andric }
213cfca06d7SDimitry Andric
214cfca06d7SDimitry Andric while (DecodeNextSection(&offset))
215cfca06d7SDimitry Andric ;
216cfca06d7SDimitry Andric return true;
217cfca06d7SDimitry Andric }
218cfca06d7SDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)219cfca06d7SDimitry Andric size_t ObjectFileWasm::GetModuleSpecifications(
220cfca06d7SDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
221cfca06d7SDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
222cfca06d7SDimitry Andric if (!ValidateModuleHeader(data_sp)) {
223cfca06d7SDimitry Andric return 0;
224cfca06d7SDimitry Andric }
225cfca06d7SDimitry Andric
226cfca06d7SDimitry Andric ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
227cfca06d7SDimitry Andric specs.Append(spec);
228cfca06d7SDimitry Andric return 1;
229cfca06d7SDimitry Andric }
230cfca06d7SDimitry Andric
ObjectFileWasm(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length)231145449b1SDimitry Andric ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP data_sp,
232cfca06d7SDimitry Andric offset_t data_offset, const FileSpec *file,
233cfca06d7SDimitry Andric offset_t offset, offset_t length)
234cfca06d7SDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
235cfca06d7SDimitry Andric m_arch("wasm32-unknown-unknown-wasm") {
236cfca06d7SDimitry Andric m_data.SetAddressByteSize(4);
237cfca06d7SDimitry Andric }
238cfca06d7SDimitry Andric
ObjectFileWasm(const lldb::ModuleSP & module_sp,lldb::WritableDataBufferSP header_data_sp,const lldb::ProcessSP & process_sp,lldb::addr_t header_addr)239cfca06d7SDimitry Andric ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
240145449b1SDimitry Andric lldb::WritableDataBufferSP header_data_sp,
241cfca06d7SDimitry Andric const lldb::ProcessSP &process_sp,
242cfca06d7SDimitry Andric lldb::addr_t header_addr)
243cfca06d7SDimitry Andric : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
244cfca06d7SDimitry Andric m_arch("wasm32-unknown-unknown-wasm") {}
245cfca06d7SDimitry Andric
ParseHeader()246cfca06d7SDimitry Andric bool ObjectFileWasm::ParseHeader() {
247cfca06d7SDimitry Andric // We already parsed the header during initialization.
248cfca06d7SDimitry Andric return true;
249cfca06d7SDimitry Andric }
250cfca06d7SDimitry Andric
ParseSymtab(Symtab & symtab)251f65dcba8SDimitry Andric void ObjectFileWasm::ParseSymtab(Symtab &symtab) {}
252cfca06d7SDimitry Andric
GetSectionTypeFromName(llvm::StringRef Name)253b60736ecSDimitry Andric static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
254b60736ecSDimitry Andric if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
255b60736ecSDimitry Andric return llvm::StringSwitch<SectionType>(Name)
256b60736ecSDimitry Andric .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
257b60736ecSDimitry Andric .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
258b60736ecSDimitry Andric .Case("addr", eSectionTypeDWARFDebugAddr)
259b60736ecSDimitry Andric .Case("aranges", eSectionTypeDWARFDebugAranges)
260b60736ecSDimitry Andric .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
261b60736ecSDimitry Andric .Case("frame", eSectionTypeDWARFDebugFrame)
262b60736ecSDimitry Andric .Case("info", eSectionTypeDWARFDebugInfo)
263b60736ecSDimitry Andric .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
264b60736ecSDimitry Andric .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
265b60736ecSDimitry Andric .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
266b60736ecSDimitry Andric .Case("loc", eSectionTypeDWARFDebugLoc)
267b60736ecSDimitry Andric .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
268b60736ecSDimitry Andric .Case("loclists", eSectionTypeDWARFDebugLocLists)
269b60736ecSDimitry Andric .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
270b60736ecSDimitry Andric .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
271b60736ecSDimitry Andric .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
272b60736ecSDimitry Andric .Case("names", eSectionTypeDWARFDebugNames)
273b60736ecSDimitry Andric .Case("pubnames", eSectionTypeDWARFDebugPubNames)
274b60736ecSDimitry Andric .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
275b60736ecSDimitry Andric .Case("ranges", eSectionTypeDWARFDebugRanges)
276b60736ecSDimitry Andric .Case("rnglists", eSectionTypeDWARFDebugRngLists)
277b60736ecSDimitry Andric .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
278b60736ecSDimitry Andric .Case("str", eSectionTypeDWARFDebugStr)
279b60736ecSDimitry Andric .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
280b60736ecSDimitry Andric .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
281b60736ecSDimitry Andric .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
282b60736ecSDimitry Andric .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
283b60736ecSDimitry Andric .Case("types", eSectionTypeDWARFDebugTypes)
284b60736ecSDimitry Andric .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
285b60736ecSDimitry Andric .Default(eSectionTypeOther);
286b60736ecSDimitry Andric }
287b60736ecSDimitry Andric return eSectionTypeOther;
288b60736ecSDimitry Andric }
289b60736ecSDimitry Andric
CreateSections(SectionList & unified_section_list)290cfca06d7SDimitry Andric void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
291cfca06d7SDimitry Andric if (m_sections_up)
292cfca06d7SDimitry Andric return;
293cfca06d7SDimitry Andric
294cfca06d7SDimitry Andric m_sections_up = std::make_unique<SectionList>();
295cfca06d7SDimitry Andric
296cfca06d7SDimitry Andric if (m_sect_infos.empty()) {
297cfca06d7SDimitry Andric DecodeSections();
298cfca06d7SDimitry Andric }
299cfca06d7SDimitry Andric
300cfca06d7SDimitry Andric for (const section_info §_info : m_sect_infos) {
301cfca06d7SDimitry Andric SectionType section_type = eSectionTypeOther;
302cfca06d7SDimitry Andric ConstString section_name;
303cfca06d7SDimitry Andric offset_t file_offset = sect_info.offset & 0xffffffff;
304cfca06d7SDimitry Andric addr_t vm_addr = file_offset;
305cfca06d7SDimitry Andric size_t vm_size = sect_info.size;
306cfca06d7SDimitry Andric
307cfca06d7SDimitry Andric if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
308cfca06d7SDimitry Andric section_type = eSectionTypeCode;
309cfca06d7SDimitry Andric section_name = ConstString("code");
310cfca06d7SDimitry Andric
311cfca06d7SDimitry Andric // A code address in DWARF for WebAssembly is the offset of an
312cfca06d7SDimitry Andric // instruction relative within the Code section of the WebAssembly file.
313cfca06d7SDimitry Andric // For this reason Section::GetFileAddress() must return zero for the
314cfca06d7SDimitry Andric // Code section.
315cfca06d7SDimitry Andric vm_addr = 0;
316cfca06d7SDimitry Andric } else {
317b60736ecSDimitry Andric section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
318cfca06d7SDimitry Andric if (section_type == eSectionTypeOther)
319cfca06d7SDimitry Andric continue;
320cfca06d7SDimitry Andric section_name = sect_info.name;
321cfca06d7SDimitry Andric if (!IsInMemory()) {
322cfca06d7SDimitry Andric vm_size = 0;
323cfca06d7SDimitry Andric vm_addr = 0;
324cfca06d7SDimitry Andric }
325cfca06d7SDimitry Andric }
326cfca06d7SDimitry Andric
327cfca06d7SDimitry Andric SectionSP section_sp(
328cfca06d7SDimitry Andric new Section(GetModule(), // Module to which this section belongs.
329cfca06d7SDimitry Andric this, // ObjectFile to which this section belongs and
330cfca06d7SDimitry Andric // should read section data from.
331cfca06d7SDimitry Andric section_type, // Section ID.
332cfca06d7SDimitry Andric section_name, // Section name.
333cfca06d7SDimitry Andric section_type, // Section type.
334cfca06d7SDimitry Andric vm_addr, // VM address.
335cfca06d7SDimitry Andric vm_size, // VM size in bytes of this section.
336cfca06d7SDimitry Andric file_offset, // Offset of this section in the file.
337cfca06d7SDimitry Andric sect_info.size, // Size of the section as found in the file.
338cfca06d7SDimitry Andric 0, // Alignment of the section
339cfca06d7SDimitry Andric 0, // Flags for this section.
340cfca06d7SDimitry Andric 1)); // Number of host bytes per target byte
341cfca06d7SDimitry Andric m_sections_up->AddSection(section_sp);
342cfca06d7SDimitry Andric unified_section_list.AddSection(section_sp);
343cfca06d7SDimitry Andric }
344cfca06d7SDimitry Andric }
345cfca06d7SDimitry Andric
SetLoadAddress(Target & target,lldb::addr_t load_address,bool value_is_offset)346cfca06d7SDimitry Andric bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
347cfca06d7SDimitry Andric bool value_is_offset) {
348cfca06d7SDimitry Andric /// In WebAssembly, linear memory is disjointed from code space. The VM can
349cfca06d7SDimitry Andric /// load multiple instances of a module, which logically share the same code.
350cfca06d7SDimitry Andric /// We represent a wasm32 code address with 64-bits, like:
351cfca06d7SDimitry Andric /// 63 32 31 0
352cfca06d7SDimitry Andric /// +---------------+---------------+
353cfca06d7SDimitry Andric /// + module_id | offset |
354cfca06d7SDimitry Andric /// +---------------+---------------+
355cfca06d7SDimitry Andric /// where the lower 32 bits represent a module offset (relative to the module
356cfca06d7SDimitry Andric /// start not to the beginning of the code section) and the higher 32 bits
357cfca06d7SDimitry Andric /// uniquely identify the module in the WebAssembly VM.
358cfca06d7SDimitry Andric /// In other words, we assume that each WebAssembly module is loaded by the
359cfca06d7SDimitry Andric /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
360cfca06d7SDimitry Andric /// 0x0000000400000000 for module_id == 4.
361cfca06d7SDimitry Andric /// These 64-bit addresses will be used to request code ranges for a specific
362cfca06d7SDimitry Andric /// module from the WebAssembly engine.
363cfca06d7SDimitry Andric
364cfca06d7SDimitry Andric assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
365cfca06d7SDimitry Andric m_memory_addr == load_address);
366cfca06d7SDimitry Andric
367cfca06d7SDimitry Andric ModuleSP module_sp = GetModule();
368cfca06d7SDimitry Andric if (!module_sp)
369cfca06d7SDimitry Andric return false;
370cfca06d7SDimitry Andric
371cfca06d7SDimitry Andric DecodeSections();
372cfca06d7SDimitry Andric
373cfca06d7SDimitry Andric size_t num_loaded_sections = 0;
374cfca06d7SDimitry Andric SectionList *section_list = GetSectionList();
375cfca06d7SDimitry Andric if (!section_list)
376cfca06d7SDimitry Andric return false;
377cfca06d7SDimitry Andric
378cfca06d7SDimitry Andric const size_t num_sections = section_list->GetSize();
379cfca06d7SDimitry Andric for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
380cfca06d7SDimitry Andric SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
381cfca06d7SDimitry Andric if (target.SetSectionLoadAddress(
382cfca06d7SDimitry Andric section_sp, load_address | section_sp->GetFileOffset())) {
383cfca06d7SDimitry Andric ++num_loaded_sections;
384cfca06d7SDimitry Andric }
385cfca06d7SDimitry Andric }
386cfca06d7SDimitry Andric
387cfca06d7SDimitry Andric return num_loaded_sections > 0;
388cfca06d7SDimitry Andric }
389cfca06d7SDimitry Andric
ReadImageData(offset_t offset,uint32_t size)390cfca06d7SDimitry Andric DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
391cfca06d7SDimitry Andric DataExtractor data;
392cfca06d7SDimitry Andric if (m_file) {
393cfca06d7SDimitry Andric if (offset < GetByteSize()) {
394cfca06d7SDimitry Andric size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
395cfca06d7SDimitry Andric auto buffer_sp = MapFileData(m_file, size, offset);
396cfca06d7SDimitry Andric return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
397cfca06d7SDimitry Andric }
398cfca06d7SDimitry Andric } else {
399cfca06d7SDimitry Andric ProcessSP process_sp(m_process_wp.lock());
400cfca06d7SDimitry Andric if (process_sp) {
401cfca06d7SDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0);
402cfca06d7SDimitry Andric Status readmem_error;
403cfca06d7SDimitry Andric size_t bytes_read = process_sp->ReadMemory(
404cfca06d7SDimitry Andric offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
405cfca06d7SDimitry Andric if (bytes_read > 0) {
406cfca06d7SDimitry Andric DataBufferSP buffer_sp(data_up.release());
407cfca06d7SDimitry Andric data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
408cfca06d7SDimitry Andric }
409cfca06d7SDimitry Andric }
410cfca06d7SDimitry Andric }
411cfca06d7SDimitry Andric
412cfca06d7SDimitry Andric data.SetByteOrder(GetByteOrder());
413cfca06d7SDimitry Andric return data;
414cfca06d7SDimitry Andric }
415cfca06d7SDimitry Andric
GetExternalDebugInfoFileSpec()416e3b55780SDimitry Andric std::optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
417cfca06d7SDimitry Andric static ConstString g_sect_name_external_debug_info("external_debug_info");
418cfca06d7SDimitry Andric
419cfca06d7SDimitry Andric for (const section_info §_info : m_sect_infos) {
420cfca06d7SDimitry Andric if (g_sect_name_external_debug_info == sect_info.name) {
421cfca06d7SDimitry Andric const uint32_t kBufferSize = 1024;
422cfca06d7SDimitry Andric DataExtractor section_header_data =
423cfca06d7SDimitry Andric ReadImageData(sect_info.offset, kBufferSize);
424cfca06d7SDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM();
425cfca06d7SDimitry Andric llvm::DataExtractor::Cursor c(0);
426e3b55780SDimitry Andric std::optional<ConstString> symbols_url = GetWasmString(data, c);
427cfca06d7SDimitry Andric if (symbols_url)
428cfca06d7SDimitry Andric return FileSpec(symbols_url->GetStringRef());
429cfca06d7SDimitry Andric }
430cfca06d7SDimitry Andric }
431e3b55780SDimitry Andric return std::nullopt;
432cfca06d7SDimitry Andric }
433cfca06d7SDimitry Andric
Dump(Stream * s)434cfca06d7SDimitry Andric void ObjectFileWasm::Dump(Stream *s) {
435cfca06d7SDimitry Andric ModuleSP module_sp(GetModule());
436cfca06d7SDimitry Andric if (!module_sp)
437cfca06d7SDimitry Andric return;
438cfca06d7SDimitry Andric
439cfca06d7SDimitry Andric std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
440cfca06d7SDimitry Andric
441cfca06d7SDimitry Andric llvm::raw_ostream &ostream = s->AsRawOstream();
442cfca06d7SDimitry Andric ostream << static_cast<void *>(this) << ": ";
443cfca06d7SDimitry Andric s->Indent();
444cfca06d7SDimitry Andric ostream << "ObjectFileWasm, file = '";
445cfca06d7SDimitry Andric m_file.Dump(ostream);
446cfca06d7SDimitry Andric ostream << "', arch = ";
447cfca06d7SDimitry Andric ostream << GetArchitecture().GetArchitectureName() << "\n";
448cfca06d7SDimitry Andric
449cfca06d7SDimitry Andric SectionList *sections = GetSectionList();
450cfca06d7SDimitry Andric if (sections) {
451cfca06d7SDimitry Andric sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
452cfca06d7SDimitry Andric UINT32_MAX);
453cfca06d7SDimitry Andric }
454cfca06d7SDimitry Andric ostream << "\n";
455cfca06d7SDimitry Andric DumpSectionHeaders(ostream);
456cfca06d7SDimitry Andric ostream << "\n";
457cfca06d7SDimitry Andric }
458cfca06d7SDimitry Andric
DumpSectionHeader(llvm::raw_ostream & ostream,const section_info_t & sh)459cfca06d7SDimitry Andric void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
460cfca06d7SDimitry Andric const section_info_t &sh) {
461cfca06d7SDimitry Andric ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
462cfca06d7SDimitry Andric << llvm::format_hex(sh.offset, 10) << " "
463cfca06d7SDimitry Andric << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
464cfca06d7SDimitry Andric << "\n";
465cfca06d7SDimitry Andric }
466cfca06d7SDimitry Andric
DumpSectionHeaders(llvm::raw_ostream & ostream)467cfca06d7SDimitry Andric void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
468cfca06d7SDimitry Andric ostream << "Section Headers\n";
469cfca06d7SDimitry Andric ostream << "IDX name addr size id\n";
470cfca06d7SDimitry Andric ostream << "==== ---------------- ---------- ---------- ------\n";
471cfca06d7SDimitry Andric
472cfca06d7SDimitry Andric uint32_t idx = 0;
473cfca06d7SDimitry Andric for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
474cfca06d7SDimitry Andric ++pos, ++idx) {
475cfca06d7SDimitry Andric ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
476cfca06d7SDimitry Andric ObjectFileWasm::DumpSectionHeader(ostream, *pos);
477cfca06d7SDimitry Andric }
478cfca06d7SDimitry Andric }
479