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