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);
199*1d891d44SHeejin Ahn   } else if (section_id <= llvm::wasm::WASM_SEC_TAG) {
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 
2567ad54d19SPhilip Pfaffe static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
2577ad54d19SPhilip Pfaffe   if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
2587ad54d19SPhilip Pfaffe     return llvm::StringSwitch<SectionType>(Name)
2597ad54d19SPhilip Pfaffe         .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
2607ad54d19SPhilip Pfaffe         .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
2617ad54d19SPhilip Pfaffe         .Case("addr", eSectionTypeDWARFDebugAddr)
2627ad54d19SPhilip Pfaffe         .Case("aranges", eSectionTypeDWARFDebugAranges)
2637ad54d19SPhilip Pfaffe         .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
2647ad54d19SPhilip Pfaffe         .Case("frame", eSectionTypeDWARFDebugFrame)
2657ad54d19SPhilip Pfaffe         .Case("info", eSectionTypeDWARFDebugInfo)
2667ad54d19SPhilip Pfaffe         .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
2677ad54d19SPhilip Pfaffe         .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
2687ad54d19SPhilip Pfaffe         .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
2697ad54d19SPhilip Pfaffe         .Case("loc", eSectionTypeDWARFDebugLoc)
2707ad54d19SPhilip Pfaffe         .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
2717ad54d19SPhilip Pfaffe         .Case("loclists", eSectionTypeDWARFDebugLocLists)
2727ad54d19SPhilip Pfaffe         .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
2737ad54d19SPhilip Pfaffe         .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
2747ad54d19SPhilip Pfaffe         .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
2757ad54d19SPhilip Pfaffe         .Case("names", eSectionTypeDWARFDebugNames)
2767ad54d19SPhilip Pfaffe         .Case("pubnames", eSectionTypeDWARFDebugPubNames)
2777ad54d19SPhilip Pfaffe         .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
2787ad54d19SPhilip Pfaffe         .Case("ranges", eSectionTypeDWARFDebugRanges)
2797ad54d19SPhilip Pfaffe         .Case("rnglists", eSectionTypeDWARFDebugRngLists)
2807ad54d19SPhilip Pfaffe         .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
2817ad54d19SPhilip Pfaffe         .Case("str", eSectionTypeDWARFDebugStr)
2827ad54d19SPhilip Pfaffe         .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
2837ad54d19SPhilip Pfaffe         .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
2847ad54d19SPhilip Pfaffe         .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
2857ad54d19SPhilip Pfaffe         .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
2867ad54d19SPhilip Pfaffe         .Case("types", eSectionTypeDWARFDebugTypes)
2877ad54d19SPhilip Pfaffe         .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
2887ad54d19SPhilip Pfaffe         .Default(eSectionTypeOther);
2897ad54d19SPhilip Pfaffe   }
2907ad54d19SPhilip Pfaffe   return eSectionTypeOther;
2917ad54d19SPhilip Pfaffe }
2927ad54d19SPhilip 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 {
3207ad54d19SPhilip 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