diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/functionalities/gdb_remote_client/TestWasm.py @@ -0,0 +1,124 @@ +import lldb +import binascii +import struct +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + +def format_register_value(val): + """ + Encode each byte by two hex digits in little-endian order. + """ + return ''.join(x.encode('hex') for x in struct.pack('GetTarget().GetArchitecture().GetTriple().getArch() == + llvm::Triple::wasm32); + } + + if (should_create) + return new DynamicLoaderWasmDYLD(process); + + return nullptr; +} + +/// In WebAssembly, linear memory is disjointed from code space. The VM can load +/// multiple instances of a module, which logically share the same code. +/// Currently we only support wasm32, which uses a 32-bit address space for the +/// code. +/// We represent a code address in LLDB as a 64-bit address with the format: +/// 63 32 31 0 +/// +---------------+---------------+ +/// + module_id | offset | +/// +---------------+---------------+ +/// where the lower 32 bits represent a module offset (relative to the module +/// start not to the beginning of the code section) and the higher 32 bits +/// uniquely identify the module in the WebAssembly VM. +/// This method should be called for each Wasm module loaded in the debuggee, +/// with base_addr = 0x{module_id}|00000000 (for example 0x0000000100000000). +ModuleSP DynamicLoaderWasmDYLD::LoadModuleAtAddress(const FileSpec &file, + addr_t link_map_addr, + addr_t base_addr, + bool base_addr_is_offset) { + if (ModuleSP module_sp = m_process->ReadModuleFromMemory(file, base_addr)) { + UpdateLoadedSections(module_sp, link_map_addr, base_addr, false); + m_process->GetTarget().GetImages().AppendIfNeeded(module_sp); + return module_sp; + } + + return ModuleSP(); +} + +void DynamicLoaderWasmDYLD::DidAttach() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + LLDB_LOGF(log, "DynamicLoaderWasmDYLD::%s()", __FUNCTION__); + + // Ask the process for the list of loaded WebAssembly modules. + auto error = m_process->LoadModules(); + LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}"); + + ModuleList loaded_module_list; + const ModuleList &module_list = m_process->GetTarget().GetImages(); + const size_t num_modules = module_list.GetSize(); + for (uint32_t idx = 0; idx < num_modules; ++idx) { + ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(idx)); + if (!module_sp) + continue; + + ObjectFileWasm *image_object_file = + llvm::dyn_cast_or_null(module_sp->GetObjectFile()); + if (!image_object_file) + continue; + + lldb::addr_t image_load_address = + image_object_file->GetBaseAddress().GetOffset(); + + SectionList *section_list = image_object_file->GetSectionList(); + if (!section_list) + continue; + + // Fixes the section load address for each section. + const size_t num_sections = section_list->GetSize(); + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + + // Code section load address is offsetted by the code section + // offset in the Wasm module. + lldb::addr_t file_addr = (section_sp->GetName() == "code") + ? image_object_file->GetCodeSectionOffset() + : section_sp->GetFileAddress(); + lldb::addr_t load_addr = image_load_address | file_addr; + if (m_process->GetTarget().SetSectionLoadAddress(section_sp, load_addr)) + loaded_module_list.AppendIfNeeded(module_sp); + } + } + + m_process->GetTarget().ModulesDidLoad(loaded_module_list); +} + +ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread, + bool stop) { + return ThreadPlanSP(); +} diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h @@ -101,8 +101,7 @@ bool value_is_offset) override; lldb_private::Address GetBaseAddress() override { - return IsInMemory() ? Address(m_memory_addr + m_code_section_offset) - : Address(m_code_section_offset); + return IsInMemory() ? Address(m_memory_addr) : Address(0); } /// \} @@ -112,6 +111,8 @@ /// information for this module. llvm::Optional GetExternalDebugInfoFileSpec(); + uint32_t GetCodeSectionOffset() const { return m_code_section_offset; } + private: ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, const FileSpec *file, @@ -127,7 +128,7 @@ /// \} /// Read a range of bytes from the Wasm module. - DataExtractor ReadImageData(uint64_t offset, size_t size); + DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size); typedef struct section_info { lldb::offset_t offset; diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -355,12 +355,12 @@ return false; const size_t num_sections = section_list->GetSize(); - size_t sect_idx = 0; - - for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); - if (target.GetSectionLoadList().SetSectionLoadAddress( - section_sp, load_address | section_sp->GetFileAddress())) { + lldb::addr_t file_address = (section_sp->GetName() == "code") + ? GetCodeSectionOffset() + : section_sp->GetFileAddress(); + if (target.SetSectionLoadAddress(section_sp, load_address | file_address)) { ++num_loaded_sections; } } @@ -368,11 +368,11 @@ return num_loaded_sections > 0; } -DataExtractor ObjectFileWasm::ReadImageData(uint64_t offset, size_t size) { +DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { DataExtractor data; if (m_file) { if (offset < GetByteSize()) { - size = std::min(size, GetByteSize() - offset); + size = std::min(static_cast(size), GetByteSize() - offset); auto buffer_sp = MapFileData(m_file, size, offset); return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); } diff --git a/lldb/tools/lldb-test/SystemInitializerTest.cpp b/lldb/tools/lldb-test/SystemInitializerTest.cpp --- a/lldb/tools/lldb-test/SystemInitializerTest.cpp +++ b/lldb/tools/lldb-test/SystemInitializerTest.cpp @@ -37,6 +37,7 @@ #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" #include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h" +#include "Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.h" #include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h" #include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h" #include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h" @@ -246,6 +247,7 @@ DynamicLoaderMacOSXDYLD::Initialize(); DynamicLoaderMacOS::Initialize(); DynamicLoaderPOSIXDYLD::Initialize(); + wasm::DynamicLoaderWasmDYLD::Initialize(); DynamicLoaderStatic::Initialize(); DynamicLoaderWindowsDYLD::Initialize(); @@ -329,6 +331,7 @@ DynamicLoaderMacOSXDYLD::Terminate(); DynamicLoaderMacOS::Terminate(); DynamicLoaderPOSIXDYLD::Terminate(); + wasm::DynamicLoaderWasmDYLD::Terminate(); DynamicLoaderStatic::Terminate(); DynamicLoaderWindowsDYLD::Terminate();