xref: /llvm-project/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp (revision 984b800a036fc61ccb129a8da7592af9cadc94dd)
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"
18c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
194bafceceSPaolo Severini #include "lldb/Utility/Log.h"
204bafceceSPaolo Severini #include "llvm/ADT/ArrayRef.h"
214bafceceSPaolo Severini #include "llvm/ADT/SmallVector.h"
224bafceceSPaolo Severini #include "llvm/ADT/StringRef.h"
234bafceceSPaolo Severini #include "llvm/BinaryFormat/Magic.h"
244bafceceSPaolo Severini #include "llvm/BinaryFormat/Wasm.h"
254bafceceSPaolo Severini #include "llvm/Support/Endian.h"
264bafceceSPaolo Severini #include "llvm/Support/Format.h"
27f190ce62SKazu Hirata #include <optional>
284bafceceSPaolo Severini 
294bafceceSPaolo Severini using namespace lldb;
304bafceceSPaolo Severini using namespace lldb_private;
314bafceceSPaolo Severini using namespace lldb_private::wasm;
324bafceceSPaolo Severini 
33bba9ba8dSJonas Devlieghere LLDB_PLUGIN_DEFINE(ObjectFileWasm)
34fbb4d1e4SJonas Devlieghere 
354bafceceSPaolo Severini static const uint32_t kWasmHeaderSize =
364bafceceSPaolo Severini     sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
374bafceceSPaolo Severini 
384bafceceSPaolo Severini /// Checks whether the data buffer starts with a valid Wasm module header.
ValidateModuleHeader(const DataBufferSP & data_sp)394bafceceSPaolo Severini static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
404bafceceSPaolo Severini   if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
414bafceceSPaolo Severini     return false;
424bafceceSPaolo Severini 
434bafceceSPaolo Severini   if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
444bafceceSPaolo Severini       llvm::file_magic::wasm_object)
454bafceceSPaolo Severini     return false;
464bafceceSPaolo Severini 
47fc54427eSJonas Devlieghere   const uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
484bafceceSPaolo Severini 
494bafceceSPaolo Severini   uint32_t version = llvm::support::endian::read32le(Ptr);
504bafceceSPaolo Severini   return version == llvm::wasm::WasmVersion;
514bafceceSPaolo Severini }
524bafceceSPaolo Severini 
532fe83274SKazu Hirata static std::optional<ConstString>
GetWasmString(llvm::DataExtractor & data,llvm::DataExtractor::Cursor & c)544bafceceSPaolo Severini GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
554bafceceSPaolo Severini   // A Wasm string is encoded as a vector of UTF-8 codes.
564bafceceSPaolo Severini   // Vectors are encoded with their u32 length followed by the element
574bafceceSPaolo Severini   // sequence.
584bafceceSPaolo Severini   uint64_t len = data.getULEB128(c);
594bafceceSPaolo Severini   if (!c) {
604bafceceSPaolo Severini     consumeError(c.takeError());
61343523d0SKazu Hirata     return std::nullopt;
624bafceceSPaolo Severini   }
634bafceceSPaolo Severini 
644bafceceSPaolo Severini   if (len >= (uint64_t(1) << 32)) {
65343523d0SKazu Hirata     return std::nullopt;
664bafceceSPaolo Severini   }
674bafceceSPaolo Severini 
684bafceceSPaolo Severini   llvm::SmallVector<uint8_t, 32> str_storage;
694bafceceSPaolo Severini   data.getU8(c, str_storage, len);
704bafceceSPaolo Severini   if (!c) {
714bafceceSPaolo Severini     consumeError(c.takeError());
72343523d0SKazu Hirata     return std::nullopt;
734bafceceSPaolo Severini   }
744bafceceSPaolo Severini 
75*984b800aSserge-sans-paille   llvm::StringRef str = toStringRef(llvm::ArrayRef(str_storage));
764bafceceSPaolo Severini   return ConstString(str);
774bafceceSPaolo Severini }
784bafceceSPaolo Severini 
799b3254dbSPaolo Severini char ObjectFileWasm::ID;
809b3254dbSPaolo Severini 
Initialize()814bafceceSPaolo Severini void ObjectFileWasm::Initialize() {
824bafceceSPaolo Severini   PluginManager::RegisterPlugin(GetPluginNameStatic(),
834bafceceSPaolo Severini                                 GetPluginDescriptionStatic(), CreateInstance,
844bafceceSPaolo Severini                                 CreateMemoryInstance, GetModuleSpecifications);
854bafceceSPaolo Severini }
864bafceceSPaolo Severini 
Terminate()874bafceceSPaolo Severini void ObjectFileWasm::Terminate() {
884bafceceSPaolo Severini   PluginManager::UnregisterPlugin(CreateInstance);
894bafceceSPaolo Severini }
904bafceceSPaolo Severini 
914bafceceSPaolo Severini ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)92c69307e5SJonas Devlieghere ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP data_sp,
934bafceceSPaolo Severini                                offset_t data_offset, const FileSpec *file,
944bafceceSPaolo Severini                                offset_t file_offset, offset_t length) {
95a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Object);
964bafceceSPaolo Severini 
974bafceceSPaolo Severini   if (!data_sp) {
984bafceceSPaolo Severini     data_sp = MapFileData(*file, length, file_offset);
994bafceceSPaolo Severini     if (!data_sp) {
1004bafceceSPaolo Severini       LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
1014bafceceSPaolo Severini                 file->GetPath().c_str());
1024bafceceSPaolo Severini       return nullptr;
1034bafceceSPaolo Severini     }
1044bafceceSPaolo Severini     data_offset = 0;
1054bafceceSPaolo Severini   }
1064bafceceSPaolo Severini 
1074bafceceSPaolo Severini   assert(data_sp);
1084bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp)) {
1094bafceceSPaolo Severini     LLDB_LOGF(log,
1104bafceceSPaolo Severini               "Failed to create ObjectFileWasm instance: invalid Wasm header");
1114bafceceSPaolo Severini     return nullptr;
1124bafceceSPaolo Severini   }
1134bafceceSPaolo Severini 
1144bafceceSPaolo Severini   // Update the data to contain the entire file if it doesn't contain it
1154bafceceSPaolo Severini   // already.
1164bafceceSPaolo Severini   if (data_sp->GetByteSize() < length) {
1174bafceceSPaolo Severini     data_sp = MapFileData(*file, length, file_offset);
1184bafceceSPaolo Severini     if (!data_sp) {
1194bafceceSPaolo Severini       LLDB_LOGF(log,
1204bafceceSPaolo Severini                 "Failed to create ObjectFileWasm instance: cannot read file %s",
1214bafceceSPaolo Severini                 file->GetPath().c_str());
1224bafceceSPaolo Severini       return nullptr;
1234bafceceSPaolo Severini     }
1244bafceceSPaolo Severini     data_offset = 0;
1254bafceceSPaolo Severini   }
1264bafceceSPaolo Severini 
1274bafceceSPaolo Severini   std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
1284bafceceSPaolo Severini       module_sp, data_sp, data_offset, file, file_offset, length));
1294bafceceSPaolo Severini   ArchSpec spec = objfile_up->GetArchitecture();
1304bafceceSPaolo Severini   if (spec && objfile_up->SetModulesArchitecture(spec)) {
1314bafceceSPaolo Severini     LLDB_LOGF(log,
1324bafceceSPaolo Severini               "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
1334bafceceSPaolo Severini               static_cast<void *>(objfile_up.get()),
1344bafceceSPaolo Severini               static_cast<void *>(objfile_up->GetModule().get()),
1354bafceceSPaolo Severini               objfile_up->GetModule()->GetSpecificationDescription().c_str(),
1364bafceceSPaolo Severini               file ? file->GetPath().c_str() : "<NULL>");
1374bafceceSPaolo Severini     return objfile_up.release();
1384bafceceSPaolo Severini   }
1394bafceceSPaolo Severini 
1404bafceceSPaolo Severini   LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
1414bafceceSPaolo Severini   return nullptr;
1424bafceceSPaolo Severini }
1434bafceceSPaolo Severini 
CreateMemoryInstance(const ModuleSP & module_sp,WritableDataBufferSP data_sp,const ProcessSP & process_sp,addr_t header_addr)1444bafceceSPaolo Severini ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
145f2ea125eSJonas Devlieghere                                                  WritableDataBufferSP data_sp,
1464bafceceSPaolo Severini                                                  const ProcessSP &process_sp,
1474bafceceSPaolo Severini                                                  addr_t header_addr) {
1484bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp))
1494bafceceSPaolo Severini     return nullptr;
1504bafceceSPaolo Severini 
1514bafceceSPaolo Severini   std::unique_ptr<ObjectFileWasm> objfile_up(
1524bafceceSPaolo Severini       new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
1534bafceceSPaolo Severini   ArchSpec spec = objfile_up->GetArchitecture();
1544bafceceSPaolo Severini   if (spec && objfile_up->SetModulesArchitecture(spec))
1554bafceceSPaolo Severini     return objfile_up.release();
1564bafceceSPaolo Severini   return nullptr;
1574bafceceSPaolo Severini }
1584bafceceSPaolo Severini 
DecodeNextSection(lldb::offset_t * offset_ptr)1594bafceceSPaolo Severini bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
1604bafceceSPaolo Severini   // Buffer sufficient to read a section header and find the pointer to the next
1614bafceceSPaolo Severini   // section.
1624bafceceSPaolo Severini   const uint32_t kBufferSize = 1024;
1634bafceceSPaolo Severini   DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
1644bafceceSPaolo Severini 
1654bafceceSPaolo Severini   llvm::DataExtractor data = section_header_data.GetAsLLVM();
1664bafceceSPaolo Severini   llvm::DataExtractor::Cursor c(0);
1674bafceceSPaolo Severini 
1684bafceceSPaolo Severini   // Each section consists of:
1694bafceceSPaolo Severini   // - a one-byte section id,
1704bafceceSPaolo Severini   // - the u32 size of the contents, in bytes,
1714bafceceSPaolo Severini   // - the actual contents.
1724bafceceSPaolo Severini   uint8_t section_id = data.getU8(c);
1734bafceceSPaolo Severini   uint64_t payload_len = data.getULEB128(c);
1744bafceceSPaolo Severini   if (!c)
1754bafceceSPaolo Severini     return !llvm::errorToBool(c.takeError());
1764bafceceSPaolo Severini 
1774bafceceSPaolo Severini   if (payload_len >= (uint64_t(1) << 32))
1784bafceceSPaolo Severini     return false;
1794bafceceSPaolo Severini 
1804bafceceSPaolo Severini   if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
1819b3254dbSPaolo Severini     // Custom sections have the id 0. Their contents consist of a name
1829b3254dbSPaolo Severini     // identifying the custom section, followed by an uninterpreted sequence
1839b3254dbSPaolo Severini     // of bytes.
1844bafceceSPaolo Severini     lldb::offset_t prev_offset = c.tell();
1852fe83274SKazu Hirata     std::optional<ConstString> sect_name = GetWasmString(data, c);
1864bafceceSPaolo Severini     if (!sect_name)
1874bafceceSPaolo Severini       return false;
1884bafceceSPaolo Severini 
1894bafceceSPaolo Severini     if (payload_len < c.tell() - prev_offset)
1904bafceceSPaolo Severini       return false;
1914bafceceSPaolo Severini 
1924bafceceSPaolo Severini     uint32_t section_length = payload_len - (c.tell() - prev_offset);
1934bafceceSPaolo Severini     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
1944bafceceSPaolo Severini                                         section_id, *sect_name});
1954bafceceSPaolo Severini     *offset_ptr += (c.tell() + section_length);
1962ae385e5SDerek Schuff   } else if (section_id <= llvm::wasm::WASM_SEC_LAST_KNOWN) {
1974bafceceSPaolo Severini     m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
1984bafceceSPaolo Severini                                         static_cast<uint32_t>(payload_len),
1994bafceceSPaolo Severini                                         section_id, ConstString()});
2004bafceceSPaolo Severini     *offset_ptr += (c.tell() + payload_len);
2014bafceceSPaolo Severini   } else {
2024bafceceSPaolo Severini     // Invalid section id.
2034bafceceSPaolo Severini     return false;
2044bafceceSPaolo Severini   }
2054bafceceSPaolo Severini   return true;
2064bafceceSPaolo Severini }
2074bafceceSPaolo Severini 
DecodeSections()2084bafceceSPaolo Severini bool ObjectFileWasm::DecodeSections() {
2094bafceceSPaolo Severini   lldb::offset_t offset = kWasmHeaderSize;
2104bafceceSPaolo Severini   if (IsInMemory()) {
2114bafceceSPaolo Severini     offset += m_memory_addr;
2124bafceceSPaolo Severini   }
2134bafceceSPaolo Severini 
2144bafceceSPaolo Severini   while (DecodeNextSection(&offset))
2154bafceceSPaolo Severini     ;
2164bafceceSPaolo Severini   return true;
2174bafceceSPaolo Severini }
2184bafceceSPaolo Severini 
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)2194bafceceSPaolo Severini size_t ObjectFileWasm::GetModuleSpecifications(
2204bafceceSPaolo Severini     const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
2214bafceceSPaolo Severini     offset_t file_offset, offset_t length, ModuleSpecList &specs) {
2224bafceceSPaolo Severini   if (!ValidateModuleHeader(data_sp)) {
2234bafceceSPaolo Severini     return 0;
2244bafceceSPaolo Severini   }
2254bafceceSPaolo Severini 
2264bafceceSPaolo Severini   ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
2274bafceceSPaolo Severini   specs.Append(spec);
2284bafceceSPaolo Severini   return 1;
2294bafceceSPaolo Severini }
2304bafceceSPaolo Severini 
ObjectFileWasm(const ModuleSP & module_sp,DataBufferSP data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length)231f2ea125eSJonas Devlieghere ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP data_sp,
2324bafceceSPaolo Severini                                offset_t data_offset, const FileSpec *file,
2334bafceceSPaolo Severini                                offset_t offset, offset_t length)
2344bafceceSPaolo Severini     : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
235c1121908SPaolo Severini       m_arch("wasm32-unknown-unknown-wasm") {
2364bafceceSPaolo Severini   m_data.SetAddressByteSize(4);
2374bafceceSPaolo Severini }
2384bafceceSPaolo Severini 
ObjectFileWasm(const lldb::ModuleSP & module_sp,lldb::WritableDataBufferSP header_data_sp,const lldb::ProcessSP & process_sp,lldb::addr_t header_addr)2394bafceceSPaolo Severini ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
240f2ea125eSJonas Devlieghere                                lldb::WritableDataBufferSP header_data_sp,
2414bafceceSPaolo Severini                                const lldb::ProcessSP &process_sp,
2424bafceceSPaolo Severini                                lldb::addr_t header_addr)
2434bafceceSPaolo Severini     : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
244c1121908SPaolo Severini       m_arch("wasm32-unknown-unknown-wasm") {}
2454bafceceSPaolo Severini 
ParseHeader()2464bafceceSPaolo Severini bool ObjectFileWasm::ParseHeader() {
2474bafceceSPaolo Severini   // We already parsed the header during initialization.
2484bafceceSPaolo Severini   return true;
2494bafceceSPaolo Severini }
2504bafceceSPaolo Severini 
ParseSymtab(Symtab & symtab)2517e6df41fSGreg Clayton void ObjectFileWasm::ParseSymtab(Symtab &symtab) {}
2524bafceceSPaolo Severini 
GetSectionTypeFromName(llvm::StringRef Name)2537ad54d19SPhilip Pfaffe static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
2547ad54d19SPhilip Pfaffe   if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
2557ad54d19SPhilip Pfaffe     return llvm::StringSwitch<SectionType>(Name)
2567ad54d19SPhilip Pfaffe         .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
2577ad54d19SPhilip Pfaffe         .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
2587ad54d19SPhilip Pfaffe         .Case("addr", eSectionTypeDWARFDebugAddr)
2597ad54d19SPhilip Pfaffe         .Case("aranges", eSectionTypeDWARFDebugAranges)
2607ad54d19SPhilip Pfaffe         .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
2617ad54d19SPhilip Pfaffe         .Case("frame", eSectionTypeDWARFDebugFrame)
2627ad54d19SPhilip Pfaffe         .Case("info", eSectionTypeDWARFDebugInfo)
2637ad54d19SPhilip Pfaffe         .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
2647ad54d19SPhilip Pfaffe         .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
2657ad54d19SPhilip Pfaffe         .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
2667ad54d19SPhilip Pfaffe         .Case("loc", eSectionTypeDWARFDebugLoc)
2677ad54d19SPhilip Pfaffe         .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
2687ad54d19SPhilip Pfaffe         .Case("loclists", eSectionTypeDWARFDebugLocLists)
2697ad54d19SPhilip Pfaffe         .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
2707ad54d19SPhilip Pfaffe         .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
2717ad54d19SPhilip Pfaffe         .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
2727ad54d19SPhilip Pfaffe         .Case("names", eSectionTypeDWARFDebugNames)
2737ad54d19SPhilip Pfaffe         .Case("pubnames", eSectionTypeDWARFDebugPubNames)
2747ad54d19SPhilip Pfaffe         .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
2757ad54d19SPhilip Pfaffe         .Case("ranges", eSectionTypeDWARFDebugRanges)
2767ad54d19SPhilip Pfaffe         .Case("rnglists", eSectionTypeDWARFDebugRngLists)
2777ad54d19SPhilip Pfaffe         .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
2787ad54d19SPhilip Pfaffe         .Case("str", eSectionTypeDWARFDebugStr)
2797ad54d19SPhilip Pfaffe         .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
2807ad54d19SPhilip Pfaffe         .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
2817ad54d19SPhilip Pfaffe         .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
2827ad54d19SPhilip Pfaffe         .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
2837ad54d19SPhilip Pfaffe         .Case("types", eSectionTypeDWARFDebugTypes)
2847ad54d19SPhilip Pfaffe         .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
2857ad54d19SPhilip Pfaffe         .Default(eSectionTypeOther);
2867ad54d19SPhilip Pfaffe   }
2877ad54d19SPhilip Pfaffe   return eSectionTypeOther;
2887ad54d19SPhilip Pfaffe }
2897ad54d19SPhilip Pfaffe 
CreateSections(SectionList & unified_section_list)2904bafceceSPaolo Severini void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
2914bafceceSPaolo Severini   if (m_sections_up)
2924bafceceSPaolo Severini     return;
2934bafceceSPaolo Severini 
2944bafceceSPaolo Severini   m_sections_up = std::make_unique<SectionList>();
2954bafceceSPaolo Severini 
2964bafceceSPaolo Severini   if (m_sect_infos.empty()) {
2974bafceceSPaolo Severini     DecodeSections();
2984bafceceSPaolo Severini   }
2994bafceceSPaolo Severini 
3004bafceceSPaolo Severini   for (const section_info &sect_info : m_sect_infos) {
3014bafceceSPaolo Severini     SectionType section_type = eSectionTypeOther;
3024bafceceSPaolo Severini     ConstString section_name;
303c1121908SPaolo Severini     offset_t file_offset = sect_info.offset & 0xffffffff;
304c1121908SPaolo Severini     addr_t vm_addr = file_offset;
305c1121908SPaolo Severini     size_t vm_size = sect_info.size;
3064bafceceSPaolo Severini 
3074bafceceSPaolo Severini     if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
3084bafceceSPaolo Severini       section_type = eSectionTypeCode;
3094bafceceSPaolo Severini       section_name = ConstString("code");
310c1121908SPaolo Severini 
311c1121908SPaolo Severini       // A code address in DWARF for WebAssembly is the offset of an
312c1121908SPaolo Severini       // instruction relative within the Code section of the WebAssembly file.
313c1121908SPaolo Severini       // For this reason Section::GetFileAddress() must return zero for the
314c1121908SPaolo Severini       // Code section.
315c1121908SPaolo Severini       vm_addr = 0;
3164bafceceSPaolo Severini     } else {
3177ad54d19SPhilip Pfaffe       section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
3184bafceceSPaolo Severini       if (section_type == eSectionTypeOther)
3194bafceceSPaolo Severini         continue;
3204bafceceSPaolo Severini       section_name = sect_info.name;
321c1121908SPaolo Severini       if (!IsInMemory()) {
322c1121908SPaolo Severini         vm_size = 0;
323c1121908SPaolo Severini         vm_addr = 0;
3244bafceceSPaolo Severini       }
3254bafceceSPaolo Severini     }
3264bafceceSPaolo Severini 
3274bafceceSPaolo Severini     SectionSP section_sp(
3284bafceceSPaolo Severini         new Section(GetModule(), // Module to which this section belongs.
3294bafceceSPaolo Severini                     this,        // ObjectFile to which this section belongs and
3304bafceceSPaolo Severini                                  // should read section data from.
3314bafceceSPaolo Severini                     section_type,   // Section ID.
3324bafceceSPaolo Severini                     section_name,   // Section name.
3334bafceceSPaolo Severini                     section_type,   // Section type.
3344bafceceSPaolo Severini                     vm_addr,        // VM address.
3354bafceceSPaolo Severini                     vm_size,        // VM size in bytes of this section.
3364bafceceSPaolo Severini                     file_offset,    // Offset of this section in the file.
3374bafceceSPaolo Severini                     sect_info.size, // Size of the section as found in the file.
3384bafceceSPaolo Severini                     0,              // Alignment of the section
3394bafceceSPaolo Severini                     0,              // Flags for this section.
3404bafceceSPaolo Severini                     1));            // Number of host bytes per target byte
3414bafceceSPaolo Severini     m_sections_up->AddSection(section_sp);
3424bafceceSPaolo Severini     unified_section_list.AddSection(section_sp);
3434bafceceSPaolo Severini   }
3444bafceceSPaolo Severini }
3454bafceceSPaolo Severini 
SetLoadAddress(Target & target,lldb::addr_t load_address,bool value_is_offset)3464bafceceSPaolo Severini bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
3474bafceceSPaolo Severini                                     bool value_is_offset) {
3484bafceceSPaolo Severini   /// In WebAssembly, linear memory is disjointed from code space. The VM can
3494bafceceSPaolo Severini   /// load multiple instances of a module, which logically share the same code.
3504bafceceSPaolo Severini   /// We represent a wasm32 code address with 64-bits, like:
3514bafceceSPaolo Severini   /// 63            32 31             0
3524bafceceSPaolo Severini   /// +---------------+---------------+
3534bafceceSPaolo Severini   /// +   module_id   |     offset    |
3544bafceceSPaolo Severini   /// +---------------+---------------+
3554bafceceSPaolo Severini   /// where the lower 32 bits represent a module offset (relative to the module
3564bafceceSPaolo Severini   /// start not to the beginning of the code section) and the higher 32 bits
3574bafceceSPaolo Severini   /// uniquely identify the module in the WebAssembly VM.
3584bafceceSPaolo Severini   /// In other words, we assume that each WebAssembly module is loaded by the
3594bafceceSPaolo Severini   /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
3604bafceceSPaolo Severini   /// 0x0000000400000000 for module_id == 4.
3614bafceceSPaolo Severini   /// These 64-bit addresses will be used to request code ranges for a specific
3624bafceceSPaolo Severini   /// module from the WebAssembly engine.
363c1121908SPaolo Severini 
364c1121908SPaolo Severini   assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
365c1121908SPaolo Severini          m_memory_addr == load_address);
366c1121908SPaolo Severini 
3674bafceceSPaolo Severini   ModuleSP module_sp = GetModule();
3684bafceceSPaolo Severini   if (!module_sp)
3694bafceceSPaolo Severini     return false;
3704bafceceSPaolo Severini 
3714bafceceSPaolo Severini   DecodeSections();
3724bafceceSPaolo Severini 
3734bafceceSPaolo Severini   size_t num_loaded_sections = 0;
3744bafceceSPaolo Severini   SectionList *section_list = GetSectionList();
3754bafceceSPaolo Severini   if (!section_list)
3764bafceceSPaolo Severini     return false;
3774bafceceSPaolo Severini 
3784bafceceSPaolo Severini   const size_t num_sections = section_list->GetSize();
379c1121908SPaolo Severini   for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
3804bafceceSPaolo Severini     SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
381c1121908SPaolo Severini     if (target.SetSectionLoadAddress(
382c1121908SPaolo Severini             section_sp, load_address | section_sp->GetFileOffset())) {
3834bafceceSPaolo Severini       ++num_loaded_sections;
3844bafceceSPaolo Severini     }
3854bafceceSPaolo Severini   }
3864bafceceSPaolo Severini 
3874bafceceSPaolo Severini   return num_loaded_sections > 0;
3884bafceceSPaolo Severini }
3894bafceceSPaolo Severini 
ReadImageData(offset_t offset,uint32_t size)390c1121908SPaolo Severini DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
3914bafceceSPaolo Severini   DataExtractor data;
3924bafceceSPaolo Severini   if (m_file) {
3934bafceceSPaolo Severini     if (offset < GetByteSize()) {
394c1121908SPaolo Severini       size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
3954bafceceSPaolo Severini       auto buffer_sp = MapFileData(m_file, size, offset);
3964bafceceSPaolo Severini       return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
3974bafceceSPaolo Severini     }
3984bafceceSPaolo Severini   } else {
3994bafceceSPaolo Severini     ProcessSP process_sp(m_process_wp.lock());
4004bafceceSPaolo Severini     if (process_sp) {
4014bafceceSPaolo Severini       auto data_up = std::make_unique<DataBufferHeap>(size, 0);
4024bafceceSPaolo Severini       Status readmem_error;
4034bafceceSPaolo Severini       size_t bytes_read = process_sp->ReadMemory(
4044bafceceSPaolo Severini           offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
4054bafceceSPaolo Severini       if (bytes_read > 0) {
4064bafceceSPaolo Severini         DataBufferSP buffer_sp(data_up.release());
4074bafceceSPaolo Severini         data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
4084bafceceSPaolo Severini       }
4094bafceceSPaolo Severini     }
4104bafceceSPaolo Severini   }
4114bafceceSPaolo Severini 
4124bafceceSPaolo Severini   data.SetByteOrder(GetByteOrder());
4134bafceceSPaolo Severini   return data;
4144bafceceSPaolo Severini }
4154bafceceSPaolo Severini 
GetExternalDebugInfoFileSpec()4162fe83274SKazu Hirata std::optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
4179b3254dbSPaolo Severini   static ConstString g_sect_name_external_debug_info("external_debug_info");
4189b3254dbSPaolo Severini 
4199b3254dbSPaolo Severini   for (const section_info &sect_info : m_sect_infos) {
4209b3254dbSPaolo Severini     if (g_sect_name_external_debug_info == sect_info.name) {
4219b3254dbSPaolo Severini       const uint32_t kBufferSize = 1024;
4229b3254dbSPaolo Severini       DataExtractor section_header_data =
4239b3254dbSPaolo Severini           ReadImageData(sect_info.offset, kBufferSize);
4249b3254dbSPaolo Severini       llvm::DataExtractor data = section_header_data.GetAsLLVM();
4259b3254dbSPaolo Severini       llvm::DataExtractor::Cursor c(0);
4262fe83274SKazu Hirata       std::optional<ConstString> symbols_url = GetWasmString(data, c);
4279b3254dbSPaolo Severini       if (symbols_url)
4289b3254dbSPaolo Severini         return FileSpec(symbols_url->GetStringRef());
4299b3254dbSPaolo Severini     }
4309b3254dbSPaolo Severini   }
431343523d0SKazu Hirata   return std::nullopt;
4329b3254dbSPaolo Severini }
4339b3254dbSPaolo Severini 
Dump(Stream * s)4344bafceceSPaolo Severini void ObjectFileWasm::Dump(Stream *s) {
4354bafceceSPaolo Severini   ModuleSP module_sp(GetModule());
4364bafceceSPaolo Severini   if (!module_sp)
4374bafceceSPaolo Severini     return;
4384bafceceSPaolo Severini 
4394bafceceSPaolo Severini   std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
4404bafceceSPaolo Severini 
4414bafceceSPaolo Severini   llvm::raw_ostream &ostream = s->AsRawOstream();
4424bafceceSPaolo Severini   ostream << static_cast<void *>(this) << ": ";
4434bafceceSPaolo Severini   s->Indent();
4444bafceceSPaolo Severini   ostream << "ObjectFileWasm, file = '";
4454bafceceSPaolo Severini   m_file.Dump(ostream);
4464bafceceSPaolo Severini   ostream << "', arch = ";
4474bafceceSPaolo Severini   ostream << GetArchitecture().GetArchitectureName() << "\n";
4484bafceceSPaolo Severini 
4494bafceceSPaolo Severini   SectionList *sections = GetSectionList();
4504bafceceSPaolo Severini   if (sections) {
4513a168297SPavel Labath     sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
4523a168297SPavel Labath                    UINT32_MAX);
4534bafceceSPaolo Severini   }
4544bafceceSPaolo Severini   ostream << "\n";
4554bafceceSPaolo Severini   DumpSectionHeaders(ostream);
4564bafceceSPaolo Severini   ostream << "\n";
4574bafceceSPaolo Severini }
4584bafceceSPaolo Severini 
DumpSectionHeader(llvm::raw_ostream & ostream,const section_info_t & sh)4594bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
4604bafceceSPaolo Severini                                        const section_info_t &sh) {
4614bafceceSPaolo Severini   ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
4624bafceceSPaolo Severini           << llvm::format_hex(sh.offset, 10) << " "
4634bafceceSPaolo Severini           << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
4644bafceceSPaolo Severini           << "\n";
4654bafceceSPaolo Severini }
4664bafceceSPaolo Severini 
DumpSectionHeaders(llvm::raw_ostream & ostream)4674bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
4684bafceceSPaolo Severini   ostream << "Section Headers\n";
4694bafceceSPaolo Severini   ostream << "IDX  name             addr       size       id\n";
4704bafceceSPaolo Severini   ostream << "==== ---------------- ---------- ---------- ------\n";
4714bafceceSPaolo Severini 
4724bafceceSPaolo Severini   uint32_t idx = 0;
4734bafceceSPaolo Severini   for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
4744bafceceSPaolo Severini        ++pos, ++idx) {
4754bafceceSPaolo Severini     ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
4764bafceceSPaolo Severini     ObjectFileWasm::DumpSectionHeader(ostream, *pos);
4774bafceceSPaolo Severini   }
4784bafceceSPaolo Severini }
479