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