diff options
Diffstat (limited to 'lldb/source')
32 files changed, 860 insertions, 190 deletions
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 0687c84..fdd6b3b 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -327,6 +327,7 @@ foreach(header endif() add_custom_target(liblldb-stage-header-${basename} DEPENDS ${staged_header}) + add_dependencies(liblldb-stage-header-${basename} lldb-sbapi-dwarf-enums) add_dependencies(liblldb-header-staging liblldb-stage-header-${basename}) add_custom_command( DEPENDS ${header} OUTPUT ${staged_header} @@ -339,6 +340,7 @@ foreach(header set(output_header $<TARGET_FILE_DIR:liblldb>/Headers/${basename}) add_custom_target(lldb-framework-fixup-header-${basename} DEPENDS ${staged_header}) + add_dependencies(lldb-framework-fixup-header-${basename} liblldb-stage-header-${basename}) add_dependencies(lldb-framework-fixup-all-headers lldb-framework-fixup-header-${basename}) add_custom_command(TARGET lldb-framework-fixup-header-${basename} POST_BUILD diff --git a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp index 2457052..701caba 100644 --- a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp @@ -35,7 +35,7 @@ BreakpointResolverScripted::BreakpointResolverScripted( void BreakpointResolverScripted::CreateImplementationIfNeeded( BreakpointSP breakpoint_sp) { - if (m_implementation_sp) + if (m_interface_sp) return; if (m_class_name.empty()) @@ -50,8 +50,27 @@ void BreakpointResolverScripted::CreateImplementationIfNeeded( if (!script_interp) return; - m_implementation_sp = script_interp->CreateScriptedBreakpointResolver( - m_class_name.c_str(), m_args, breakpoint_sp); + m_interface_sp = script_interp->CreateScriptedBreakpointInterface(); + if (!m_interface_sp) { + m_error = Status::FromErrorStringWithFormat( + "BreakpointResolverScripted::%s () - ERROR: %s", __FUNCTION__, + "Script interpreter couldn't create Scripted Breakpoint Interface"); + return; + } + + auto obj_or_err = + m_interface_sp->CreatePluginObject(m_class_name, breakpoint_sp, m_args); + if (!obj_or_err) { + m_error = Status::FromError(obj_or_err.takeError()); + return; + } + + StructuredData::ObjectSP object_sp = *obj_or_err; + if (!object_sp || !object_sp->IsValid()) { + m_error = Status::FromErrorStringWithFormat( + "ScriptedBreakpoint::%s () - ERROR: %s", __FUNCTION__, + "Failed to create valid script object"); + } } void BreakpointResolverScripted::NotifyBreakpointSet() { @@ -104,13 +123,10 @@ ScriptInterpreter *BreakpointResolverScripted::GetScriptInterpreter() { Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback( SearchFilter &filter, SymbolContext &context, Address *addr) { bool should_continue = true; - if (!m_implementation_sp) + if (!m_interface_sp) return Searcher::eCallbackReturnStop; - ScriptInterpreter *interp = GetScriptInterpreter(); - should_continue = interp->ScriptedBreakpointResolverSearchCallback( - m_implementation_sp, - &context); + should_continue = m_interface_sp->ResolverCallback(context); if (should_continue) return Searcher::eCallbackReturnContinue; @@ -120,25 +136,21 @@ Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback( lldb::SearchDepth BreakpointResolverScripted::GetDepth() { lldb::SearchDepth depth = lldb::eSearchDepthModule; - if (m_implementation_sp) { - ScriptInterpreter *interp = GetScriptInterpreter(); - depth = interp->ScriptedBreakpointResolverSearchDepth( - m_implementation_sp); - } + if (m_interface_sp) + depth = m_interface_sp->GetDepth(); + return depth; } void BreakpointResolverScripted::GetDescription(Stream *s) { StructuredData::GenericSP generic_sp; - std::string short_help; + std::optional<std::string> short_help; - if (m_implementation_sp) { - ScriptInterpreter *interp = GetScriptInterpreter(); - interp->GetShortHelpForCommandObject(m_implementation_sp, - short_help); + if (m_interface_sp) { + short_help = m_interface_sp->GetShortHelp(); } - if (!short_help.empty()) - s->PutCString(short_help.c_str()); + if (short_help && !short_help->empty()) + s->PutCString(short_help->c_str()); else s->Printf("python class = %s", m_class_name.c_str()); } diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index ae913e6..5ee19ff 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -116,6 +116,13 @@ lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream( return nullptr; } +SymbolContext ScriptInterpreter::GetOpaqueTypeFromSBSymbolContext( + const lldb::SBSymbolContext &sb_sym_ctx) const { + if (sb_sym_ctx.m_opaque_up) + return *sb_sym_ctx.m_opaque_up.get(); + return {}; +} + std::optional<MemoryRegionInfo> ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( const lldb::SBMemoryRegionInfo &mem_region) const { 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/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt index 33af2e2..bb69016 100644 --- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessLinux NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp + NativeRegisterContextLinux_arm64dbreg.cpp NativeRegisterContextLinux_loongarch64.cpp NativeRegisterContextLinux_ppc64le.cpp NativeRegisterContextLinux_riscv64.cpp diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index dc7fb10..fdafacf 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -23,13 +23,19 @@ #include <elf.h> #include <sys/uio.h> +#if defined(__arm64__) || defined(__aarch64__) +#include "NativeRegisterContextLinux_arm64dbreg.h" +#include "lldb/Host/linux/Ptrace.h" +#include <asm/ptrace.h> +#endif + #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr)) #ifndef PTRACE_GETVFPREGS #define PTRACE_GETVFPREGS 27 #define PTRACE_SETVFPREGS 28 #endif -#ifndef PTRACE_GETHBPREGS +#if defined(__arm__) && !defined(PTRACE_GETHBPREGS) #define PTRACE_GETHBPREGS 29 #define PTRACE_SETHBPREGS 30 #endif @@ -342,7 +348,8 @@ NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, m_hbr_regs[bp_index].control = control_value; // PTRACE call to set corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, + bp_index); if (error.Fail()) { m_hbr_regs[bp_index].address = 0; @@ -375,7 +382,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { m_hbr_regs[hw_idx].address = 0; // PTRACE call to clear corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, + hw_idx); if (error.Fail()) { m_hbr_regs[hw_idx].control = tempControl; @@ -435,7 +443,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() { m_hbr_regs[i].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeBREAK, i); + error = + WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i); if (error.Fail()) { m_hbr_regs[i].control = tempControl; @@ -555,7 +564,8 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( m_hwp_regs[wp_index].control = control_value; // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, + wp_index); if (error.Fail()) { m_hwp_regs[wp_index].address = 0; @@ -590,7 +600,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( m_hwp_regs[wp_index].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, + wp_index); if (error.Fail()) { m_hwp_regs[wp_index].control = tempControl; @@ -623,7 +634,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { m_hwp_regs[i].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); + error = + WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i); if (error.Fail()) { m_hwp_regs[i].control = tempControl; @@ -723,6 +735,7 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { return Status(); } +#ifdef __arm__ unsigned int cap_val; error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), @@ -737,16 +750,21 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { m_refresh_hwdebug_info = false; return error; +#else // __aarch64__ + return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported, + m_max_hbp_supported); +#endif // ifdef __arm__ } -Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, - int hwb_index) { +Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs( + NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) { Status error; +#ifdef __arm__ lldb::addr_t *addr_buf; uint32_t *ctrl_buf; - if (hwbType == eDREGTypeWATCH) { + if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) { addr_buf = &m_hwp_regs[hwb_index].address; ctrl_buf = &m_hwp_regs[hwb_index].control; @@ -781,6 +799,17 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, } return error; +#else // __aarch64__ + uint32_t max_supported = + (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) + ? m_max_hwp_supported + : m_max_hbp_supported; + auto ®s = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) + ? m_hwp_regs + : m_hbr_regs; + return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported, + regs); +#endif // ifdef __arm__ } uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index 420e866..3a31d68 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -12,6 +12,7 @@ #define lldb_NativeRegisterContextLinux_arm_h #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" #include "Plugins/Process/Utility/lldb-arm-register-enums.h" @@ -74,9 +75,6 @@ public: bool WatchpointIsEnabled(uint32_t wp_index); - // Debug register type select - enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; - protected: Status DoReadRegisterValue(uint32_t offset, const char *reg_name, uint32_t size, RegisterValue &value) override; @@ -102,17 +100,10 @@ private: uint32_t m_gpr_arm[k_num_gpr_registers_arm]; RegisterInfoPOSIX_arm::FPU m_fpr; - // Debug register info for hardware breakpoints and watchpoints management. - struct DREG { - lldb::addr_t address; // Breakpoint/watchpoint address value. - lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception - // occurred. - lldb::addr_t real_addr; // Address value that should cause target to stop. - uint32_t control; // Breakpoint/watchpoint control value. - }; - - struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints - struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints + std::array<NativeRegisterContextDBReg::DREG, 16> + m_hbr_regs; // Arm native linux hardware breakpoints + std::array<NativeRegisterContextDBReg::DREG, 16> + m_hwp_regs; // Arm native linux hardware watchpoints uint32_t m_max_hwp_supported; uint32_t m_max_hbp_supported; @@ -124,7 +115,8 @@ private: Status ReadHardwareDebugInfo(); - Status WriteHardwareDebugRegs(int hwbType, int hwb_index); + Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType, + int hwb_index); uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index b1c7421..294a446 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -8,8 +8,9 @@ #if defined(__arm64__) || defined(__aarch64__) -#include "NativeRegisterContextLinux_arm.h" #include "NativeRegisterContextLinux_arm64.h" +#include "NativeRegisterContextLinux_arm.h" +#include "NativeRegisterContextLinux_arm64dbreg.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/common/NativeProcessProtocol.h" @@ -1146,29 +1147,11 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { ::pid_t tid = m_thread.GetID(); - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Status error; - - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof(dreg_state); - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - + Status error = arm64::ReadHardwareDebugInfo(tid, m_max_hwp_supported, + m_max_hbp_supported); if (error.Fail()) return error.ToError(); - m_max_hwp_supported = dreg_state.dbg_info & 0xff; - - regset = NT_ARM_HW_BREAK; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - - if (error.Fail()) - return error.ToError(); - - m_max_hbp_supported = dreg_state.dbg_info & 0xff; m_refresh_hwdebug_info = false; return llvm::Error::success(); @@ -1176,38 +1159,11 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { llvm::Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - int regset; - - memset(&dreg_state, 0, sizeof(dreg_state)); - ioVec.iov_base = &dreg_state; - - switch (hwbType) { - case eDREGTypeWATCH: - regset = NT_ARM_HW_WATCH; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; - } - break; - case eDREGTypeBREAK: - regset = NT_ARM_HW_BREAK; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control; - } - break; - } - - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - ®set, &ioVec, ioVec.iov_len) + uint32_t max_supported = + (hwbType == eDREGTypeWATCH) ? m_max_hwp_supported : m_max_hbp_supported; + auto ®s = (hwbType == eDREGTypeWATCH) ? m_hwp_regs : m_hbp_regs; + return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported, + regs) .ToError(); } diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp new file mode 100644 index 0000000..53ee8fd --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp @@ -0,0 +1,77 @@ +//===-- NativeRegisterContextLinux_arm64dbreg.cpp -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm64__) || defined(__aarch64__) + +#include "NativeRegisterContextLinux_arm64dbreg.h" +#include "lldb/Host/linux/Ptrace.h" + +#include <asm/ptrace.h> +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include <sys/uio.h> +// NT_PRSTATUS and NT_FPREGSET definition +#include <elf.h> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_linux; + +static Status ReadHardwareDebugInfoHelper(int regset, ::pid_t tid, + uint32_t &max_supported) { + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Status error; + + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof(dreg_state); + error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, + &ioVec, ioVec.iov_len); + + if (error.Fail()) + return error; + + max_supported = dreg_state.dbg_info & 0xff; + return error; +} + +Status lldb_private::process_linux::arm64::ReadHardwareDebugInfo( + ::pid_t tid, uint32_t &max_hwp_supported, uint32_t &max_hbp_supported) { + Status error = + ReadHardwareDebugInfoHelper(NT_ARM_HW_WATCH, tid, max_hwp_supported); + + if (error.Fail()) + return error; + + return ReadHardwareDebugInfoHelper(NT_ARM_HW_BREAK, tid, max_hbp_supported); +} + +Status lldb_private::process_linux::arm64::WriteHardwareDebugRegs( + int hwbType, ::pid_t tid, uint32_t max_supported, + const std::array<NativeRegisterContextDBReg::DREG, 16> ®s) { + int regset = hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH + ? NT_ARM_HW_WATCH + : NT_ARM_HW_BREAK; + + struct user_hwdebug_state dreg_state; + memset(&dreg_state, 0, sizeof(dreg_state)); + for (uint32_t i = 0; i < max_supported; i++) { + dreg_state.dbg_regs[i].addr = regs[i].address; + dreg_state.dbg_regs[i].ctrl = regs[i].control; + } + + struct iovec ioVec; + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + + (sizeof(dreg_state.dbg_regs[0]) * max_supported); + + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, + &ioVec, ioVec.iov_len); +} + +#endif // defined (__arm64__) || defined (__aarch64__) diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h new file mode 100644 index 0000000..bca2178 --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h @@ -0,0 +1,31 @@ +//===-- NativeRegisterContextLinux_arm64dbreg.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 +// +//===----------------------------------------------------------------------===// + +// When debugging 32-bit processes, Arm64 lldb-server should use 64-bit ptrace +// interfaces. 32-bit ptrace interfaces should only be used by 32-bit server. +// These functions are split out to be reused in both 32-bit and 64-bit register +// context for 64-bit server. + +#include "Plugins/Process/Linux/NativeProcessLinux.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h" +#include "lldb/Utility/Status.h" + +namespace lldb_private { +namespace process_linux { +namespace arm64 { + +Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported, + uint32_t &max_hbp_supported); + +Status WriteHardwareDebugRegs( + int hwbType, ::pid_t tid, uint32_t max_supported, + const std::array<NativeRegisterContextDBReg::DREG, 16> ®s); + +} // namespace arm64 +} // namespace process_linux +} // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h index e17a700..9b6ecd3 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h @@ -51,7 +51,6 @@ public: lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; -protected: // Debug register type select enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; @@ -64,6 +63,7 @@ protected: uint32_t control; // Breakpoint/watchpoint control value. }; +protected: std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints 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/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt index db9e11b..0437094 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt @@ -26,6 +26,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN ScriptedProcessPythonInterface.cpp ScriptedPythonInterface.cpp ScriptedStopHookPythonInterface.cpp + ScriptedBreakpointPythonInterface.cpp ScriptedThreadPlanPythonInterface.cpp ScriptedThreadPythonInterface.cpp diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp index 1fd3299..d43036d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp @@ -29,6 +29,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() { ScriptedPlatformPythonInterface::Initialize(); ScriptedProcessPythonInterface::Initialize(); ScriptedStopHookPythonInterface::Initialize(); + ScriptedBreakpointPythonInterface::Initialize(); ScriptedThreadPlanPythonInterface::Initialize(); } @@ -37,6 +38,7 @@ void ScriptInterpreterPythonInterfaces::Terminate() { ScriptedPlatformPythonInterface::Terminate(); ScriptedProcessPythonInterface::Terminate(); ScriptedStopHookPythonInterface::Terminate(); + ScriptedBreakpointPythonInterface::Terminate(); ScriptedThreadPlanPythonInterface::Terminate(); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h index 26c80b7..02dc065 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h @@ -16,6 +16,7 @@ #if LLDB_ENABLE_PYTHON #include "OperatingSystemPythonInterface.h" +#include "ScriptedBreakpointPythonInterface.h" #include "ScriptedPlatformPythonInterface.h" #include "ScriptedProcessPythonInterface.h" #include "ScriptedStopHookPythonInterface.h" diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp new file mode 100644 index 0000000..660edaa --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.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 "lldb/Core/PluginManager.h" +#include "lldb/Host/Config.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Log.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "../lldb-python.h" + +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" +#include "ScriptedBreakpointPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; + +ScriptedBreakpointPythonInterface::ScriptedBreakpointPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedBreakpointInterface(), ScriptedPythonInterface(interpreter) {} + +llvm::Expected<StructuredData::GenericSP> +ScriptedBreakpointPythonInterface::CreatePluginObject( + llvm::StringRef class_name, lldb::BreakpointSP break_sp, + const StructuredDataImpl &args_sp) { + return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, + break_sp, args_sp); +} + +bool ScriptedBreakpointPythonInterface::ResolverCallback( + SymbolContext sym_ctx) { + Status error; + + StructuredData::ObjectSP obj = Dispatch("__callback__", error, sym_ctx); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + Log *log = GetLog(LLDBLog::Script); + LLDB_LOG(log, "Error calling __callback__ method: {1}", error); + return true; + } + return obj->GetBooleanValue(); +} + +lldb::SearchDepth ScriptedBreakpointPythonInterface::GetDepth() { + Status error; + StructuredData::ObjectSP obj = Dispatch("__get_depth__", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + return lldb::eSearchDepthModule; + } + uint64_t value = obj->GetUnsignedIntegerValue(); + if (value <= lldb::kLastSearchDepthKind) + return (lldb::SearchDepth)value; + // This is what we were doing on error before, though I'm not sure that's + // better than returning eSearchDepthInvalid. + return lldb::eSearchDepthModule; +} + +std::optional<std::string> ScriptedBreakpointPythonInterface::GetShortHelp() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_short_help", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + return {}; + } + + return obj->GetAsString()->GetValue().str(); +} + +void ScriptedBreakpointPythonInterface::Initialize() { + const std::vector<llvm::StringRef> ci_usages = { + "breakpoint set -P classname [-k key -v value ...]"}; + const std::vector<llvm::StringRef> api_usages = { + "SBTarget.BreakpointCreateFromScript"}; + PluginManager::RegisterPlugin( + GetPluginNameStatic(), + llvm::StringRef("Create a breakpoint that chooses locations based on " + "user-created callbacks"), + CreateInstance, eScriptLanguagePython, {ci_usages, api_usages}); +} + +void ScriptedBreakpointPythonInterface::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h new file mode 100644 index 0000000..27bdd871 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h @@ -0,0 +1,53 @@ +//===-- ScriptedBreakpointPythonInterface.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_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" +#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedPythonInterface.h" + +namespace lldb_private { +class ScriptedBreakpointPythonInterface : public ScriptedBreakpointInterface, + public ScriptedPythonInterface, + public PluginInterface { +public: + ScriptedBreakpointPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, lldb::BreakpointSP break_sp, + const StructuredDataImpl &args_sp) override; + + llvm::SmallVector<AbstractMethodRequirement> + GetAbstractMethodRequirements() const override { + return llvm::SmallVector<AbstractMethodRequirement>({{"__callback__", 2}}); + } + + bool ResolverCallback(SymbolContext sym_ctx) override; + lldb::SearchDepth GetDepth() override; + std::optional<std::string> GetShortHelp() override; + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { + return "ScriptedBreakpointPythonInterface"; + } + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp index cf11c06..b49d1d8 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp @@ -17,6 +17,7 @@ #include "../ScriptInterpreterPythonImpl.h" #include "ScriptedPythonInterface.h" +#include "lldb/Symbol/SymbolContext.h" #include <optional> using namespace lldb; @@ -80,6 +81,20 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( } template <> +SymbolContext +ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>( + python::PythonObject &p, Status &error) { + if (lldb::SBSymbolContext *sb_symbol_context = + reinterpret_cast<lldb::SBSymbolContext *>( + python::LLDBSWIGPython_CastPyObjectToSBSymbolContext(p.get()))) + return m_interpreter.GetOpaqueTypeFromSBSymbolContext(*sb_symbol_context); + error = Status::FromErrorString( + "Couldn't cast lldb::SBSymbolContext to lldb_private::SymbolContext."); + + return {}; +} + +template <> lldb::DataExtractorSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( python::PythonObject &p, Status &error) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index b38b65e..f769d3d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -432,6 +432,10 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(lldb::BreakpointSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -452,6 +456,10 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(const SymbolContext &arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::StreamSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg.get()); } @@ -556,6 +564,11 @@ Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( python::PythonObject &p, Status &error); template <> +SymbolContext +ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>( + python::PythonObject &p, Status &error); + +template <> lldb::StreamSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( python::PythonObject &p, Status &error); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 504b3aa..4137786 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -151,15 +151,6 @@ public: const char *session_dictionary_name, lldb::DebuggerSP debugger_sp); - static python::PythonObject LLDBSwigPythonCreateScriptedBreakpointResolver( - const char *python_class_name, const char *session_dictionary_name, - const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp); - - static unsigned int - LLDBSwigPythonCallBreakpointResolver(void *implementor, - const char *method_name, - lldb_private::SymbolContext *sym_ctx); - static size_t LLDBSwigPython_CalculateNumChildren(PyObject *implementor, uint32_t max); @@ -270,6 +261,7 @@ void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data); +void *LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 457182a..ce77569 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1550,6 +1550,11 @@ ScriptInterpreterPythonImpl::CreateScriptedStopHookInterface() { return std::make_shared<ScriptedStopHookPythonInterface>(*this); } +ScriptedBreakpointInterfaceSP +ScriptInterpreterPythonImpl::CreateScriptedBreakpointInterface() { + return std::make_shared<ScriptedBreakpointPythonInterface>(*this); +} + ScriptedThreadInterfaceSP ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { return std::make_shared<ScriptedThreadPythonInterface>(*this); @@ -1576,75 +1581,6 @@ ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( return py_obj.CreateStructuredObject(); } -StructuredData::GenericSP -ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( - const char *class_name, const StructuredDataImpl &args_data, - lldb::BreakpointSP &bkpt_sp) { - - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::GenericSP(); - - if (!bkpt_sp.get()) - return StructuredData::GenericSP(); - - Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); - ScriptInterpreterPythonImpl *python_interpreter = - GetPythonInterpreter(debugger); - - if (!python_interpreter) - return StructuredData::GenericSP(); - - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - PythonObject ret_val = - SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( - class_name, python_interpreter->m_dictionary_name.c_str(), args_data, - bkpt_sp); - - return StructuredData::GenericSP( - new StructuredPythonObject(std::move(ret_val))); -} - -bool ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchCallback( - StructuredData::GenericSP implementor_sp, SymbolContext *sym_ctx) { - bool should_continue = false; - - if (implementor_sp) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_continue = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - implementor_sp->GetValue(), "__callback__", sym_ctx); - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - } - return should_continue; -} - -lldb::SearchDepth -ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( - StructuredData::GenericSP implementor_sp) { - int depth_as_int = lldb::eSearchDepthModule; - if (implementor_sp) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - depth_as_int = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - implementor_sp->GetValue(), "__get_depth__", nullptr); - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - } - if (depth_as_int == lldb::eSearchDepthInvalid) - return lldb::eSearchDepthModule; - - if (depth_as_int <= lldb::kLastSearchDepthKind) - return (lldb::SearchDepth)depth_as_int; - return lldb::eSearchDepthModule; -} - StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 5d77608..4698b82a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -81,17 +81,6 @@ public: CreateStructuredDataFromScriptObject(ScriptObject obj) override; StructuredData::GenericSP - CreateScriptedBreakpointResolver(const char *class_name, - const StructuredDataImpl &args_data, - lldb::BreakpointSP &bkpt_sp) override; - bool ScriptedBreakpointResolverSearchCallback( - StructuredData::GenericSP implementor_sp, - SymbolContext *sym_ctx) override; - - lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( - StructuredData::GenericSP implementor_sp) override; - - StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; lldb::ValueObjectListSP @@ -105,6 +94,9 @@ public: lldb::ScriptedStopHookInterfaceSP CreateScriptedStopHookInterface() override; + lldb::ScriptedBreakpointInterfaceSP + CreateScriptedBreakpointInterface() override; + lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; lldb::ScriptedThreadPlanInterfaceSP diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 8000cd0..e9d9c8f 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -2076,6 +2076,13 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, trap_opcode_size = sizeof(g_loongarch_opcode); } break; + case llvm::Triple::wasm32: { + // Unreachable (0x00) triggers an unconditional trap. + static const uint8_t g_wasm_opcode[] = {0x00}; + trap_opcode = g_wasm_opcode; + trap_opcode_size = sizeof(g_wasm_opcode); + } break; + default: return 0; } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 823b4b5..4f39f60 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -36,6 +36,7 @@ #include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h" #include "lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h" #include "lldb/Interpreter/OptionGroupWatchpoint.h" #include "lldb/Interpreter/OptionValues.h" |