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