diff options
Diffstat (limited to 'lldb/source/Plugins/Process/Utility')
7 files changed, 188 insertions, 10 deletions
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt index 5d99c22dafe1..b1e326ec064e 100644 --- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt @@ -13,6 +13,7 @@ add_lldb_library(lldbPluginProcessUtility MemoryTagManagerAArch64MTE.cpp NativeProcessSoftwareSingleStep.cpp NativeRegisterContextDBReg.cpp + NativeRegisterContextDBReg_arm.cpp NativeRegisterContextDBReg_arm64.cpp NativeRegisterContextDBReg_loongarch.cpp NativeRegisterContextDBReg_x86.cpp diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp index 19601b7f35d4..f35027e93514 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp @@ -44,15 +44,16 @@ uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr, return LLDB_INVALID_INDEX32; } - uint32_t control_value = 0, bp_index = 0; - if (!ValidateBreakpoint(size, addr)) return LLDB_INVALID_INDEX32; - control_value = MakeBreakControlValue(size); + uint32_t control_value = MakeBreakControlValue(size); + auto details = AdjustBreakpoint({size, addr}); + size = details.size; + addr = details.addr; // Iterate over stored breakpoints and find a free bp_index - bp_index = LLDB_INVALID_INDEX32; + uint32_t bp_index = LLDB_INVALID_INDEX32; for (uint32_t i = 0; i < m_max_hbp_supported; i++) { if (!BreakpointIsEnabled(i)) bp_index = i; // Mark last free slot @@ -222,7 +223,7 @@ uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint( addr = adjusted->addr; // Check if we are setting watchpoint other than read/write/access Also - // update watchpoint flag to match AArch64/LoongArch write-read bit + // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit // configuration. switch (watch_flags) { case lldb::eWatchpointKindWrite: diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h index 9b6ecd382c3f..2dd11dcf74de 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h @@ -12,6 +12,7 @@ #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" #include <array> +#include <optional> // Common utilities for hardware breakpoints and hardware watchpoints on AArch64 // and LoongArch. @@ -76,19 +77,25 @@ protected: // On AArch64 and Loongarch the hardware breakpoint length size is 4, and the // target address must 4-byte alignment. - bool ValidateBreakpoint(size_t size, lldb::addr_t addr) { + virtual bool ValidateBreakpoint(size_t size, lldb::addr_t addr) { return (size == 4) && !(addr & 0x3); } + struct WatchpointDetails { size_t size; lldb::addr_t addr; }; virtual std::optional<WatchpointDetails> AdjustWatchpoint(const WatchpointDetails &details) = 0; + + using BreakpointDetails = WatchpointDetails; + virtual BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) { + return details; + } + virtual uint32_t MakeBreakControlValue(size_t size) = 0; virtual uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) = 0; virtual uint32_t GetWatchpointSize(uint32_t wp_index) = 0; - virtual llvm::Error ReadHardwareDebugInfo() = 0; virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0; virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) { diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp new file mode 100644 index 000000000000..803fed54d6b0 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.cpp @@ -0,0 +1,117 @@ +//===-- NativeRegisterContextDBReg_arm.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 +// +//===----------------------------------------------------------------------===// + +#include "NativeRegisterContextDBReg_arm.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" + +using namespace lldb_private; + +uint32_t NativeRegisterContextDBReg_arm::GetWatchpointSize(uint32_t wp_index) { + Log *log = GetLog(LLDBLog::Watchpoints); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + switch ((m_hwp_regs[wp_index].control >> 5) & 0x0f) { + case 0x01: + return 1; + case 0x03: + return 2; + case 0x07: + return 3; + case 0x0f: + return 4; + default: + return 0; + } +} + +std::optional<NativeRegisterContextDBReg::WatchpointDetails> +NativeRegisterContextDBReg_arm::AdjustWatchpoint( + const WatchpointDetails &details) { + auto [size, addr] = details; + + if (size == 0 || size > 4) + return {}; + + // Check 4-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 4-byte aligned addresses as well. + if (addr & 0x03) { + uint8_t watch_mask = (addr & 0x03) + size; + if (watch_mask > 0x04) + return {}; + else if (watch_mask <= 0x02) + size = 2; + else + size = 4; + + addr = addr & (~0x03); + } + + return WatchpointDetails{size, addr}; +} + +NativeRegisterContextDBReg::BreakpointDetails +NativeRegisterContextDBReg_arm::AdjustBreakpoint( + const BreakpointDetails &details) { + BreakpointDetails bd = details; + // Use size to get a hint of arm vs thumb modes. + // LLDB usually aligns this client side, but other clients may not. + switch (bd.size) { + case 2: + bd.addr &= ~1; + break; + case 4: + bd.addr &= ~3; + break; + default: + // We assume that ValidateBreakpoint would have caught this earlier. + llvm_unreachable("Invalid breakpoint size!"); + } + + return bd; +} + +uint32_t NativeRegisterContextDBReg_arm::MakeBreakControlValue(size_t size) { + switch (size) { + case 2: + return (0x3 << 5) | 7; + case 4: + return (0xfu << 5) | 7; + default: + // ValidateBreakpoint would have rejected this earlier. + llvm_unreachable("Invalid breakpoint size."); + } +} + +uint32_t +NativeRegisterContextDBReg_arm::MakeWatchControlValue(size_t size, + uint32_t watch_flags) { + // We can only watch up to four bytes that follow a 4 byte aligned address + // per watchpoint register pair, so make sure we can properly encode this. + // We assume that the address was 4 byte aligned by AdjustWatchpoint. + uint32_t byte_mask = (1u << size) - 1u; + + // Check if we need multiple watchpoint register + if (byte_mask > 0xfu) + return LLDB_INVALID_INDEX32; + + // Setup control value + // Make the byte_mask into a valid Byte Address Select mask + uint32_t control_value = byte_mask << 5; + + // Turn on appropriate watchpoint flags read or write + control_value |= (watch_flags << 3); + + // Enable this watchpoint and make it stop in privileged or user mode; + control_value |= 7; + + return control_value; +} diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h new file mode 100644 index 000000000000..253ae96c90c9 --- /dev/null +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm.h @@ -0,0 +1,42 @@ +//===-- NativeRegisterContextDBReg_arm.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_NativeRegisterContextDBReg_arm_h +#define lldb_NativeRegisterContextDBReg_arm_h + +#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h" + +namespace lldb_private { + +class NativeRegisterContextDBReg_arm : public NativeRegisterContextDBReg { +public: + NativeRegisterContextDBReg_arm() + : NativeRegisterContextDBReg(/*enable_bit=*/0x1U) {} + +private: + uint32_t GetWatchpointSize(uint32_t wp_index) override; + + std::optional<WatchpointDetails> + AdjustWatchpoint(const WatchpointDetails &details) override; + + BreakpointDetails AdjustBreakpoint(const BreakpointDetails &details) override; + + uint32_t MakeBreakControlValue(size_t size) override; + + uint32_t MakeWatchControlValue(size_t size, uint32_t watch_flags) override; + + bool ValidateBreakpoint(size_t size, + [[maybe_unused]] lldb::addr_t addr) override { + // Break on 4 or 2 byte instructions. + return size == 4 || size == 2; + } +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextDBReg_arm_h diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index fbf128553fd5..3b8d6a84c964 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -79,7 +79,7 @@ static lldb_private::RegisterInfo g_register_infos_mte[] = { DEFINE_EXTENSION_REG(mte_ctrl)}; static lldb_private::RegisterInfo g_register_infos_tls[] = { - DEFINE_EXTENSION_REG(tpidr), + DEFINE_EXTENSION_REG_GENERIC(tpidr, LLDB_REGNUM_GENERIC_TP), // Only present when SME is present DEFINE_EXTENSION_REG(tpidr2)}; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h index c9c4d7ceae55..829fa076d221 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -456,6 +456,7 @@ static uint32_t g_d29_invalidates[] = {fpu_v29, fpu_s29, LLDB_INVALID_REGNUM}; static uint32_t g_d30_invalidates[] = {fpu_v30, fpu_s30, LLDB_INVALID_REGNUM}; static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; +// clang-format off // Generates register kinds array with DWARF, EH frame and generic kind #define MISC_KIND(reg, type, generic_kind) \ { \ @@ -470,6 +471,11 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; LLDB_INVALID_REGNUM, lldb_kind \ } +#define GENERIC_KIND(genenric_kind) \ + { \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, genenric_kind, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \ + } // Generates register kinds array for registers with only lldb kind #define KIND_ALL_INVALID \ { \ @@ -484,8 +490,6 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; #define MISC_FPU_KIND(lldb_kind) LLDB_KIND(lldb_kind) #define MISC_EXC_KIND(lldb_kind) LLDB_KIND(lldb_kind) -// clang-format off - // Defines a 64-bit general purpose register #define DEFINE_GPR64(reg, generic_kind) \ { \ @@ -540,6 +544,12 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \ KIND_ALL_INVALID, nullptr, nullptr, nullptr, \ } + +#define DEFINE_EXTENSION_REG_GENERIC(reg, generic_kind) \ + { \ + #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \ + GENERIC_KIND(generic_kind), nullptr, nullptr, nullptr, \ + } static lldb_private::RegisterInfo g_register_infos_arm64_le[] = { // DEFINE_GPR64(name, GENERIC KIND) |
