14bafceceSPaolo Severini //===-- ObjectFileWasm.cpp ------------------------------------------------===//
24bafceceSPaolo Severini //
34bafceceSPaolo Severini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44bafceceSPaolo Severini // See https://llvm.org/LICENSE.txt for license information.
54bafceceSPaolo Severini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64bafceceSPaolo Severini //
74bafceceSPaolo Severini //===----------------------------------------------------------------------===//
84bafceceSPaolo Severini 
94bafceceSPaolo Severini #include "ObjectFileWasm.h"
104bafceceSPaolo Severini #include "lldb/Core/Module.h"
114bafceceSPaolo Severini #include "lldb/Core/ModuleSpec.h"
124bafceceSPaolo Severini #include "lldb/Core/PluginManager.h"
134bafceceSPaolo Severini #include "lldb/Core/Section.h"
144bafceceSPaolo Severini #include "lldb/Target/Process.h"
154bafceceSPaolo Severini #include "lldb/Target/SectionLoadList.h"
164bafceceSPaolo Severini #include "lldb/Target/Target.h"
174bafceceSPaolo Severini #include "lldb/Utility/DataBufferHeap.h"
184bafceceSPaolo Severini #include "lldb/Utility/Log.h"
194bafceceSPaolo Severini #include "llvm/ADT/ArrayRef.h"
204bafceceSPaolo Severini #include "llvm/ADT/SmallVector.h"
214bafceceSPaolo Severini #include "llvm/ADT/StringRef.h"
224bafceceSPaolo Severini #include "llvm/BinaryFormat/Magic.h"
234bafceceSPaolo Severini #include "llvm/BinaryFormat/Wasm.h"
244bafceceSPaolo Severini #include "llvm/Support/Endian.h"
254bafceceSPaolo Severini #include "llvm/Support/Format.h"
264bafceceSPaolo Severini 
274bafceceSPaolo Severini using namespace lldb;
284bafceceSPaolo Severini using namespace lldb_private;
294bafceceSPaolo Severini using namespace lldb_private::wasm;
304bafceceSPaolo Severini 
31bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(ObjectFileWasm)
32fbb4d1e4SJonas Devlieghere 
334bafceceSPaolo Severini static const uint32_t kWasmHeaderSize =
344bafceceSPaolo Severini     sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
354bafceceSPaolo Severini 
364bafceceSPaolo Severini /// Checks whether the data buffer starts with a valid Wasm module header.
374bafceceSPaolo Severini static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
384bafceceSPaolo Severini   if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
394bafceceSPaolo Severini     return false;
404bafceceSPaolo Severini 
414bafceceSPaolo Severini   if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
424bafceceSPaolo Severini       llvm::file_magic::wasm_object)
434bafceceSPaolo Severini     return false;
444bafceceSPaolo Severini 
454bafceceSPaolo Severini   uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
464bafceceSPaolo Severini 
474bafceceSPaolo Severini   uint32_t version = llvm::support::endian::read32le(Ptr);
484bafceceSPaolo Severini   return version == llvm::wasm::WasmVersion;
494bafceceSPaolo Severini }
504bafceceSPaolo Severini 
514bafceceSPaolo Severini static llvm::Optional<ConstString>
524bafceceSPaolo Severini GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
534bafceceSPaolo Severini   // A Wasm string is encoded as a vector of UTF-8 codes.
544bafceceSPaolo Severini   // Vectors are encoded with their u32 length followed by the element
554bafceceSPaolo Severini   // sequence.
564bafceceSPaolo Severini   uint64_t len = data.getULEB128(c);
574bafceceSPaolo Severini   if (!c) {
584bafceceSPaolo Severini     consumeError(c.takeError());
594bafceceSPaolo Severini     return llvm::None;
604bafceceSPaolo Severini   }
614bafceceSPaolo Severini 
624bafceceSPaolo Severini   if (len >= (uint64_t(1) << 32)) {
634bafceceSPaolo Severini     return llvm::None;
644bafceceSPaolo Severini   }
654bafceceSPaolo Severini 
664bafceceSPaolo Severini   llvm::SmallVector<uint8_t, 32> str_storage;
674bafceceSPaolo Severini   data.getU8(c, str_storage, len);
684bafceceSPaolo Severini   if (!c) {
694bafceceSPaolo Severini     consumeError(c.takeError());
704bafceceSPaolo Severini     return llvm::None;
714bafceceSPaolo Severini   }
724bafceceSPaolo Severini 
734bafceceSPaolo Severini   llvm::StringRef str = toStringRef(makeArrayRef(str_storage));
744bafceceSPaolo Severini   return ConstString(str);
754bafceceSPaolo Severini }
764bafceceSPaolo Severini 
779b3254dbSPaolo Severini char ObjectFileWasm::ID;
789b3254dbSPaolo Severini 
794bafceceSPaolo Severini void ObjectFileWasm::Initialize() {
804bafceceSPaolo Severini   PluginManager::RegisterPlugin(GetPluginNameStatic(),
814bafceceSPaolo Severini                                 GetPluginDescriptionStatic(), CreateInstance,
824bafceceSPaolo Severini                                 CreateMemoryInstance, GetModuleSpecifications);
834bafceceSPaolo Severini }
844bafceceSPaolo Severini 
854bafceceSPaolo Severini void ObjectFileWasm::Terminate() {
864bafceceSPaolo Severini   PluginManager::UnregisterPlugin(CreateInstance);
874bafceceSPaolo Severini }
884bafceceSPaolo Severini 
894bafceceSPaolo Severini ConstString ObjectFileWasm::GetPluginNameStatic() {
904bafceceSPaolo Severini   static ConstString g_name("wasm");
914bafceceSPaolo Severini   return g_name;
924bafceceSPaolo Severini }
934bafceceSPaolo Severini 
944bafceceSPaolo Severini ObjectFile *
954bafceceSPaolo Severini ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
964bafceceSPaolo Severini                                offset_t data_offset, const FileSpec *file,
974bafceceSPaolo Severini                                offset_t file_offset, offset_t length) {
984bafceceSPaolo Severini   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
994bafceceSPaolo Severini 
1004bafceceSPaolo Severini   if (!data_sp) {
1014bafceceSPaolo Severini     data_sp = MapFileData(*file, length, file_offset);
1024bafceceSPaolo Severini     if (!data_sp) {
1034bafceceSPaolo Severini       LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
1044bafceceSPaolo Severini                 file->GetPath().c_str());
1054bafceceSPaolo Severini       return nullptr;
1064bafceceSPaolo Severini     }
1074bafceceSPaolo Severini     data_offset = 0;
1084bafceceSPaolo Severini   }
1094bafceceSPaolo Severini 
1104bafceceSPaolo Severini   assert(data_sp);
1114bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp)) {
1124bafceceSPaolo Severini     LLDB_LOGF(log,
1134bafceceSPaolo Severini               "Failed to create ObjectFileWasm instance: invalid Wasm header");
1144bafceceSPaolo Severini     return nullptr;
1154bafceceSPaolo Severini   }
1164bafceceSPaolo Severini 
1174bafceceSPaolo Severini   // Update the data to contain the entire file if it doesn't contain it
1184bafceceSPaolo Severini   // already.
1194bafceceSPaolo Severini   if (data_sp->GetByteSize() < length) {
1204bafceceSPaolo Severini     data_sp = MapFileData(*file, length, file_offset);
1214bafceceSPaolo Severini     if (!data_sp) {
1224bafceceSPaolo Severini       LLDB_LOGF(log,
1234bafceceSPaolo Severini                 "Failed to create ObjectFileWasm instance: cannot read file %s",
1244bafceceSPaolo Severini                 file->GetPath().c_str());
1254bafceceSPaolo Severini       return nullptr;
1264bafceceSPaolo Severini     }
1274bafceceSPaolo Severini     data_offset = 0;
1284bafceceSPaolo Severini   }
1294bafceceSPaolo Severini 
1304bafceceSPaolo Severini   std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
1314bafceceSPaolo Severini       module_sp, data_sp, data_offset, file, file_offset, length));
1324bafceceSPaolo Severini   ArchSpec spec = objfile_up->GetArchitecture();
1334bafceceSPaolo Severini   if (spec && objfile_up->SetModulesArchitecture(spec)) {
1344bafceceSPaolo Severini     LLDB_LOGF(log,
1354bafceceSPaolo Severini               "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
1364bafceceSPaolo Severini               static_cast<void *>(objfile_up.get()),
1374bafceceSPaolo Severini               static_cast<void *>(objfile_up->GetModule().get()),
1384bafceceSPaolo Severini               objfile_up->GetModule()->GetSpecificationDescription().c_str(),
1394bafceceSPaolo Severini               file ? file->GetPath().c_str() : "<NULL>");
1404bafceceSPaolo Severini     return objfile_up.release();
1414bafceceSPaolo Severini   }
1424bafceceSPaolo Severini 
1434bafceceSPaolo Severini   LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
1444bafceceSPaolo Severini   return nullptr;
1454bafceceSPaolo Severini }
1464bafceceSPaolo Severini 
1474bafceceSPaolo Severini ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
1484bafceceSPaolo Severini                                                  DataBufferSP &data_sp,
1494bafceceSPaolo Severini                                                  const ProcessSP &process_sp,
1504bafceceSPaolo Severini                                                  addr_t header_addr) {
1514bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp))
1524bafceceSPaolo Severini     return nullptr;
1534bafceceSPaolo Severini 
1544bafceceSPaolo Severini   std::unique_ptr<ObjectFileWasm> objfile_up(
1554bafceceSPaolo Severini       new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
1564bafceceSPaolo Severini   ArchSpec spec = objfile_up->GetArchitecture();
1574bafceceSPaolo Severini   if (spec && objfile_up->SetModulesArchitecture(spec))
1584bafceceSPaolo Severini     return objfile_up.release();
1594bafceceSPaolo Severini   return nullptr;
1604bafceceSPaolo Severini }
1614bafceceSPaolo Severini 
1624bafceceSPaolo Severini bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
1634bafceceSPaolo Severini   // Buffer sufficient to read a section header and find the pointer to the next
1644bafceceSPaolo Severini   // section.
1654bafceceSPaolo Severini   const uint32_t kBufferSize = 1024;
1664bafceceSPaolo Severini   DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
1674bafceceSPaolo Severini 
1684bafceceSPaolo Severini   llvm::DataExtractor data = section_header_data.GetAsLLVM();
1694bafceceSPaolo Severini   llvm::DataExtractor::Cursor c(0);
1704bafceceSPaolo Severini 
1714bafceceSPaolo Severini   // Each section consists of:
1724bafceceSPaolo Severini   // - a one-byte section id,
1734bafceceSPaolo Severini   // - the u32 size of the contents, in bytes,
1744bafceceSPaolo Severini   // - the actual contents.
1754bafceceSPaolo Severini   uint8_t section_id = data.getU8(c);
1764bafceceSPaolo Severini   uint64_t payload_len = data.getULEB128(c);
1774bafceceSPaolo Severini   if (!c)
1784bafceceSPaolo Severini     return !llvm::errorToBool(c.takeError());
1794bafceceSPaolo Severini 
1804bafceceSPaolo Severini   if (payload_len >= (uint64_t(1) << 32))
1814bafceceSPaolo Severini     return false;
1824bafceceSPaolo Severini 
1834bafceceSPaolo Severini   if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
1849b3254dbSPaolo Severini     // Custom sections have the id 0. Their contents consist of a name
1859b3254dbSPaolo Severini     // identifying the custom section, followed by an uninterpreted sequence
1869b3254dbSPaolo Severini     // of bytes.
1874bafceceSPaolo Severini     lldb::offset_t prev_offset = c.tell();
1884bafceceSPaolo Severini     llvm::Optional<ConstString> sect_name = GetWasmString(data, c);
1894bafceceSPaolo Severini     if (!sect_name)
1904bafceceSPaolo Severini       return false;
1914bafceceSPaolo Severini 
1924bafceceSPaolo Severini     if (payload_len < c.tell() - prev_offset)
1934bafceceSPaolo Severini       return false;
1944bafceceSPaolo Severini 
1954bafceceSPaolo Severini     uint32_t section_length = payload_len - (c.tell() - prev_offset);
1964bafceceSPaolo Severini     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
1974bafceceSPaolo Severini                                         section_id, *sect_name});
1984bafceceSPaolo Severini     *offset_ptr += (c.tell() + section_length);
1994bafceceSPaolo Severini   } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) {
2004bafceceSPaolo Severini     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
2014bafceceSPaolo Severini                                         static_cast<uint32_t>(payload_len),
2024bafceceSPaolo Severini                                         section_id, ConstString()});
2034bafceceSPaolo Severini     *offset_ptr += (c.tell() + payload_len);
2044bafceceSPaolo Severini   } else {
2054bafceceSPaolo Severini     // Invalid section id.
2064bafceceSPaolo Severini     return false;
2074bafceceSPaolo Severini   }
2084bafceceSPaolo Severini   return true;
2094bafceceSPaolo Severini }
2104bafceceSPaolo Severini 
2114bafceceSPaolo Severini bool ObjectFileWasm::DecodeSections() {
2124bafceceSPaolo Severini   lldb::offset_t offset = kWasmHeaderSize;
2134bafceceSPaolo Severini   if (IsInMemory()) {
2144bafceceSPaolo Severini     offset += m_memory_addr;
2154bafceceSPaolo Severini   }
2164bafceceSPaolo Severini 
2174bafceceSPaolo Severini   while (DecodeNextSection(&offset))
2184bafceceSPaolo Severini     ;
2194bafceceSPaolo Severini   return true;
2204bafceceSPaolo Severini }
2214bafceceSPaolo Severini 
2224bafceceSPaolo Severini size_t ObjectFileWasm::GetModuleSpecifications(
2234bafceceSPaolo Severini     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
2244bafceceSPaolo Severini     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
2254bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp)) {
2264bafceceSPaolo Severini     return 0;
2274bafceceSPaolo Severini   }
2284bafceceSPaolo Severini 
2294bafceceSPaolo Severini   ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
2304bafceceSPaolo Severini   specs.Append(spec);
2314bafceceSPaolo Severini   return 1;
2324bafceceSPaolo Severini }
2334bafceceSPaolo Severini 
2344bafceceSPaolo Severini ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp,
2354bafceceSPaolo Severini                                offset_t data_offset, const FileSpec *file,
2364bafceceSPaolo Severini                                offset_t offset, offset_t length)
2374bafceceSPaolo Severini     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
238c1121908SPaolo Severini       m_arch("wasm32-unknown-unknown-wasm") {
2394bafceceSPaolo Severini   m_data.SetAddressByteSize(4);
2404bafceceSPaolo Severini }
2414bafceceSPaolo Severini 
2424bafceceSPaolo Severini ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
2434bafceceSPaolo Severini                                lldb::DataBufferSP &header_data_sp,
2444bafceceSPaolo Severini                                const lldb::ProcessSP &process_sp,
2454bafceceSPaolo Severini                                lldb::addr_t header_addr)
2464bafceceSPaolo Severini     : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
247c1121908SPaolo Severini       m_arch("wasm32-unknown-unknown-wasm") {}
2484bafceceSPaolo Severini 
2494bafceceSPaolo Severini bool ObjectFileWasm::ParseHeader() {
2504bafceceSPaolo Severini   // We already parsed the header during initialization.
2514bafceceSPaolo Severini   return true;
2524bafceceSPaolo Severini }
2534bafceceSPaolo Severini 
2544bafceceSPaolo Severini Symtab *ObjectFileWasm::GetSymtab() { return nullptr; }
2554bafceceSPaolo Severini 
256*7ad54d19SPhilip Pfaffe static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
257*7ad54d19SPhilip Pfaffe   if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
258*7ad54d19SPhilip Pfaffe     return llvm::StringSwitch<SectionType>(Name)
259*7ad54d19SPhilip Pfaffe         .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
260*7ad54d19SPhilip Pfaffe         .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
261*7ad54d19SPhilip Pfaffe         .Case("addr", eSectionTypeDWARFDebugAddr)
262*7ad54d19SPhilip Pfaffe         .Case("aranges", eSectionTypeDWARFDebugAranges)
263*7ad54d19SPhilip Pfaffe         .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
264*7ad54d19SPhilip Pfaffe         .Case("frame", eSectionTypeDWARFDebugFrame)
265*7ad54d19SPhilip Pfaffe         .Case("info", eSectionTypeDWARFDebugInfo)
266*7ad54d19SPhilip Pfaffe         .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
267*7ad54d19SPhilip Pfaffe         .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
268*7ad54d19SPhilip Pfaffe         .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
269*7ad54d19SPhilip Pfaffe         .Case("loc", eSectionTypeDWARFDebugLoc)
270*7ad54d19SPhilip Pfaffe         .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
271*7ad54d19SPhilip Pfaffe         .Case("loclists", eSectionTypeDWARFDebugLocLists)
272*7ad54d19SPhilip Pfaffe         .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
273*7ad54d19SPhilip Pfaffe         .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
274*7ad54d19SPhilip Pfaffe         .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
275*7ad54d19SPhilip Pfaffe         .Case("names", eSectionTypeDWARFDebugNames)
276*7ad54d19SPhilip Pfaffe         .Case("pubnames", eSectionTypeDWARFDebugPubNames)
277*7ad54d19SPhilip Pfaffe         .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
278*7ad54d19SPhilip Pfaffe         .Case("ranges", eSectionTypeDWARFDebugRanges)
279*7ad54d19SPhilip Pfaffe         .Case("rnglists", eSectionTypeDWARFDebugRngLists)
280*7ad54d19SPhilip Pfaffe         .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
281*7ad54d19SPhilip Pfaffe         .Case("str", eSectionTypeDWARFDebugStr)
282*7ad54d19SPhilip Pfaffe         .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
283*7ad54d19SPhilip Pfaffe         .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
284*7ad54d19SPhilip Pfaffe         .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
285*7ad54d19SPhilip Pfaffe         .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
286*7ad54d19SPhilip Pfaffe         .Case("types", eSectionTypeDWARFDebugTypes)
287*7ad54d19SPhilip Pfaffe         .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
288*7ad54d19SPhilip Pfaffe         .Default(eSectionTypeOther);
289*7ad54d19SPhilip Pfaffe   }
290*7ad54d19SPhilip Pfaffe   return eSectionTypeOther;
291*7ad54d19SPhilip Pfaffe }
292*7ad54d19SPhilip Pfaffe 
2934bafceceSPaolo Severini void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
2944bafceceSPaolo Severini   if (m_sections_up)
2954bafceceSPaolo Severini     return;
2964bafceceSPaolo Severini 
2974bafceceSPaolo Severini   m_sections_up = std::make_unique<SectionList>();
2984bafceceSPaolo Severini 
2994bafceceSPaolo Severini   if (m_sect_infos.empty()) {
3004bafceceSPaolo Severini     DecodeSections();
3014bafceceSPaolo Severini   }
3024bafceceSPaolo Severini 
3034bafceceSPaolo Severini   for (const section_info &sect_info : m_sect_infos) {
3044bafceceSPaolo Severini     SectionType section_type = eSectionTypeOther;
3054bafceceSPaolo Severini     ConstString section_name;
306c1121908SPaolo Severini     offset_t file_offset = sect_info.offset & 0xffffffff;
307c1121908SPaolo Severini     addr_t vm_addr = file_offset;
308c1121908SPaolo Severini     size_t vm_size = sect_info.size;
3094bafceceSPaolo Severini 
3104bafceceSPaolo Severini     if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
3114bafceceSPaolo Severini       section_type = eSectionTypeCode;
3124bafceceSPaolo Severini       section_name = ConstString("code");
313c1121908SPaolo Severini 
314c1121908SPaolo Severini       // A code address in DWARF for WebAssembly is the offset of an
315c1121908SPaolo Severini       // instruction relative within the Code section of the WebAssembly file.
316c1121908SPaolo Severini       // For this reason Section::GetFileAddress() must return zero for the
317c1121908SPaolo Severini       // Code section.
318c1121908SPaolo Severini       vm_addr = 0;
3194bafceceSPaolo Severini     } else {
320*7ad54d19SPhilip Pfaffe       section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
3214bafceceSPaolo Severini       if (section_type == eSectionTypeOther)
3224bafceceSPaolo Severini         continue;
3234bafceceSPaolo Severini       section_name = sect_info.name;
324c1121908SPaolo Severini       if (!IsInMemory()) {
325c1121908SPaolo Severini         vm_size = 0;
326c1121908SPaolo Severini         vm_addr = 0;
3274bafceceSPaolo Severini       }
3284bafceceSPaolo Severini     }
3294bafceceSPaolo Severini 
3304bafceceSPaolo Severini     SectionSP section_sp(
3314bafceceSPaolo Severini         new Section(GetModule(), // Module to which this section belongs.
3324bafceceSPaolo Severini                     this,        // ObjectFile to which this section belongs and
3334bafceceSPaolo Severini                                  // should read section data from.
3344bafceceSPaolo Severini                     section_type,   // Section ID.
3354bafceceSPaolo Severini                     section_name,   // Section name.
3364bafceceSPaolo Severini                     section_type,   // Section type.
3374bafceceSPaolo Severini                     vm_addr,        // VM address.
3384bafceceSPaolo Severini                     vm_size,        // VM size in bytes of this section.
3394bafceceSPaolo Severini                     file_offset,    // Offset of this section in the file.
3404bafceceSPaolo Severini                     sect_info.size, // Size of the section as found in the file.
3414bafceceSPaolo Severini                     0,              // Alignment of the section
3424bafceceSPaolo Severini                     0,              // Flags for this section.
3434bafceceSPaolo Severini                     1));            // Number of host bytes per target byte
3444bafceceSPaolo Severini     m_sections_up->AddSection(section_sp);
3454bafceceSPaolo Severini     unified_section_list.AddSection(section_sp);
3464bafceceSPaolo Severini   }
3474bafceceSPaolo Severini }
3484bafceceSPaolo Severini 
3494bafceceSPaolo Severini bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
3504bafceceSPaolo Severini                                     bool value_is_offset) {
3514bafceceSPaolo Severini   /// In WebAssembly, linear memory is disjointed from code space. The VM can
3524bafceceSPaolo Severini   /// load multiple instances of a module, which logically share the same code.
3534bafceceSPaolo Severini   /// We represent a wasm32 code address with 64-bits, like:
3544bafceceSPaolo Severini   /// 63            32 31             0
3554bafceceSPaolo Severini   /// +---------------+---------------+
3564bafceceSPaolo Severini   /// +   module_id   |     offset    |
3574bafceceSPaolo Severini   /// +---------------+---------------+
3584bafceceSPaolo Severini   /// where the lower 32 bits represent a module offset (relative to the module
3594bafceceSPaolo Severini   /// start not to the beginning of the code section) and the higher 32 bits
3604bafceceSPaolo Severini   /// uniquely identify the module in the WebAssembly VM.
3614bafceceSPaolo Severini   /// In other words, we assume that each WebAssembly module is loaded by the
3624bafceceSPaolo Severini   /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
3634bafceceSPaolo Severini   /// 0x0000000400000000 for module_id == 4.
3644bafceceSPaolo Severini   /// These 64-bit addresses will be used to request code ranges for a specific
3654bafceceSPaolo Severini   /// module from the WebAssembly engine.
366c1121908SPaolo Severini 
367c1121908SPaolo Severini   assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
368c1121908SPaolo Severini          m_memory_addr == load_address);
369c1121908SPaolo Severini 
3704bafceceSPaolo Severini   ModuleSP module_sp = GetModule();
3714bafceceSPaolo Severini   if (!module_sp)
3724bafceceSPaolo Severini     return false;
3734bafceceSPaolo Severini 
3744bafceceSPaolo Severini   DecodeSections();
3754bafceceSPaolo Severini 
3764bafceceSPaolo Severini   size_t num_loaded_sections = 0;
3774bafceceSPaolo Severini   SectionList *section_list = GetSectionList();
3784bafceceSPaolo Severini   if (!section_list)
3794bafceceSPaolo Severini     return false;
3804bafceceSPaolo Severini 
3814bafceceSPaolo Severini   const size_t num_sections = section_list->GetSize();
382c1121908SPaolo Severini   for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
3834bafceceSPaolo Severini     SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
384c1121908SPaolo Severini     if (target.SetSectionLoadAddress(
385c1121908SPaolo Severini             section_sp, load_address | section_sp->GetFileOffset())) {
3864bafceceSPaolo Severini       ++num_loaded_sections;
3874bafceceSPaolo Severini     }
3884bafceceSPaolo Severini   }
3894bafceceSPaolo Severini 
3904bafceceSPaolo Severini   return num_loaded_sections > 0;
3914bafceceSPaolo Severini }
3924bafceceSPaolo Severini 
393c1121908SPaolo Severini DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
3944bafceceSPaolo Severini   DataExtractor data;
3954bafceceSPaolo Severini   if (m_file) {
3964bafceceSPaolo Severini     if (offset < GetByteSize()) {
397c1121908SPaolo Severini       size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
3984bafceceSPaolo Severini       auto buffer_sp = MapFileData(m_file, size, offset);
3994bafceceSPaolo Severini       return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
4004bafceceSPaolo Severini     }
4014bafceceSPaolo Severini   } else {
4024bafceceSPaolo Severini     ProcessSP process_sp(m_process_wp.lock());
4034bafceceSPaolo Severini     if (process_sp) {
4044bafceceSPaolo Severini       auto data_up = std::make_unique<DataBufferHeap>(size, 0);
4054bafceceSPaolo Severini       Status readmem_error;
4064bafceceSPaolo Severini       size_t bytes_read = process_sp->ReadMemory(
4074bafceceSPaolo Severini           offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
4084bafceceSPaolo Severini       if (bytes_read > 0) {
4094bafceceSPaolo Severini         DataBufferSP buffer_sp(data_up.release());
4104bafceceSPaolo Severini         data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
4114bafceceSPaolo Severini       }
4124bafceceSPaolo Severini     }
4134bafceceSPaolo Severini   }
4144bafceceSPaolo Severini 
4154bafceceSPaolo Severini   data.SetByteOrder(GetByteOrder());
4164bafceceSPaolo Severini   return data;
4174bafceceSPaolo Severini }
4184bafceceSPaolo Severini 
4199b3254dbSPaolo Severini llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
4209b3254dbSPaolo Severini   static ConstString g_sect_name_external_debug_info("external_debug_info");
4219b3254dbSPaolo Severini 
4229b3254dbSPaolo Severini   for (const section_info &sect_info : m_sect_infos) {
4239b3254dbSPaolo Severini     if (g_sect_name_external_debug_info == sect_info.name) {
4249b3254dbSPaolo Severini       const uint32_t kBufferSize = 1024;
4259b3254dbSPaolo Severini       DataExtractor section_header_data =
4269b3254dbSPaolo Severini           ReadImageData(sect_info.offset, kBufferSize);
4279b3254dbSPaolo Severini       llvm::DataExtractor data = section_header_data.GetAsLLVM();
4289b3254dbSPaolo Severini       llvm::DataExtractor::Cursor c(0);
4299b3254dbSPaolo Severini       llvm::Optional<ConstString> symbols_url = GetWasmString(data, c);
4309b3254dbSPaolo Severini       if (symbols_url)
4319b3254dbSPaolo Severini         return FileSpec(symbols_url->GetStringRef());
4329b3254dbSPaolo Severini     }
4339b3254dbSPaolo Severini   }
4349b3254dbSPaolo Severini   return llvm::None;
4359b3254dbSPaolo Severini }
4369b3254dbSPaolo Severini 
4374bafceceSPaolo Severini void ObjectFileWasm::Dump(Stream *s) {
4384bafceceSPaolo Severini   ModuleSP module_sp(GetModule());
4394bafceceSPaolo Severini   if (!module_sp)
4404bafceceSPaolo Severini     return;
4414bafceceSPaolo Severini 
4424bafceceSPaolo Severini   std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
4434bafceceSPaolo Severini 
4444bafceceSPaolo Severini   llvm::raw_ostream &ostream = s->AsRawOstream();
4454bafceceSPaolo Severini   ostream << static_cast<void *>(this) << ": ";
4464bafceceSPaolo Severini   s->Indent();
4474bafceceSPaolo Severini   ostream << "ObjectFileWasm, file = '";
4484bafceceSPaolo Severini   m_file.Dump(ostream);
4494bafceceSPaolo Severini   ostream << "', arch = ";
4504bafceceSPaolo Severini   ostream << GetArchitecture().GetArchitectureName() << "\n";
4514bafceceSPaolo Severini 
4524bafceceSPaolo Severini   SectionList *sections = GetSectionList();
4534bafceceSPaolo Severini   if (sections) {
4543a168297SPavel Labath     sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
4553a168297SPavel Labath                    UINT32_MAX);
4564bafceceSPaolo Severini   }
4574bafceceSPaolo Severini   ostream << "\n";
4584bafceceSPaolo Severini   DumpSectionHeaders(ostream);
4594bafceceSPaolo Severini   ostream << "\n";
4604bafceceSPaolo Severini }
4614bafceceSPaolo Severini 
4624bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
4634bafceceSPaolo Severini                                        const section_info_t &sh) {
4644bafceceSPaolo Severini   ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
4654bafceceSPaolo Severini           << llvm::format_hex(sh.offset, 10) << " "
4664bafceceSPaolo Severini           << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
4674bafceceSPaolo Severini           << "\n";
4684bafceceSPaolo Severini }
4694bafceceSPaolo Severini 
4704bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
4714bafceceSPaolo Severini   ostream << "Section Headers\n";
4724bafceceSPaolo Severini   ostream << "IDX  name             addr       size       id\n";
4734bafceceSPaolo Severini   ostream << "==== ---------------- ---------- ---------- ------\n";
4744bafceceSPaolo Severini 
4754bafceceSPaolo Severini   uint32_t idx = 0;
4764bafceceSPaolo Severini   for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
4774bafceceSPaolo Severini        ++pos, ++idx) {
4784bafceceSPaolo Severini     ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
4794bafceceSPaolo Severini     ObjectFileWasm::DumpSectionHeader(ostream, *pos);
4804bafceceSPaolo Severini   }
4814bafceceSPaolo Severini }
482