xref: /src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 &sect_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 &sect_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