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 ObjectFile * 904bafceceSPaolo Severini ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, 914bafceceSPaolo Severini offset_t data_offset, const FileSpec *file, 924bafceceSPaolo Severini offset_t file_offset, offset_t length) { 934bafceceSPaolo Severini Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); 944bafceceSPaolo Severini 954bafceceSPaolo Severini if (!data_sp) { 964bafceceSPaolo Severini data_sp = MapFileData(*file, length, file_offset); 974bafceceSPaolo Severini if (!data_sp) { 984bafceceSPaolo Severini LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s", 994bafceceSPaolo Severini file->GetPath().c_str()); 1004bafceceSPaolo Severini return nullptr; 1014bafceceSPaolo Severini } 1024bafceceSPaolo Severini data_offset = 0; 1034bafceceSPaolo Severini } 1044bafceceSPaolo Severini 1054bafceceSPaolo Severini assert(data_sp); 1064bafceceSPaolo Severini if (!ValidateModuleHeader(data_sp)) { 1074bafceceSPaolo Severini LLDB_LOGF(log, 1084bafceceSPaolo Severini "Failed to create ObjectFileWasm instance: invalid Wasm header"); 1094bafceceSPaolo Severini return nullptr; 1104bafceceSPaolo Severini } 1114bafceceSPaolo Severini 1124bafceceSPaolo Severini // Update the data to contain the entire file if it doesn't contain it 1134bafceceSPaolo Severini // already. 1144bafceceSPaolo Severini if (data_sp->GetByteSize() < length) { 1154bafceceSPaolo Severini data_sp = MapFileData(*file, length, file_offset); 1164bafceceSPaolo Severini if (!data_sp) { 1174bafceceSPaolo Severini LLDB_LOGF(log, 1184bafceceSPaolo Severini "Failed to create ObjectFileWasm instance: cannot read file %s", 1194bafceceSPaolo Severini file->GetPath().c_str()); 1204bafceceSPaolo Severini return nullptr; 1214bafceceSPaolo Severini } 1224bafceceSPaolo Severini data_offset = 0; 1234bafceceSPaolo Severini } 1244bafceceSPaolo Severini 1254bafceceSPaolo Severini std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm( 1264bafceceSPaolo Severini module_sp, data_sp, data_offset, file, file_offset, length)); 1274bafceceSPaolo Severini ArchSpec spec = objfile_up->GetArchitecture(); 1284bafceceSPaolo Severini if (spec && objfile_up->SetModulesArchitecture(spec)) { 1294bafceceSPaolo Severini LLDB_LOGF(log, 1304bafceceSPaolo Severini "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s", 1314bafceceSPaolo Severini static_cast<void *>(objfile_up.get()), 1324bafceceSPaolo Severini static_cast<void *>(objfile_up->GetModule().get()), 1334bafceceSPaolo Severini objfile_up->GetModule()->GetSpecificationDescription().c_str(), 1344bafceceSPaolo Severini file ? file->GetPath().c_str() : "<NULL>"); 1354bafceceSPaolo Severini return objfile_up.release(); 1364bafceceSPaolo Severini } 1374bafceceSPaolo Severini 1384bafceceSPaolo Severini LLDB_LOGF(log, "Failed to create ObjectFileWasm instance"); 1394bafceceSPaolo Severini return nullptr; 1404bafceceSPaolo Severini } 1414bafceceSPaolo Severini 1424bafceceSPaolo Severini ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp, 1434bafceceSPaolo Severini DataBufferSP &data_sp, 1444bafceceSPaolo Severini const ProcessSP &process_sp, 1454bafceceSPaolo Severini addr_t header_addr) { 1464bafceceSPaolo Severini if (!ValidateModuleHeader(data_sp)) 1474bafceceSPaolo Severini return nullptr; 1484bafceceSPaolo Severini 1494bafceceSPaolo Severini std::unique_ptr<ObjectFileWasm> objfile_up( 1504bafceceSPaolo Severini new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr)); 1514bafceceSPaolo Severini ArchSpec spec = objfile_up->GetArchitecture(); 1524bafceceSPaolo Severini if (spec && objfile_up->SetModulesArchitecture(spec)) 1534bafceceSPaolo Severini return objfile_up.release(); 1544bafceceSPaolo Severini return nullptr; 1554bafceceSPaolo Severini } 1564bafceceSPaolo Severini 1574bafceceSPaolo Severini bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) { 1584bafceceSPaolo Severini // Buffer sufficient to read a section header and find the pointer to the next 1594bafceceSPaolo Severini // section. 1604bafceceSPaolo Severini const uint32_t kBufferSize = 1024; 1614bafceceSPaolo Severini DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize); 1624bafceceSPaolo Severini 1634bafceceSPaolo Severini llvm::DataExtractor data = section_header_data.GetAsLLVM(); 1644bafceceSPaolo Severini llvm::DataExtractor::Cursor c(0); 1654bafceceSPaolo Severini 1664bafceceSPaolo Severini // Each section consists of: 1674bafceceSPaolo Severini // - a one-byte section id, 1684bafceceSPaolo Severini // - the u32 size of the contents, in bytes, 1694bafceceSPaolo Severini // - the actual contents. 1704bafceceSPaolo Severini uint8_t section_id = data.getU8(c); 1714bafceceSPaolo Severini uint64_t payload_len = data.getULEB128(c); 1724bafceceSPaolo Severini if (!c) 1734bafceceSPaolo Severini return !llvm::errorToBool(c.takeError()); 1744bafceceSPaolo Severini 1754bafceceSPaolo Severini if (payload_len >= (uint64_t(1) << 32)) 1764bafceceSPaolo Severini return false; 1774bafceceSPaolo Severini 1784bafceceSPaolo Severini if (section_id == llvm::wasm::WASM_SEC_CUSTOM) { 1799b3254dbSPaolo Severini // Custom sections have the id 0. Their contents consist of a name 1809b3254dbSPaolo Severini // identifying the custom section, followed by an uninterpreted sequence 1819b3254dbSPaolo Severini // of bytes. 1824bafceceSPaolo Severini lldb::offset_t prev_offset = c.tell(); 1834bafceceSPaolo Severini llvm::Optional<ConstString> sect_name = GetWasmString(data, c); 1844bafceceSPaolo Severini if (!sect_name) 1854bafceceSPaolo Severini return false; 1864bafceceSPaolo Severini 1874bafceceSPaolo Severini if (payload_len < c.tell() - prev_offset) 1884bafceceSPaolo Severini return false; 1894bafceceSPaolo Severini 1904bafceceSPaolo Severini uint32_t section_length = payload_len - (c.tell() - prev_offset); 1914bafceceSPaolo Severini m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length, 1924bafceceSPaolo Severini section_id, *sect_name}); 1934bafceceSPaolo Severini *offset_ptr += (c.tell() + section_length); 1941d891d44SHeejin Ahn } else if (section_id <= llvm::wasm::WASM_SEC_TAG) { 1954bafceceSPaolo Severini m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), 1964bafceceSPaolo Severini static_cast<uint32_t>(payload_len), 1974bafceceSPaolo Severini section_id, ConstString()}); 1984bafceceSPaolo Severini *offset_ptr += (c.tell() + payload_len); 1994bafceceSPaolo Severini } else { 2004bafceceSPaolo Severini // Invalid section id. 2014bafceceSPaolo Severini return false; 2024bafceceSPaolo Severini } 2034bafceceSPaolo Severini return true; 2044bafceceSPaolo Severini } 2054bafceceSPaolo Severini 2064bafceceSPaolo Severini bool ObjectFileWasm::DecodeSections() { 2074bafceceSPaolo Severini lldb::offset_t offset = kWasmHeaderSize; 2084bafceceSPaolo Severini if (IsInMemory()) { 2094bafceceSPaolo Severini offset += m_memory_addr; 2104bafceceSPaolo Severini } 2114bafceceSPaolo Severini 2124bafceceSPaolo Severini while (DecodeNextSection(&offset)) 2134bafceceSPaolo Severini ; 2144bafceceSPaolo Severini return true; 2154bafceceSPaolo Severini } 2164bafceceSPaolo Severini 2174bafceceSPaolo Severini size_t ObjectFileWasm::GetModuleSpecifications( 2184bafceceSPaolo Severini const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 2194bafceceSPaolo Severini offset_t file_offset, offset_t length, ModuleSpecList &specs) { 2204bafceceSPaolo Severini if (!ValidateModuleHeader(data_sp)) { 2214bafceceSPaolo Severini return 0; 2224bafceceSPaolo Severini } 2234bafceceSPaolo Severini 2244bafceceSPaolo Severini ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm")); 2254bafceceSPaolo Severini specs.Append(spec); 2264bafceceSPaolo Severini return 1; 2274bafceceSPaolo Severini } 2284bafceceSPaolo Severini 2294bafceceSPaolo Severini ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp, 2304bafceceSPaolo Severini offset_t data_offset, const FileSpec *file, 2314bafceceSPaolo Severini offset_t offset, offset_t length) 2324bafceceSPaolo Severini : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 233c1121908SPaolo Severini m_arch("wasm32-unknown-unknown-wasm") { 2344bafceceSPaolo Severini m_data.SetAddressByteSize(4); 2354bafceceSPaolo Severini } 2364bafceceSPaolo Severini 2374bafceceSPaolo Severini ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp, 2384bafceceSPaolo Severini lldb::DataBufferSP &header_data_sp, 2394bafceceSPaolo Severini const lldb::ProcessSP &process_sp, 2404bafceceSPaolo Severini lldb::addr_t header_addr) 2414bafceceSPaolo Severini : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), 242c1121908SPaolo Severini m_arch("wasm32-unknown-unknown-wasm") {} 2434bafceceSPaolo Severini 2444bafceceSPaolo Severini bool ObjectFileWasm::ParseHeader() { 2454bafceceSPaolo Severini // We already parsed the header during initialization. 2464bafceceSPaolo Severini return true; 2474bafceceSPaolo Severini } 2484bafceceSPaolo Severini 249*7e6df41fSGreg Clayton void ObjectFileWasm::ParseSymtab(Symtab &symtab) {} 2504bafceceSPaolo Severini 2517ad54d19SPhilip Pfaffe static SectionType GetSectionTypeFromName(llvm::StringRef Name) { 2527ad54d19SPhilip Pfaffe if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) { 2537ad54d19SPhilip Pfaffe return llvm::StringSwitch<SectionType>(Name) 2547ad54d19SPhilip Pfaffe .Case("abbrev", eSectionTypeDWARFDebugAbbrev) 2557ad54d19SPhilip Pfaffe .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) 2567ad54d19SPhilip Pfaffe .Case("addr", eSectionTypeDWARFDebugAddr) 2577ad54d19SPhilip Pfaffe .Case("aranges", eSectionTypeDWARFDebugAranges) 2587ad54d19SPhilip Pfaffe .Case("cu_index", eSectionTypeDWARFDebugCuIndex) 2597ad54d19SPhilip Pfaffe .Case("frame", eSectionTypeDWARFDebugFrame) 2607ad54d19SPhilip Pfaffe .Case("info", eSectionTypeDWARFDebugInfo) 2617ad54d19SPhilip Pfaffe .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo) 2627ad54d19SPhilip Pfaffe .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine) 2637ad54d19SPhilip Pfaffe .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr) 2647ad54d19SPhilip Pfaffe .Case("loc", eSectionTypeDWARFDebugLoc) 2657ad54d19SPhilip Pfaffe .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo) 2667ad54d19SPhilip Pfaffe .Case("loclists", eSectionTypeDWARFDebugLocLists) 2677ad54d19SPhilip Pfaffe .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo) 2687ad54d19SPhilip Pfaffe .Case("macinfo", eSectionTypeDWARFDebugMacInfo) 2697ad54d19SPhilip Pfaffe .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro) 2707ad54d19SPhilip Pfaffe .Case("names", eSectionTypeDWARFDebugNames) 2717ad54d19SPhilip Pfaffe .Case("pubnames", eSectionTypeDWARFDebugPubNames) 2727ad54d19SPhilip Pfaffe .Case("pubtypes", eSectionTypeDWARFDebugPubTypes) 2737ad54d19SPhilip Pfaffe .Case("ranges", eSectionTypeDWARFDebugRanges) 2747ad54d19SPhilip Pfaffe .Case("rnglists", eSectionTypeDWARFDebugRngLists) 2757ad54d19SPhilip Pfaffe .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo) 2767ad54d19SPhilip Pfaffe .Case("str", eSectionTypeDWARFDebugStr) 2777ad54d19SPhilip Pfaffe .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) 2787ad54d19SPhilip Pfaffe .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) 2797ad54d19SPhilip Pfaffe .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) 2807ad54d19SPhilip Pfaffe .Case("tu_index", eSectionTypeDWARFDebugTuIndex) 2817ad54d19SPhilip Pfaffe .Case("types", eSectionTypeDWARFDebugTypes) 2827ad54d19SPhilip Pfaffe .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) 2837ad54d19SPhilip Pfaffe .Default(eSectionTypeOther); 2847ad54d19SPhilip Pfaffe } 2857ad54d19SPhilip Pfaffe return eSectionTypeOther; 2867ad54d19SPhilip Pfaffe } 2877ad54d19SPhilip Pfaffe 2884bafceceSPaolo Severini void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { 2894bafceceSPaolo Severini if (m_sections_up) 2904bafceceSPaolo Severini return; 2914bafceceSPaolo Severini 2924bafceceSPaolo Severini m_sections_up = std::make_unique<SectionList>(); 2934bafceceSPaolo Severini 2944bafceceSPaolo Severini if (m_sect_infos.empty()) { 2954bafceceSPaolo Severini DecodeSections(); 2964bafceceSPaolo Severini } 2974bafceceSPaolo Severini 2984bafceceSPaolo Severini for (const section_info §_info : m_sect_infos) { 2994bafceceSPaolo Severini SectionType section_type = eSectionTypeOther; 3004bafceceSPaolo Severini ConstString section_name; 301c1121908SPaolo Severini offset_t file_offset = sect_info.offset & 0xffffffff; 302c1121908SPaolo Severini addr_t vm_addr = file_offset; 303c1121908SPaolo Severini size_t vm_size = sect_info.size; 3044bafceceSPaolo Severini 3054bafceceSPaolo Severini if (llvm::wasm::WASM_SEC_CODE == sect_info.id) { 3064bafceceSPaolo Severini section_type = eSectionTypeCode; 3074bafceceSPaolo Severini section_name = ConstString("code"); 308c1121908SPaolo Severini 309c1121908SPaolo Severini // A code address in DWARF for WebAssembly is the offset of an 310c1121908SPaolo Severini // instruction relative within the Code section of the WebAssembly file. 311c1121908SPaolo Severini // For this reason Section::GetFileAddress() must return zero for the 312c1121908SPaolo Severini // Code section. 313c1121908SPaolo Severini vm_addr = 0; 3144bafceceSPaolo Severini } else { 3157ad54d19SPhilip Pfaffe section_type = GetSectionTypeFromName(sect_info.name.GetStringRef()); 3164bafceceSPaolo Severini if (section_type == eSectionTypeOther) 3174bafceceSPaolo Severini continue; 3184bafceceSPaolo Severini section_name = sect_info.name; 319c1121908SPaolo Severini if (!IsInMemory()) { 320c1121908SPaolo Severini vm_size = 0; 321c1121908SPaolo Severini vm_addr = 0; 3224bafceceSPaolo Severini } 3234bafceceSPaolo Severini } 3244bafceceSPaolo Severini 3254bafceceSPaolo Severini SectionSP section_sp( 3264bafceceSPaolo Severini new Section(GetModule(), // Module to which this section belongs. 3274bafceceSPaolo Severini this, // ObjectFile to which this section belongs and 3284bafceceSPaolo Severini // should read section data from. 3294bafceceSPaolo Severini section_type, // Section ID. 3304bafceceSPaolo Severini section_name, // Section name. 3314bafceceSPaolo Severini section_type, // Section type. 3324bafceceSPaolo Severini vm_addr, // VM address. 3334bafceceSPaolo Severini vm_size, // VM size in bytes of this section. 3344bafceceSPaolo Severini file_offset, // Offset of this section in the file. 3354bafceceSPaolo Severini sect_info.size, // Size of the section as found in the file. 3364bafceceSPaolo Severini 0, // Alignment of the section 3374bafceceSPaolo Severini 0, // Flags for this section. 3384bafceceSPaolo Severini 1)); // Number of host bytes per target byte 3394bafceceSPaolo Severini m_sections_up->AddSection(section_sp); 3404bafceceSPaolo Severini unified_section_list.AddSection(section_sp); 3414bafceceSPaolo Severini } 3424bafceceSPaolo Severini } 3434bafceceSPaolo Severini 3444bafceceSPaolo Severini bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address, 3454bafceceSPaolo Severini bool value_is_offset) { 3464bafceceSPaolo Severini /// In WebAssembly, linear memory is disjointed from code space. The VM can 3474bafceceSPaolo Severini /// load multiple instances of a module, which logically share the same code. 3484bafceceSPaolo Severini /// We represent a wasm32 code address with 64-bits, like: 3494bafceceSPaolo Severini /// 63 32 31 0 3504bafceceSPaolo Severini /// +---------------+---------------+ 3514bafceceSPaolo Severini /// + module_id | offset | 3524bafceceSPaolo Severini /// +---------------+---------------+ 3534bafceceSPaolo Severini /// where the lower 32 bits represent a module offset (relative to the module 3544bafceceSPaolo Severini /// start not to the beginning of the code section) and the higher 32 bits 3554bafceceSPaolo Severini /// uniquely identify the module in the WebAssembly VM. 3564bafceceSPaolo Severini /// In other words, we assume that each WebAssembly module is loaded by the 3574bafceceSPaolo Severini /// engine at a 64-bit address that starts at the boundary of 4GB pages, like 3584bafceceSPaolo Severini /// 0x0000000400000000 for module_id == 4. 3594bafceceSPaolo Severini /// These 64-bit addresses will be used to request code ranges for a specific 3604bafceceSPaolo Severini /// module from the WebAssembly engine. 361c1121908SPaolo Severini 362c1121908SPaolo Severini assert(m_memory_addr == LLDB_INVALID_ADDRESS || 363c1121908SPaolo Severini m_memory_addr == load_address); 364c1121908SPaolo Severini 3654bafceceSPaolo Severini ModuleSP module_sp = GetModule(); 3664bafceceSPaolo Severini if (!module_sp) 3674bafceceSPaolo Severini return false; 3684bafceceSPaolo Severini 3694bafceceSPaolo Severini DecodeSections(); 3704bafceceSPaolo Severini 3714bafceceSPaolo Severini size_t num_loaded_sections = 0; 3724bafceceSPaolo Severini SectionList *section_list = GetSectionList(); 3734bafceceSPaolo Severini if (!section_list) 3744bafceceSPaolo Severini return false; 3754bafceceSPaolo Severini 3764bafceceSPaolo Severini const size_t num_sections = section_list->GetSize(); 377c1121908SPaolo Severini for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { 3784bafceceSPaolo Severini SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); 379c1121908SPaolo Severini if (target.SetSectionLoadAddress( 380c1121908SPaolo Severini section_sp, load_address | section_sp->GetFileOffset())) { 3814bafceceSPaolo Severini ++num_loaded_sections; 3824bafceceSPaolo Severini } 3834bafceceSPaolo Severini } 3844bafceceSPaolo Severini 3854bafceceSPaolo Severini return num_loaded_sections > 0; 3864bafceceSPaolo Severini } 3874bafceceSPaolo Severini 388c1121908SPaolo Severini DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { 3894bafceceSPaolo Severini DataExtractor data; 3904bafceceSPaolo Severini if (m_file) { 3914bafceceSPaolo Severini if (offset < GetByteSize()) { 392c1121908SPaolo Severini size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset); 3934bafceceSPaolo Severini auto buffer_sp = MapFileData(m_file, size, offset); 3944bafceceSPaolo Severini return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); 3954bafceceSPaolo Severini } 3964bafceceSPaolo Severini } else { 3974bafceceSPaolo Severini ProcessSP process_sp(m_process_wp.lock()); 3984bafceceSPaolo Severini if (process_sp) { 3994bafceceSPaolo Severini auto data_up = std::make_unique<DataBufferHeap>(size, 0); 4004bafceceSPaolo Severini Status readmem_error; 4014bafceceSPaolo Severini size_t bytes_read = process_sp->ReadMemory( 4024bafceceSPaolo Severini offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error); 4034bafceceSPaolo Severini if (bytes_read > 0) { 4044bafceceSPaolo Severini DataBufferSP buffer_sp(data_up.release()); 4054bafceceSPaolo Severini data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); 4064bafceceSPaolo Severini } 4074bafceceSPaolo Severini } 4084bafceceSPaolo Severini } 4094bafceceSPaolo Severini 4104bafceceSPaolo Severini data.SetByteOrder(GetByteOrder()); 4114bafceceSPaolo Severini return data; 4124bafceceSPaolo Severini } 4134bafceceSPaolo Severini 4149b3254dbSPaolo Severini llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() { 4159b3254dbSPaolo Severini static ConstString g_sect_name_external_debug_info("external_debug_info"); 4169b3254dbSPaolo Severini 4179b3254dbSPaolo Severini for (const section_info §_info : m_sect_infos) { 4189b3254dbSPaolo Severini if (g_sect_name_external_debug_info == sect_info.name) { 4199b3254dbSPaolo Severini const uint32_t kBufferSize = 1024; 4209b3254dbSPaolo Severini DataExtractor section_header_data = 4219b3254dbSPaolo Severini ReadImageData(sect_info.offset, kBufferSize); 4229b3254dbSPaolo Severini llvm::DataExtractor data = section_header_data.GetAsLLVM(); 4239b3254dbSPaolo Severini llvm::DataExtractor::Cursor c(0); 4249b3254dbSPaolo Severini llvm::Optional<ConstString> symbols_url = GetWasmString(data, c); 4259b3254dbSPaolo Severini if (symbols_url) 4269b3254dbSPaolo Severini return FileSpec(symbols_url->GetStringRef()); 4279b3254dbSPaolo Severini } 4289b3254dbSPaolo Severini } 4299b3254dbSPaolo Severini return llvm::None; 4309b3254dbSPaolo Severini } 4319b3254dbSPaolo Severini 4324bafceceSPaolo Severini void ObjectFileWasm::Dump(Stream *s) { 4334bafceceSPaolo Severini ModuleSP module_sp(GetModule()); 4344bafceceSPaolo Severini if (!module_sp) 4354bafceceSPaolo Severini return; 4364bafceceSPaolo Severini 4374bafceceSPaolo Severini std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); 4384bafceceSPaolo Severini 4394bafceceSPaolo Severini llvm::raw_ostream &ostream = s->AsRawOstream(); 4404bafceceSPaolo Severini ostream << static_cast<void *>(this) << ": "; 4414bafceceSPaolo Severini s->Indent(); 4424bafceceSPaolo Severini ostream << "ObjectFileWasm, file = '"; 4434bafceceSPaolo Severini m_file.Dump(ostream); 4444bafceceSPaolo Severini ostream << "', arch = "; 4454bafceceSPaolo Severini ostream << GetArchitecture().GetArchitectureName() << "\n"; 4464bafceceSPaolo Severini 4474bafceceSPaolo Severini SectionList *sections = GetSectionList(); 4484bafceceSPaolo Severini if (sections) { 4493a168297SPavel Labath sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, 4503a168297SPavel Labath UINT32_MAX); 4514bafceceSPaolo Severini } 4524bafceceSPaolo Severini ostream << "\n"; 4534bafceceSPaolo Severini DumpSectionHeaders(ostream); 4544bafceceSPaolo Severini ostream << "\n"; 4554bafceceSPaolo Severini } 4564bafceceSPaolo Severini 4574bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream, 4584bafceceSPaolo Severini const section_info_t &sh) { 4594bafceceSPaolo Severini ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " " 4604bafceceSPaolo Severini << llvm::format_hex(sh.offset, 10) << " " 4614bafceceSPaolo Severini << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6) 4624bafceceSPaolo Severini << "\n"; 4634bafceceSPaolo Severini } 4644bafceceSPaolo Severini 4654bafceceSPaolo Severini void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) { 4664bafceceSPaolo Severini ostream << "Section Headers\n"; 4674bafceceSPaolo Severini ostream << "IDX name addr size id\n"; 4684bafceceSPaolo Severini ostream << "==== ---------------- ---------- ---------- ------\n"; 4694bafceceSPaolo Severini 4704bafceceSPaolo Severini uint32_t idx = 0; 4714bafceceSPaolo Severini for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end(); 4724bafceceSPaolo Severini ++pos, ++idx) { 4734bafceceSPaolo Severini ostream << "[" << llvm::format_decimal(idx, 2) << "] "; 4744bafceceSPaolo Severini ObjectFileWasm::DumpSectionHeader(ostream, *pos); 4754bafceceSPaolo Severini } 4764bafceceSPaolo Severini } 477