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; +} + +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}"); +} + +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 @@ -1,153 +1,151 @@ -//===-- ObjectFileWasm.h ----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H -#define LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H - -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/ArchSpec.h" - -namespace lldb_private { -namespace wasm { - -/// Generic Wasm object file reader. -/// -/// This class provides a generic wasm32 reader plugin implementing the -/// ObjectFile protocol. -class ObjectFileWasm : public ObjectFile { -public: - static void Initialize(); - static void Terminate(); - - static ConstString GetPluginNameStatic(); - static const char *GetPluginDescriptionStatic() { - return "WebAssembly object file reader."; - } - - static ObjectFile * - CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, - lldb::offset_t data_offset, const FileSpec *file, - lldb::offset_t file_offset, lldb::offset_t length); - - static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP &data_sp, - const lldb::ProcessSP &process_sp, - lldb::addr_t header_addr); - - static size_t GetModuleSpecifications(const FileSpec &file, - lldb::DataBufferSP &data_sp, - lldb::offset_t data_offset, - lldb::offset_t file_offset, - lldb::offset_t length, - ModuleSpecList &specs); - - /// PluginInterface protocol. - /// \{ - ConstString GetPluginName() override { return GetPluginNameStatic(); } - uint32_t GetPluginVersion() override { return 1; } - /// \} - - /// LLVM RTTI support - /// \{ - static char ID; - bool isA(const void *ClassID) const override { - return ClassID == &ID || ObjectFile::isA(ClassID); - } - static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } - /// \} - - /// ObjectFile Protocol. - /// \{ - bool ParseHeader() override; - - lldb::ByteOrder GetByteOrder() const override { - return m_arch.GetByteOrder(); - } - - bool IsExecutable() const override { return true; } - - uint32_t GetAddressByteSize() const override { - return m_arch.GetAddressByteSize(); - } - - AddressClass GetAddressClass(lldb::addr_t file_addr) override { - return AddressClass::eInvalid; - } - - Symtab *GetSymtab() override; - - bool IsStripped() override { return true; } - - void CreateSections(SectionList &unified_section_list) override; - - void Dump(Stream *s) override; - - ArchSpec GetArchitecture() override { return m_arch; } - - UUID GetUUID() override { return m_uuid; } - - uint32_t GetDependentModules(FileSpecList &files) override { return 0; } - - Type CalculateType() override { return eTypeExecutable; } - - Strata CalculateStrata() override { return eStrataUser; } - - bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, - 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); - } - /// \} - - /// A Wasm module that has external DWARF debug information should contain a - /// custom section named "external_debug_info", whose payload is an UTF-8 - /// encoded string that points to a Wasm module that contains the debug - /// information for this module. - llvm::Optional GetExternalDebugInfoFileSpec(); - -private: - ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, - lldb::offset_t data_offset, const FileSpec *file, - lldb::offset_t offset, lldb::offset_t length); - ObjectFileWasm(const lldb::ModuleSP &module_sp, - lldb::DataBufferSP &header_data_sp, - const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); - - /// Wasm section decoding routines. - /// \{ - bool DecodeNextSection(lldb::offset_t *offset_ptr); - bool DecodeSections(); - /// \} - - /// Read a range of bytes from the Wasm module. - DataExtractor ReadImageData(uint64_t offset, size_t size); - - typedef struct section_info { - lldb::offset_t offset; - uint32_t size; - uint32_t id; - ConstString name; - } section_info_t; - - /// Wasm section header dump routines. - /// \{ - void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh); - void DumpSectionHeaders(llvm::raw_ostream &ostream); - /// \} - - std::vector m_sect_infos; - ArchSpec m_arch; - UUID m_uuid; - uint32_t m_code_section_offset; -}; - -} // namespace wasm -} // namespace lldb_private -#endif // LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H +//===-- ObjectFileWasm.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H +#define LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { +namespace wasm { + +/// Generic Wasm object file reader. +/// +/// This class provides a generic wasm32 reader plugin implementing the +/// ObjectFile protocol. +class ObjectFileWasm : public ObjectFile { +public: + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "WebAssembly object file reader."; + } + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + /// PluginInterface protocol. + /// \{ + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + /// \} + + /// LLVM RTTI support + /// \{ + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + /// \} + + /// ObjectFile Protocol. + /// \{ + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override { + return m_arch.GetByteOrder(); + } + + bool IsExecutable() const override { return false; } + + uint32_t GetAddressByteSize() const override { + return m_arch.GetAddressByteSize(); + } + + AddressClass GetAddressClass(lldb::addr_t file_addr) override { + return AddressClass::eInvalid; + } + + Symtab *GetSymtab() override; + + bool IsStripped() override { return !!GetExternalDebugInfoFileSpec(); } + + void CreateSections(SectionList &unified_section_list) override; + + void Dump(Stream *s) override; + + ArchSpec GetArchitecture() override { return m_arch; } + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeSharedLibrary; } + + Strata CalculateStrata() override { return eStrataUser; } + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb_private::Address GetBaseAddress() override { + return IsInMemory() ? Address(m_memory_addr) : Address(0); + } + /// \} + + /// A Wasm module that has external DWARF debug information should contain a + /// custom section named "external_debug_info", whose payload is an UTF-8 + /// encoded string that points to a Wasm module that contains the debug + /// information for this module. + llvm::Optional GetExternalDebugInfoFileSpec(); + +private: + ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + ObjectFileWasm(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + /// Wasm section decoding routines. + /// \{ + bool DecodeNextSection(lldb::offset_t *offset_ptr); + bool DecodeSections(); + /// \} + + /// Read a range of bytes from the Wasm module. + DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size); + + typedef struct section_info { + lldb::offset_t offset; + uint32_t size; + uint32_t id; + ConstString name; + } section_info_t; + + /// Wasm section header dump routines. + /// \{ + void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh); + void DumpSectionHeaders(llvm::raw_ostream &ostream); + /// \} + + std::vector m_sect_infos; + ArchSpec m_arch; + UUID m_uuid; +}; + +} // namespace wasm +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H 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 @@ -233,7 +233,7 @@ offset_t data_offset, const FileSpec *file, offset_t offset, offset_t length) : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), - m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) { + m_arch("wasm32-unknown-unknown-wasm") { m_data.SetAddressByteSize(4); } @@ -242,7 +242,7 @@ const lldb::ProcessSP &process_sp, lldb::addr_t header_addr) : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), - m_arch("wasm32-unknown-unknown-wasm"), m_code_section_offset(0) {} + m_arch("wasm32-unknown-unknown-wasm") {} bool ObjectFileWasm::ParseHeader() { // We already parsed the header during initialization. @@ -264,15 +264,19 @@ for (const section_info §_info : m_sect_infos) { SectionType section_type = eSectionTypeOther; ConstString section_name; - offset_t file_offset = 0; - addr_t vm_addr = 0; - size_t vm_size = 0; + offset_t file_offset = sect_info.offset & 0xffffffff; + addr_t vm_addr = file_offset; + size_t vm_size = sect_info.size; if (llvm::wasm::WASM_SEC_CODE == sect_info.id) { section_type = eSectionTypeCode; section_name = ConstString("code"); - m_code_section_offset = sect_info.offset & 0xffffffff; - vm_size = sect_info.size; + + // A code address in DWARF for WebAssembly is the offset of an + // instruction relative within the Code section of the WebAssembly file. + // For this reason Section::GetFileAddress() must return zero for the + // Code section. + vm_addr = 0; } else { section_type = llvm::StringSwitch(sect_info.name.GetStringRef()) @@ -300,10 +304,9 @@ if (section_type == eSectionTypeOther) continue; section_name = sect_info.name; - file_offset = sect_info.offset & 0xffffffff; - if (IsInMemory()) { - vm_addr = sect_info.offset & 0xffffffff; - vm_size = sect_info.size; + if (!IsInMemory()) { + vm_size = 0; + vm_addr = 0; } } @@ -343,6 +346,8 @@ /// 0x0000000400000000 for module_id == 4. /// These 64-bit addresses will be used to request code ranges for a specific /// module from the WebAssembly engine. + assert(m_memory_addr == load_address); + ModuleSP module_sp = GetModule(); if (!module_sp) return false; @@ -355,12 +360,10 @@ 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())) { + if (target.SetSectionLoadAddress( + section_sp, load_address | section_sp->GetFileOffset())) { ++num_loaded_sections; } } @@ -368,11 +371,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();