diff options
Diffstat (limited to 'lldb/source/Plugins')
23 files changed, 621 insertions, 12 deletions
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 67963a7..b1efd25 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -376,9 +376,13 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { DataBufferSP buffer_sp(data_up.release()); data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); } + } else if (offset < m_data.GetByteSize()) { + size = + std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset); + return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(), + GetAddressByteSize()); } } - data.SetByteOrder(GetByteOrder()); return data; } diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index bd9b1b8..3413360 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -29,3 +29,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(wasm) diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/lldb/source/Plugins/Process/Utility/AuxVector.cpp index 50500a85..d660bfe 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.cpp +++ b/lldb/source/Plugins/Process/Utility/AuxVector.cpp @@ -92,6 +92,8 @@ const char *AuxVector::GetEntryName(EntryType type) const { case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break; case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break; case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break; + case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP3); break; + case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP4); break; } #undef ENTRY_NAME diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h index 7733e0f..ad6b70e 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -70,6 +70,10 @@ public: // Platform specific values which may overlap the Linux values. AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value. + // FreeBSD and Linux use the same AT_HWCAP2 value. + AUXV_FREEBSD_AT_HWCAP3 = 38, ///< FreeBSD specific AT_HWCAP3 value. + AUXV_FREEBSD_AT_HWCAP4 = 39, ///< FreeBSD specific AT_HWCAP4 value. + }; std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const; diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 36e7409..f610422 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -323,6 +323,11 @@ ProcessGDBRemote::~ProcessGDBRemote() { KillDebugserverProcess(); } +std::shared_ptr<ThreadGDBRemote> +ProcessGDBRemote::CreateThread(lldb::tid_t tid) { + return std::make_shared<ThreadGDBRemote>(*this, tid); +} + bool ProcessGDBRemote::ParsePythonTargetDefinition( const FileSpec &target_definition_fspec) { ScriptInterpreter *interpreter = @@ -1594,7 +1599,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + thread_sp = CreateThread(tid); LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.", thread_sp.get(), thread_sp->GetID()); } else { @@ -1726,7 +1731,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (!thread_sp) { // Create the thread if we need to - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + thread_sp = CreateThread(tid); m_thread_list_real.AddThread(thread_sp); } } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 7ae3383..7c3dfb1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -246,6 +246,8 @@ protected: ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid); + bool SupportsMemoryTagging() override; /// Broadcaster event bits definitions. diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt new file mode 100644 index 0000000..ff8a3c7 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginProcessWasm PLUGIN + ProcessWasm.cpp + ThreadWasm.cpp + UnwindWasm.cpp + + LINK_LIBS + lldbCore + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp new file mode 100644 index 0000000..5eeabec --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "ProcessWasm.h" +#include "ThreadWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "lldb/Target/UnixSignals.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(ProcessWasm) + +ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp) + : ProcessGDBRemote(target_sp, listener_sp) { + assert(target_sp); + // Wasm doesn't have any Unix-like signals as a platform concept, but pretend + // like it does to appease LLDB. + m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture()); +} + +void ProcessWasm::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + }); +} + +void ProcessWasm::DebuggerInitialize(Debugger &debugger) { + ProcessGDBRemote::DebuggerInitialize(debugger); +} + +llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); } + +llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; } + +llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() { + return "GDB Remote protocol based WebAssembly debugging plug-in."; +} + +void ProcessWasm::Terminate() { + PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance); +} + +lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect) { + if (crash_file_path == nullptr) + return std::make_shared<ProcessWasm>(target_sp, listener_sp); + return {}; +} + +bool ProcessWasm::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + if (plugin_specified_by_name) + return true; + + if (Module *exe_module = target_sp->GetExecutableModulePointer()) { + if (ObjectFile *exe_objfile = exe_module->GetObjectFile()) + return exe_objfile->GetArchitecture().GetMachine() == + llvm::Triple::wasm32; + } + + // However, if there is no wasm module, we return false, otherwise, + // we might use ProcessWasm to attach gdb remote. + return false; +} + +std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) { + return std::make_shared<ThreadWasm>(*this, tid); +} + +size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) { + wasm_addr_t wasm_addr(vm_addr); + + switch (wasm_addr.GetType()) { + case WasmAddressType::Memory: + case WasmAddressType::Object: + return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error); + case WasmAddressType::Invalid: + error.FromErrorStringWithFormat( + "Wasm read failed for invalid address 0x%" PRIx64, vm_addr); + return 0; + } +} + +llvm::Expected<std::vector<lldb::addr_t>> +ProcessWasm::GetWasmCallStack(lldb::tid_t tid) { + StreamString packet; + packet.Printf("qWasmCallStack:"); + packet.Printf("%" PRIx64, tid); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) != + GDBRemoteCommunication::PacketResult::Success) + return llvm::createStringError("failed to send qWasmCallStack"); + + if (!response.IsNormalResponse()) + return llvm::createStringError("failed to get response for qWasmCallStack"); + + WritableDataBufferSP data_buffer_sp = + std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0); + const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc'); + if (bytes == 0 || bytes % sizeof(uint64_t) != 0) + return llvm::createStringError("invalid response for qWasmCallStack"); + + // To match the Wasm specification, the addresses are encoded in little endian + // byte order. + DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle, + GetAddressByteSize()); + lldb::offset_t offset = 0; + std::vector<lldb::addr_t> call_stack_pcs; + while (offset < bytes) + call_stack_pcs.push_back(data.GetU64(&offset)); + + return call_stack_pcs; +} diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h new file mode 100644 index 0000000..bab14a8 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H + +#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" + +namespace lldb_private { +namespace wasm { + +/// Each WebAssembly module has separated address spaces for Code and Memory. +/// A WebAssembly module also has a Data section which, when the module is +/// loaded, gets mapped into a region in the module Memory. +enum WasmAddressType : uint8_t { Memory = 0x00, Object = 0x01, Invalid = 0xff }; + +/// For the purpose of debugging, we can represent all these separated 32-bit +/// address spaces with a single virtual 64-bit address space. The +/// wasm_addr_t provides this encoding using bitfields. +struct wasm_addr_t { + uint64_t offset : 32; + uint64_t module_id : 30; + uint64_t type : 2; + + wasm_addr_t(lldb::addr_t addr) + : offset(addr & 0x00000000ffffffff), + module_id((addr & 0x00ffffff00000000) >> 32), type(addr >> 62) {} + + wasm_addr_t(WasmAddressType type, uint32_t module_id, uint32_t offset) + : offset(offset), module_id(module_id), type(type) {} + + WasmAddressType GetType() { return static_cast<WasmAddressType>(type); } + + operator lldb::addr_t() { return *(uint64_t *)this; } +}; + +static_assert(sizeof(wasm_addr_t) == 8, ""); + +/// ProcessWasm provides the access to the Wasm program state +/// retrieved from the Wasm engine. +class ProcessWasm : public process_gdb_remote::ProcessGDBRemote { +public: + ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + ~ProcessWasm() override = default; + + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + static void DebuggerInitialize(Debugger &debugger); + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic(); + static llvm::StringRef GetPluginDescriptionStatic(); + + llvm::StringRef GetPluginName() override; + + size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + /// Retrieve the current call stack from the WebAssembly remote process. + llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack(lldb::tid_t tid); + +protected: + std::shared_ptr<process_gdb_remote::ThreadGDBRemote> + CreateThread(lldb::tid_t tid) override; + +private: + friend class UnwindWasm; + process_gdb_remote::GDBRemoteDynamicRegisterInfoSP &GetRegisterInfo() { + return m_register_info_sp; + } + + ProcessWasm(const ProcessWasm &); + const ProcessWasm &operator=(const ProcessWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp new file mode 100644 index 0000000..a6553ff --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "ThreadWasm.h" + +#include "ProcessWasm.h" +#include "UnwindWasm.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +Unwind &ThreadWasm::GetUnwinder() { + if (!m_unwinder_up) { + assert(CalculateTarget()->GetArchitecture().GetMachine() == + llvm::Triple::wasm32); + m_unwinder_up.reset(new wasm::UnwindWasm(*this)); + } + return *m_unwinder_up; +} + +llvm::Expected<std::vector<lldb::addr_t>> ThreadWasm::GetWasmCallStack() { + if (ProcessSP process_sp = GetProcess()) { + ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get()); + return wasm_process->GetWasmCallStack(GetID()); + } + return llvm::createStringError("no process"); +} diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.h b/lldb/source/Plugins/Process/wasm/ThreadWasm.h new file mode 100644 index 0000000..1c90f58 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H + +#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h" + +namespace lldb_private { +namespace wasm { + +/// ProcessWasm provides the access to the Wasm program state +/// retrieved from the Wasm engine. +class ThreadWasm : public process_gdb_remote::ThreadGDBRemote { +public: + ThreadWasm(Process &process, lldb::tid_t tid) + : process_gdb_remote::ThreadGDBRemote(process, tid) {} + ~ThreadWasm() override = default; + + /// Retrieve the current call stack from the WebAssembly remote process. + llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack(); + +protected: + Unwind &GetUnwinder() override; + + ThreadWasm(const ThreadWasm &); + const ThreadWasm &operator=(const ThreadWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp new file mode 100644 index 0000000..99845dd --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "UnwindWasm.h" +#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h" +#include "ProcessWasm.h" +#include "ThreadWasm.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; +using namespace process_gdb_remote; +using namespace wasm; + +class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext { +public: + WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread, + uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfoSP ®_info_sp, + uint64_t pc) + : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false, + false) { + // Wasm does not have a fixed set of registers but relies on a mechanism + // named local and global variables to store information such as the stack + // pointer. The only actual register is the PC. + PrivateSetRegisterValue(0, pc); + } +}; + +lldb::RegisterContextSP +UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) { + if (m_frames.size() <= frame->GetFrameIndex()) + return lldb::RegisterContextSP(); + + ThreadSP thread = frame->GetThread(); + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread.get()); + ProcessWasm *wasm_process = + static_cast<ProcessWasm *>(thread->GetProcess().get()); + + return std::make_shared<WasmGDBRemoteRegisterContext>( + *gdb_thread, frame->GetConcreteFrameIndex(), + wasm_process->GetRegisterInfo(), m_frames[frame->GetFrameIndex()]); +} + +uint32_t UnwindWasm::DoGetFrameCount() { + if (m_unwind_complete) + return m_frames.size(); + + m_unwind_complete = true; + m_frames.clear(); + + ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread()); + llvm::Expected<std::vector<lldb::addr_t>> call_stack_pcs = + wasm_thread.GetWasmCallStack(); + if (!call_stack_pcs) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Unwind), call_stack_pcs.takeError(), + "Failed to get Wasm callstack: {0}"); + m_frames.clear(); + return 0; + } + + m_frames = *call_stack_pcs; + return m_frames.size(); +} + +bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, + lldb::addr_t &pc, + bool &behaves_like_zeroth_frame) { + if (m_frames.size() == 0) + DoGetFrameCount(); + + if (frame_idx >= m_frames.size()) + return false; + + behaves_like_zeroth_frame = (frame_idx == 0); + cfa = 0; + pc = m_frames[frame_idx]; + return true; +} diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h new file mode 100644 index 0000000..ff5e06d --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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_SOURCE_PLUGINS_PROCESS_WASM_UNWINDWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_UNWINDWASM_H + +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Unwind.h" +#include <vector> + +namespace lldb_private { +namespace wasm { + +/// UnwindWasm manages stack unwinding for a WebAssembly process. +class UnwindWasm : public lldb_private::Unwind { +public: + UnwindWasm(lldb_private::Thread &thread) : Unwind(thread) {} + ~UnwindWasm() override = default; + +protected: + void DoClear() override { + m_frames.clear(); + m_unwind_complete = false; + } + + uint32_t DoGetFrameCount() override; + + bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, + lldb::addr_t &pc, + bool &behaves_like_zeroth_frame) override; + + lldb::RegisterContextSP + DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + +private: + std::vector<lldb::addr_t> m_frames; + bool m_unwind_complete = false; + + UnwindWasm(const UnwindWasm &); + const UnwindWasm &operator=(const UnwindWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 212cc36..c3f1bb5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -35,6 +35,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN SymbolFileDWARF.cpp SymbolFileDWARFDwo.cpp SymbolFileDWARFDebugMap.cpp + SymbolFileWasm.cpp UniqueDWARFASTType.cpp LINK_COMPONENTS diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index a66af5b..94fc2e83 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -736,9 +736,11 @@ DWARFUnit::GetVendorDWARFOpcodeSize(const DataExtractor &data, bool DWARFUnit::ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, lldb::offset_t &offset, + RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, std::vector<Value> &stack) const { return GetSymbolFileDWARF().ParseVendorDWARFOpcode(op, opcodes, offset, - stack); + reg_ctx, reg_kind, stack); } bool DWARFUnit::ParseDWARFLocationList( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index f55400e..91a6938 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -164,9 +164,11 @@ public: const lldb::offset_t data_offset, const uint8_t op) const override; - bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, - lldb::offset_t &offset, - std::vector<Value> &stack) const override; + virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, + RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + std::vector<Value> &stack) const override; bool ParseDWARFLocationList(const DataExtractor &data, DWARFExpressionList &loc_list) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 4b4a582..41ab8d1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -41,6 +41,7 @@ #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileWasm.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" @@ -327,6 +328,9 @@ llvm::StringRef SymbolFileDWARF::GetPluginDescriptionStatic() { } SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFileSP objfile_sp) { + if (objfile_sp->GetArchitecture().GetTriple().isWasm()) + return new SymbolFileWasm(std::move(objfile_sp), + /*dwo_section_list*/ nullptr); return new SymbolFileDWARF(std::move(objfile_sp), /*dwo_section_list*/ nullptr); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 2dc862c..56d8ccb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -329,6 +329,8 @@ public: virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, lldb::offset_t &offset, + RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, std::vector<Value> &stack) const { return false; } @@ -556,6 +558,7 @@ protected: /// an index that identifies the .DWO or .o file. std::optional<uint64_t> m_file_index; }; + } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index c1829ab..52de3ab 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -97,9 +97,11 @@ uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) { } bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode( - uint8_t op, const lldb_private::DataExtractor &opcodes, - lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const { - return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, stack); + uint8_t op, const DataExtractor &opcodes, lldb::offset_t &offset, + RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, + std::vector<Value> &stack) const { + return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, + reg_ctx, reg_kind, stack); } llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> & diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 75f5986..1ab6494 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -50,7 +50,8 @@ public: uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, - lldb::offset_t &offset, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, std::vector<Value> &stack) const override; void FindGlobalVariables(ConstString name, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp new file mode 100644 index 0000000..e25a89c --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "SymbolFileWasm.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" +#include "Utility/WasmVirtualRegisters.h" +#include "lldb/Utility/LLDBLog.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::plugin::dwarf; + +SymbolFileWasm::SymbolFileWasm(ObjectFileSP objfile_sp, + SectionList *dwo_section_list) + : SymbolFileDWARF(objfile_sp, dwo_section_list) {} + +SymbolFileWasm::~SymbolFileWasm() = default; + +lldb::offset_t +SymbolFileWasm::GetVendorDWARFOpcodeSize(const DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const { + if (op != llvm::dwarf::DW_OP_WASM_location) + return LLDB_INVALID_OFFSET; + + lldb::offset_t offset = data_offset; + const uint8_t wasm_op = data.GetU8(&offset); + switch (wasm_op) { + case 0: // LOCAL + case 1: // GLOBAL_FIXED + case 2: // OPERAND_STACK + data.GetULEB128(&offset); + break; + case 3: // GLOBAL_RELOC + data.GetU32(&offset); + break; + default: + return LLDB_INVALID_OFFSET; + } + + return offset - data_offset; +} + +bool SymbolFileWasm::ParseVendorDWARFOpcode(uint8_t op, + const DataExtractor &opcodes, + lldb::offset_t &offset, + RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + std::vector<Value> &stack) const { + if (op != llvm::dwarf::DW_OP_WASM_location) + return false; + + uint32_t index = 0; + uint8_t tag = eWasmTagNotAWasmLocation; + + /// |DWARF Location Index | WebAssembly Construct | + /// |---------------------|-----------------------| + /// |0 | Local | + /// |1 or 3 | Global | + /// |2 | Operand Stack | + const uint8_t wasm_op = opcodes.GetU8(&offset); + switch (wasm_op) { + case 0: // LOCAL + index = opcodes.GetULEB128(&offset); + tag = eWasmTagLocal; + break; + case 1: // GLOBAL_FIXED + index = opcodes.GetULEB128(&offset); + tag = eWasmTagGlobal; + break; + case 2: // OPERAND_STACK + index = opcodes.GetULEB128(&offset); + tag = eWasmTagOperandStack; + break; + case 3: // GLOBAL_RELOC + index = opcodes.GetU32(&offset); + tag = eWasmTagGlobal; + break; + default: + return false; + } + + const uint32_t reg_num = GetWasmRegister(tag, index); + + Value tmp; + llvm::Error error = DWARFExpression::ReadRegisterValueAsScalar( + reg_ctx, reg_kind, reg_num, tmp); + if (error) { + LLDB_LOG_ERROR(GetLog(DWARFLog::DebugInfo), std::move(error), "{0}"); + return false; + } + + stack.push_back(tmp); + return true; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h new file mode 100644 index 0000000..0e0b742 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEWASM_H +#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEWASM_H + +#include "SymbolFileDWARF.h" + +namespace lldb_private::plugin { +namespace dwarf { +class SymbolFileWasm : public SymbolFileDWARF { +public: + SymbolFileWasm(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list); + + ~SymbolFileWasm() override; + + lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const override; + + bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + std::vector<Value> &stack) const override; +}; +} // namespace dwarf +} // namespace lldb_private::plugin + +#endif diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h index 1f888f4..98b965c 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -65,7 +65,7 @@ struct CVTagRecord { } llvm::StringRef name() const { - if (m_kind == Struct || m_kind == Union) + if (m_kind == Struct || m_kind == Class) return cvclass.Name; if (m_kind == Enum) return cvenum.Name; |