xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
15ffd83dbSDimitry Andric //===-- ObjectFileWasm.cpp ------------------------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric 
95ffd83dbSDimitry Andric #include "ObjectFileWasm.h"
105ffd83dbSDimitry Andric #include "lldb/Core/Module.h"
115ffd83dbSDimitry Andric #include "lldb/Core/ModuleSpec.h"
125ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h"
135ffd83dbSDimitry Andric #include "lldb/Core/Section.h"
145ffd83dbSDimitry Andric #include "lldb/Target/Process.h"
155ffd83dbSDimitry Andric #include "lldb/Target/SectionLoadList.h"
165ffd83dbSDimitry Andric #include "lldb/Target/Target.h"
175ffd83dbSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
185ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
195ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h"
205ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
215ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h"
225ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
235ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Wasm.h"
245ffd83dbSDimitry Andric #include "llvm/Support/Endian.h"
255ffd83dbSDimitry Andric #include "llvm/Support/Format.h"
265ffd83dbSDimitry Andric 
275ffd83dbSDimitry Andric using namespace lldb;
285ffd83dbSDimitry Andric using namespace lldb_private;
295ffd83dbSDimitry Andric using namespace lldb_private::wasm;
305ffd83dbSDimitry Andric 
315ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileWasm)
325ffd83dbSDimitry Andric 
335ffd83dbSDimitry Andric static const uint32_t kWasmHeaderSize =
345ffd83dbSDimitry Andric     sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
355ffd83dbSDimitry Andric 
365ffd83dbSDimitry Andric /// Checks whether the data buffer starts with a valid Wasm module header.
375ffd83dbSDimitry Andric static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
385ffd83dbSDimitry Andric   if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
395ffd83dbSDimitry Andric     return false;
405ffd83dbSDimitry Andric 
415ffd83dbSDimitry Andric   if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
425ffd83dbSDimitry Andric       llvm::file_magic::wasm_object)
435ffd83dbSDimitry Andric     return false;
445ffd83dbSDimitry Andric 
455ffd83dbSDimitry Andric   uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
465ffd83dbSDimitry Andric 
475ffd83dbSDimitry Andric   uint32_t version = llvm::support::endian::read32le(Ptr);
485ffd83dbSDimitry Andric   return version == llvm::wasm::WasmVersion;
495ffd83dbSDimitry Andric }
505ffd83dbSDimitry Andric 
515ffd83dbSDimitry Andric static llvm::Optional<ConstString>
525ffd83dbSDimitry Andric GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
535ffd83dbSDimitry Andric   // A Wasm string is encoded as a vector of UTF-8 codes.
545ffd83dbSDimitry Andric   // Vectors are encoded with their u32 length followed by the element
555ffd83dbSDimitry Andric   // sequence.
565ffd83dbSDimitry Andric   uint64_t len = data.getULEB128(c);
575ffd83dbSDimitry Andric   if (!c) {
585ffd83dbSDimitry Andric     consumeError(c.takeError());
595ffd83dbSDimitry Andric     return llvm::None;
605ffd83dbSDimitry Andric   }
615ffd83dbSDimitry Andric 
625ffd83dbSDimitry Andric   if (len >= (uint64_t(1) << 32)) {
635ffd83dbSDimitry Andric     return llvm::None;
645ffd83dbSDimitry Andric   }
655ffd83dbSDimitry Andric 
665ffd83dbSDimitry Andric   llvm::SmallVector<uint8_t, 32> str_storage;
675ffd83dbSDimitry Andric   data.getU8(c, str_storage, len);
685ffd83dbSDimitry Andric   if (!c) {
695ffd83dbSDimitry Andric     consumeError(c.takeError());
705ffd83dbSDimitry Andric     return llvm::None;
715ffd83dbSDimitry Andric   }
725ffd83dbSDimitry Andric 
735ffd83dbSDimitry Andric   llvm::StringRef str = toStringRef(makeArrayRef(str_storage));
745ffd83dbSDimitry Andric   return ConstString(str);
755ffd83dbSDimitry Andric }
765ffd83dbSDimitry Andric 
775ffd83dbSDimitry Andric char ObjectFileWasm::ID;
785ffd83dbSDimitry Andric 
795ffd83dbSDimitry Andric void ObjectFileWasm::Initialize() {
805ffd83dbSDimitry Andric   PluginManager::RegisterPlugin(GetPluginNameStatic(),
815ffd83dbSDimitry Andric                                 GetPluginDescriptionStatic(), CreateInstance,
825ffd83dbSDimitry Andric                                 CreateMemoryInstance, GetModuleSpecifications);
835ffd83dbSDimitry Andric }
845ffd83dbSDimitry Andric 
855ffd83dbSDimitry Andric void ObjectFileWasm::Terminate() {
865ffd83dbSDimitry Andric   PluginManager::UnregisterPlugin(CreateInstance);
875ffd83dbSDimitry Andric }
885ffd83dbSDimitry Andric 
895ffd83dbSDimitry Andric ConstString ObjectFileWasm::GetPluginNameStatic() {
905ffd83dbSDimitry Andric   static ConstString g_name("wasm");
915ffd83dbSDimitry Andric   return g_name;
925ffd83dbSDimitry Andric }
935ffd83dbSDimitry Andric 
945ffd83dbSDimitry Andric ObjectFile *
955ffd83dbSDimitry Andric ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
965ffd83dbSDimitry Andric                                offset_t data_offset, const FileSpec *file,
975ffd83dbSDimitry Andric                                offset_t file_offset, offset_t length) {
985ffd83dbSDimitry Andric   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
995ffd83dbSDimitry Andric 
1005ffd83dbSDimitry Andric   if (!data_sp) {
1015ffd83dbSDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
1025ffd83dbSDimitry Andric     if (!data_sp) {
1035ffd83dbSDimitry Andric       LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
1045ffd83dbSDimitry Andric                 file->GetPath().c_str());
1055ffd83dbSDimitry Andric       return nullptr;
1065ffd83dbSDimitry Andric     }
1075ffd83dbSDimitry Andric     data_offset = 0;
1085ffd83dbSDimitry Andric   }
1095ffd83dbSDimitry Andric 
1105ffd83dbSDimitry Andric   assert(data_sp);
1115ffd83dbSDimitry Andric   if (!ValidateModuleHeader(data_sp)) {
1125ffd83dbSDimitry Andric     LLDB_LOGF(log,
1135ffd83dbSDimitry Andric               "Failed to create ObjectFileWasm instance: invalid Wasm header");
1145ffd83dbSDimitry Andric     return nullptr;
1155ffd83dbSDimitry Andric   }
1165ffd83dbSDimitry Andric 
1175ffd83dbSDimitry Andric   // Update the data to contain the entire file if it doesn't contain it
1185ffd83dbSDimitry Andric   // already.
1195ffd83dbSDimitry Andric   if (data_sp->GetByteSize() < length) {
1205ffd83dbSDimitry Andric     data_sp = MapFileData(*file, length, file_offset);
1215ffd83dbSDimitry Andric     if (!data_sp) {
1225ffd83dbSDimitry Andric       LLDB_LOGF(log,
1235ffd83dbSDimitry Andric                 "Failed to create ObjectFileWasm instance: cannot read file %s",
1245ffd83dbSDimitry Andric                 file->GetPath().c_str());
1255ffd83dbSDimitry Andric       return nullptr;
1265ffd83dbSDimitry Andric     }
1275ffd83dbSDimitry Andric     data_offset = 0;
1285ffd83dbSDimitry Andric   }
1295ffd83dbSDimitry Andric 
1305ffd83dbSDimitry Andric   std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
1315ffd83dbSDimitry Andric       module_sp, data_sp, data_offset, file, file_offset, length));
1325ffd83dbSDimitry Andric   ArchSpec spec = objfile_up->GetArchitecture();
1335ffd83dbSDimitry Andric   if (spec && objfile_up->SetModulesArchitecture(spec)) {
1345ffd83dbSDimitry Andric     LLDB_LOGF(log,
1355ffd83dbSDimitry Andric               "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
1365ffd83dbSDimitry Andric               static_cast<void *>(objfile_up.get()),
1375ffd83dbSDimitry Andric               static_cast<void *>(objfile_up->GetModule().get()),
1385ffd83dbSDimitry Andric               objfile_up->GetModule()->GetSpecificationDescription().c_str(),
1395ffd83dbSDimitry Andric               file ? file->GetPath().c_str() : "<NULL>");
1405ffd83dbSDimitry Andric     return objfile_up.release();
1415ffd83dbSDimitry Andric   }
1425ffd83dbSDimitry Andric 
1435ffd83dbSDimitry Andric   LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
1445ffd83dbSDimitry Andric   return nullptr;
1455ffd83dbSDimitry Andric }
1465ffd83dbSDimitry Andric 
1475ffd83dbSDimitry Andric ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
1485ffd83dbSDimitry Andric                                                  DataBufferSP &data_sp,
1495ffd83dbSDimitry Andric                                                  const ProcessSP &process_sp,
1505ffd83dbSDimitry Andric                                                  addr_t header_addr) {
1515ffd83dbSDimitry Andric   if (!ValidateModuleHeader(data_sp))
1525ffd83dbSDimitry Andric     return nullptr;
1535ffd83dbSDimitry Andric 
1545ffd83dbSDimitry Andric   std::unique_ptr<ObjectFileWasm> objfile_up(
1555ffd83dbSDimitry Andric       new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
1565ffd83dbSDimitry Andric   ArchSpec spec = objfile_up->GetArchitecture();
1575ffd83dbSDimitry Andric   if (spec && objfile_up->SetModulesArchitecture(spec))
1585ffd83dbSDimitry Andric     return objfile_up.release();
1595ffd83dbSDimitry Andric   return nullptr;
1605ffd83dbSDimitry Andric }
1615ffd83dbSDimitry Andric 
1625ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
1635ffd83dbSDimitry Andric   // Buffer sufficient to read a section header and find the pointer to the next
1645ffd83dbSDimitry Andric   // section.
1655ffd83dbSDimitry Andric   const uint32_t kBufferSize = 1024;
1665ffd83dbSDimitry Andric   DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
1675ffd83dbSDimitry Andric 
1685ffd83dbSDimitry Andric   llvm::DataExtractor data = section_header_data.GetAsLLVM();
1695ffd83dbSDimitry Andric   llvm::DataExtractor::Cursor c(0);
1705ffd83dbSDimitry Andric 
1715ffd83dbSDimitry Andric   // Each section consists of:
1725ffd83dbSDimitry Andric   // - a one-byte section id,
1735ffd83dbSDimitry Andric   // - the u32 size of the contents, in bytes,
1745ffd83dbSDimitry Andric   // - the actual contents.
1755ffd83dbSDimitry Andric   uint8_t section_id = data.getU8(c);
1765ffd83dbSDimitry Andric   uint64_t payload_len = data.getULEB128(c);
1775ffd83dbSDimitry Andric   if (!c)
1785ffd83dbSDimitry Andric     return !llvm::errorToBool(c.takeError());
1795ffd83dbSDimitry Andric 
1805ffd83dbSDimitry Andric   if (payload_len >= (uint64_t(1) << 32))
1815ffd83dbSDimitry Andric     return false;
1825ffd83dbSDimitry Andric 
1835ffd83dbSDimitry Andric   if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
1845ffd83dbSDimitry Andric     // Custom sections have the id 0. Their contents consist of a name
1855ffd83dbSDimitry Andric     // identifying the custom section, followed by an uninterpreted sequence
1865ffd83dbSDimitry Andric     // of bytes.
1875ffd83dbSDimitry Andric     lldb::offset_t prev_offset = c.tell();
1885ffd83dbSDimitry Andric     llvm::Optional<ConstString> sect_name = GetWasmString(data, c);
1895ffd83dbSDimitry Andric     if (!sect_name)
1905ffd83dbSDimitry Andric       return false;
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric     if (payload_len < c.tell() - prev_offset)
1935ffd83dbSDimitry Andric       return false;
1945ffd83dbSDimitry Andric 
1955ffd83dbSDimitry Andric     uint32_t section_length = payload_len - (c.tell() - prev_offset);
1965ffd83dbSDimitry Andric     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
1975ffd83dbSDimitry Andric                                         section_id, *sect_name});
1985ffd83dbSDimitry Andric     *offset_ptr += (c.tell() + section_length);
1995ffd83dbSDimitry Andric   } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) {
2005ffd83dbSDimitry Andric     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
2015ffd83dbSDimitry Andric                                         static_cast<uint32_t>(payload_len),
2025ffd83dbSDimitry Andric                                         section_id, ConstString()});
2035ffd83dbSDimitry Andric     *offset_ptr += (c.tell() + payload_len);
2045ffd83dbSDimitry Andric   } else {
2055ffd83dbSDimitry Andric     // Invalid section id.
2065ffd83dbSDimitry Andric     return false;
2075ffd83dbSDimitry Andric   }
2085ffd83dbSDimitry Andric   return true;
2095ffd83dbSDimitry Andric }
2105ffd83dbSDimitry Andric 
2115ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeSections() {
2125ffd83dbSDimitry Andric   lldb::offset_t offset = kWasmHeaderSize;
2135ffd83dbSDimitry Andric   if (IsInMemory()) {
2145ffd83dbSDimitry Andric     offset += m_memory_addr;
2155ffd83dbSDimitry Andric   }
2165ffd83dbSDimitry Andric 
2175ffd83dbSDimitry Andric   while (DecodeNextSection(&offset))
2185ffd83dbSDimitry Andric     ;
2195ffd83dbSDimitry Andric   return true;
2205ffd83dbSDimitry Andric }
2215ffd83dbSDimitry Andric 
2225ffd83dbSDimitry Andric size_t ObjectFileWasm::GetModuleSpecifications(
2235ffd83dbSDimitry Andric     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
2245ffd83dbSDimitry Andric     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
2255ffd83dbSDimitry Andric   if (!ValidateModuleHeader(data_sp)) {
2265ffd83dbSDimitry Andric     return 0;
2275ffd83dbSDimitry Andric   }
2285ffd83dbSDimitry Andric 
2295ffd83dbSDimitry Andric   ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
2305ffd83dbSDimitry Andric   specs.Append(spec);
2315ffd83dbSDimitry Andric   return 1;
2325ffd83dbSDimitry Andric }
2335ffd83dbSDimitry Andric 
2345ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp,
2355ffd83dbSDimitry Andric                                offset_t data_offset, const FileSpec *file,
2365ffd83dbSDimitry Andric                                offset_t offset, offset_t length)
2375ffd83dbSDimitry Andric     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
2385ffd83dbSDimitry Andric       m_arch("wasm32-unknown-unknown-wasm") {
2395ffd83dbSDimitry Andric   m_data.SetAddressByteSize(4);
2405ffd83dbSDimitry Andric }
2415ffd83dbSDimitry Andric 
2425ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
2435ffd83dbSDimitry Andric                                lldb::DataBufferSP &header_data_sp,
2445ffd83dbSDimitry Andric                                const lldb::ProcessSP &process_sp,
2455ffd83dbSDimitry Andric                                lldb::addr_t header_addr)
2465ffd83dbSDimitry Andric     : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
2475ffd83dbSDimitry Andric       m_arch("wasm32-unknown-unknown-wasm") {}
2485ffd83dbSDimitry Andric 
2495ffd83dbSDimitry Andric bool ObjectFileWasm::ParseHeader() {
2505ffd83dbSDimitry Andric   // We already parsed the header during initialization.
2515ffd83dbSDimitry Andric   return true;
2525ffd83dbSDimitry Andric }
2535ffd83dbSDimitry Andric 
2545ffd83dbSDimitry Andric Symtab *ObjectFileWasm::GetSymtab() { return nullptr; }
2555ffd83dbSDimitry Andric 
256*e8d8bef9SDimitry Andric static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
257*e8d8bef9SDimitry Andric   if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
258*e8d8bef9SDimitry Andric     return llvm::StringSwitch<SectionType>(Name)
259*e8d8bef9SDimitry Andric         .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
260*e8d8bef9SDimitry Andric         .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
261*e8d8bef9SDimitry Andric         .Case("addr", eSectionTypeDWARFDebugAddr)
262*e8d8bef9SDimitry Andric         .Case("aranges", eSectionTypeDWARFDebugAranges)
263*e8d8bef9SDimitry Andric         .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
264*e8d8bef9SDimitry Andric         .Case("frame", eSectionTypeDWARFDebugFrame)
265*e8d8bef9SDimitry Andric         .Case("info", eSectionTypeDWARFDebugInfo)
266*e8d8bef9SDimitry Andric         .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
267*e8d8bef9SDimitry Andric         .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
268*e8d8bef9SDimitry Andric         .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
269*e8d8bef9SDimitry Andric         .Case("loc", eSectionTypeDWARFDebugLoc)
270*e8d8bef9SDimitry Andric         .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
271*e8d8bef9SDimitry Andric         .Case("loclists", eSectionTypeDWARFDebugLocLists)
272*e8d8bef9SDimitry Andric         .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
273*e8d8bef9SDimitry Andric         .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
274*e8d8bef9SDimitry Andric         .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
275*e8d8bef9SDimitry Andric         .Case("names", eSectionTypeDWARFDebugNames)
276*e8d8bef9SDimitry Andric         .Case("pubnames", eSectionTypeDWARFDebugPubNames)
277*e8d8bef9SDimitry Andric         .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
278*e8d8bef9SDimitry Andric         .Case("ranges", eSectionTypeDWARFDebugRanges)
279*e8d8bef9SDimitry Andric         .Case("rnglists", eSectionTypeDWARFDebugRngLists)
280*e8d8bef9SDimitry Andric         .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
281*e8d8bef9SDimitry Andric         .Case("str", eSectionTypeDWARFDebugStr)
282*e8d8bef9SDimitry Andric         .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
283*e8d8bef9SDimitry Andric         .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
284*e8d8bef9SDimitry Andric         .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
285*e8d8bef9SDimitry Andric         .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
286*e8d8bef9SDimitry Andric         .Case("types", eSectionTypeDWARFDebugTypes)
287*e8d8bef9SDimitry Andric         .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
288*e8d8bef9SDimitry Andric         .Default(eSectionTypeOther);
289*e8d8bef9SDimitry Andric   }
290*e8d8bef9SDimitry Andric   return eSectionTypeOther;
291*e8d8bef9SDimitry Andric }
292*e8d8bef9SDimitry Andric 
2935ffd83dbSDimitry Andric void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
2945ffd83dbSDimitry Andric   if (m_sections_up)
2955ffd83dbSDimitry Andric     return;
2965ffd83dbSDimitry Andric 
2975ffd83dbSDimitry Andric   m_sections_up = std::make_unique<SectionList>();
2985ffd83dbSDimitry Andric 
2995ffd83dbSDimitry Andric   if (m_sect_infos.empty()) {
3005ffd83dbSDimitry Andric     DecodeSections();
3015ffd83dbSDimitry Andric   }
3025ffd83dbSDimitry Andric 
3035ffd83dbSDimitry Andric   for (const section_info &sect_info : m_sect_infos) {
3045ffd83dbSDimitry Andric     SectionType section_type = eSectionTypeOther;
3055ffd83dbSDimitry Andric     ConstString section_name;
3065ffd83dbSDimitry Andric     offset_t file_offset = sect_info.offset & 0xffffffff;
3075ffd83dbSDimitry Andric     addr_t vm_addr = file_offset;
3085ffd83dbSDimitry Andric     size_t vm_size = sect_info.size;
3095ffd83dbSDimitry Andric 
3105ffd83dbSDimitry Andric     if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
3115ffd83dbSDimitry Andric       section_type = eSectionTypeCode;
3125ffd83dbSDimitry Andric       section_name = ConstString("code");
3135ffd83dbSDimitry Andric 
3145ffd83dbSDimitry Andric       // A code address in DWARF for WebAssembly is the offset of an
3155ffd83dbSDimitry Andric       // instruction relative within the Code section of the WebAssembly file.
3165ffd83dbSDimitry Andric       // For this reason Section::GetFileAddress() must return zero for the
3175ffd83dbSDimitry Andric       // Code section.
3185ffd83dbSDimitry Andric       vm_addr = 0;
3195ffd83dbSDimitry Andric     } else {
320*e8d8bef9SDimitry Andric       section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
3215ffd83dbSDimitry Andric       if (section_type == eSectionTypeOther)
3225ffd83dbSDimitry Andric         continue;
3235ffd83dbSDimitry Andric       section_name = sect_info.name;
3245ffd83dbSDimitry Andric       if (!IsInMemory()) {
3255ffd83dbSDimitry Andric         vm_size = 0;
3265ffd83dbSDimitry Andric         vm_addr = 0;
3275ffd83dbSDimitry Andric       }
3285ffd83dbSDimitry Andric     }
3295ffd83dbSDimitry Andric 
3305ffd83dbSDimitry Andric     SectionSP section_sp(
3315ffd83dbSDimitry Andric         new Section(GetModule(), // Module to which this section belongs.
3325ffd83dbSDimitry Andric                     this,        // ObjectFile to which this section belongs and
3335ffd83dbSDimitry Andric                                  // should read section data from.
3345ffd83dbSDimitry Andric                     section_type,   // Section ID.
3355ffd83dbSDimitry Andric                     section_name,   // Section name.
3365ffd83dbSDimitry Andric                     section_type,   // Section type.
3375ffd83dbSDimitry Andric                     vm_addr,        // VM address.
3385ffd83dbSDimitry Andric                     vm_size,        // VM size in bytes of this section.
3395ffd83dbSDimitry Andric                     file_offset,    // Offset of this section in the file.
3405ffd83dbSDimitry Andric                     sect_info.size, // Size of the section as found in the file.
3415ffd83dbSDimitry Andric                     0,              // Alignment of the section
3425ffd83dbSDimitry Andric                     0,              // Flags for this section.
3435ffd83dbSDimitry Andric                     1));            // Number of host bytes per target byte
3445ffd83dbSDimitry Andric     m_sections_up->AddSection(section_sp);
3455ffd83dbSDimitry Andric     unified_section_list.AddSection(section_sp);
3465ffd83dbSDimitry Andric   }
3475ffd83dbSDimitry Andric }
3485ffd83dbSDimitry Andric 
3495ffd83dbSDimitry Andric bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
3505ffd83dbSDimitry Andric                                     bool value_is_offset) {
3515ffd83dbSDimitry Andric   /// In WebAssembly, linear memory is disjointed from code space. The VM can
3525ffd83dbSDimitry Andric   /// load multiple instances of a module, which logically share the same code.
3535ffd83dbSDimitry Andric   /// We represent a wasm32 code address with 64-bits, like:
3545ffd83dbSDimitry Andric   /// 63            32 31             0
3555ffd83dbSDimitry Andric   /// +---------------+---------------+
3565ffd83dbSDimitry Andric   /// +   module_id   |     offset    |
3575ffd83dbSDimitry Andric   /// +---------------+---------------+
3585ffd83dbSDimitry Andric   /// where the lower 32 bits represent a module offset (relative to the module
3595ffd83dbSDimitry Andric   /// start not to the beginning of the code section) and the higher 32 bits
3605ffd83dbSDimitry Andric   /// uniquely identify the module in the WebAssembly VM.
3615ffd83dbSDimitry Andric   /// In other words, we assume that each WebAssembly module is loaded by the
3625ffd83dbSDimitry Andric   /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
3635ffd83dbSDimitry Andric   /// 0x0000000400000000 for module_id == 4.
3645ffd83dbSDimitry Andric   /// These 64-bit addresses will be used to request code ranges for a specific
3655ffd83dbSDimitry Andric   /// module from the WebAssembly engine.
3665ffd83dbSDimitry Andric 
3675ffd83dbSDimitry Andric   assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
3685ffd83dbSDimitry Andric          m_memory_addr == load_address);
3695ffd83dbSDimitry Andric 
3705ffd83dbSDimitry Andric   ModuleSP module_sp = GetModule();
3715ffd83dbSDimitry Andric   if (!module_sp)
3725ffd83dbSDimitry Andric     return false;
3735ffd83dbSDimitry Andric 
3745ffd83dbSDimitry Andric   DecodeSections();
3755ffd83dbSDimitry Andric 
3765ffd83dbSDimitry Andric   size_t num_loaded_sections = 0;
3775ffd83dbSDimitry Andric   SectionList *section_list = GetSectionList();
3785ffd83dbSDimitry Andric   if (!section_list)
3795ffd83dbSDimitry Andric     return false;
3805ffd83dbSDimitry Andric 
3815ffd83dbSDimitry Andric   const size_t num_sections = section_list->GetSize();
3825ffd83dbSDimitry Andric   for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
3835ffd83dbSDimitry Andric     SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
3845ffd83dbSDimitry Andric     if (target.SetSectionLoadAddress(
3855ffd83dbSDimitry Andric             section_sp, load_address | section_sp->GetFileOffset())) {
3865ffd83dbSDimitry Andric       ++num_loaded_sections;
3875ffd83dbSDimitry Andric     }
3885ffd83dbSDimitry Andric   }
3895ffd83dbSDimitry Andric 
3905ffd83dbSDimitry Andric   return num_loaded_sections > 0;
3915ffd83dbSDimitry Andric }
3925ffd83dbSDimitry Andric 
3935ffd83dbSDimitry Andric DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
3945ffd83dbSDimitry Andric   DataExtractor data;
3955ffd83dbSDimitry Andric   if (m_file) {
3965ffd83dbSDimitry Andric     if (offset < GetByteSize()) {
3975ffd83dbSDimitry Andric       size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
3985ffd83dbSDimitry Andric       auto buffer_sp = MapFileData(m_file, size, offset);
3995ffd83dbSDimitry Andric       return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
4005ffd83dbSDimitry Andric     }
4015ffd83dbSDimitry Andric   } else {
4025ffd83dbSDimitry Andric     ProcessSP process_sp(m_process_wp.lock());
4035ffd83dbSDimitry Andric     if (process_sp) {
4045ffd83dbSDimitry Andric       auto data_up = std::make_unique<DataBufferHeap>(size, 0);
4055ffd83dbSDimitry Andric       Status readmem_error;
4065ffd83dbSDimitry Andric       size_t bytes_read = process_sp->ReadMemory(
4075ffd83dbSDimitry Andric           offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
4085ffd83dbSDimitry Andric       if (bytes_read > 0) {
4095ffd83dbSDimitry Andric         DataBufferSP buffer_sp(data_up.release());
4105ffd83dbSDimitry Andric         data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
4115ffd83dbSDimitry Andric       }
4125ffd83dbSDimitry Andric     }
4135ffd83dbSDimitry Andric   }
4145ffd83dbSDimitry Andric 
4155ffd83dbSDimitry Andric   data.SetByteOrder(GetByteOrder());
4165ffd83dbSDimitry Andric   return data;
4175ffd83dbSDimitry Andric }
4185ffd83dbSDimitry Andric 
4195ffd83dbSDimitry Andric llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
4205ffd83dbSDimitry Andric   static ConstString g_sect_name_external_debug_info("external_debug_info");
4215ffd83dbSDimitry Andric 
4225ffd83dbSDimitry Andric   for (const section_info &sect_info : m_sect_infos) {
4235ffd83dbSDimitry Andric     if (g_sect_name_external_debug_info == sect_info.name) {
4245ffd83dbSDimitry Andric       const uint32_t kBufferSize = 1024;
4255ffd83dbSDimitry Andric       DataExtractor section_header_data =
4265ffd83dbSDimitry Andric           ReadImageData(sect_info.offset, kBufferSize);
4275ffd83dbSDimitry Andric       llvm::DataExtractor data = section_header_data.GetAsLLVM();
4285ffd83dbSDimitry Andric       llvm::DataExtractor::Cursor c(0);
4295ffd83dbSDimitry Andric       llvm::Optional<ConstString> symbols_url = GetWasmString(data, c);
4305ffd83dbSDimitry Andric       if (symbols_url)
4315ffd83dbSDimitry Andric         return FileSpec(symbols_url->GetStringRef());
4325ffd83dbSDimitry Andric     }
4335ffd83dbSDimitry Andric   }
4345ffd83dbSDimitry Andric   return llvm::None;
4355ffd83dbSDimitry Andric }
4365ffd83dbSDimitry Andric 
4375ffd83dbSDimitry Andric void ObjectFileWasm::Dump(Stream *s) {
4385ffd83dbSDimitry Andric   ModuleSP module_sp(GetModule());
4395ffd83dbSDimitry Andric   if (!module_sp)
4405ffd83dbSDimitry Andric     return;
4415ffd83dbSDimitry Andric 
4425ffd83dbSDimitry Andric   std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
4435ffd83dbSDimitry Andric 
4445ffd83dbSDimitry Andric   llvm::raw_ostream &ostream = s->AsRawOstream();
4455ffd83dbSDimitry Andric   ostream << static_cast<void *>(this) << ": ";
4465ffd83dbSDimitry Andric   s->Indent();
4475ffd83dbSDimitry Andric   ostream << "ObjectFileWasm, file = '";
4485ffd83dbSDimitry Andric   m_file.Dump(ostream);
4495ffd83dbSDimitry Andric   ostream << "', arch = ";
4505ffd83dbSDimitry Andric   ostream << GetArchitecture().GetArchitectureName() << "\n";
4515ffd83dbSDimitry Andric 
4525ffd83dbSDimitry Andric   SectionList *sections = GetSectionList();
4535ffd83dbSDimitry Andric   if (sections) {
4545ffd83dbSDimitry Andric     sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
4555ffd83dbSDimitry Andric                    UINT32_MAX);
4565ffd83dbSDimitry Andric   }
4575ffd83dbSDimitry Andric   ostream << "\n";
4585ffd83dbSDimitry Andric   DumpSectionHeaders(ostream);
4595ffd83dbSDimitry Andric   ostream << "\n";
4605ffd83dbSDimitry Andric }
4615ffd83dbSDimitry Andric 
4625ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
4635ffd83dbSDimitry Andric                                        const section_info_t &sh) {
4645ffd83dbSDimitry Andric   ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
4655ffd83dbSDimitry Andric           << llvm::format_hex(sh.offset, 10) << " "
4665ffd83dbSDimitry Andric           << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
4675ffd83dbSDimitry Andric           << "\n";
4685ffd83dbSDimitry Andric }
4695ffd83dbSDimitry Andric 
4705ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
4715ffd83dbSDimitry Andric   ostream << "Section Headers\n";
4725ffd83dbSDimitry Andric   ostream << "IDX  name             addr       size       id\n";
4735ffd83dbSDimitry Andric   ostream << "==== ---------------- ---------- ---------- ------\n";
4745ffd83dbSDimitry Andric 
4755ffd83dbSDimitry Andric   uint32_t idx = 0;
4765ffd83dbSDimitry Andric   for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
4775ffd83dbSDimitry Andric        ++pos, ++idx) {
4785ffd83dbSDimitry Andric     ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
4795ffd83dbSDimitry Andric     ObjectFileWasm::DumpSectionHeader(ostream, *pos);
4805ffd83dbSDimitry Andric   }
4815ffd83dbSDimitry Andric }
482