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