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