Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.cpp
213845 views
//===-- NativeRegisterContextDBReg.cpp ------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "NativeRegisterContextDBReg.h"910#include "lldb/Utility/LLDBLog.h"11#include "lldb/Utility/Log.h"12#include "lldb/Utility/RegisterValue.h"1314using namespace lldb_private;1516uint32_t NativeRegisterContextDBReg::NumSupportedHardwareBreakpoints() {17Log *log = GetLog(LLDBLog::Breakpoints);1819// Read hardware breakpoint and watchpoint information.20llvm::Error error = ReadHardwareDebugInfo();2122if (error) {23LLDB_LOG_ERROR(log, std::move(error),24"failed to read debug registers: {0}");25return 0;26}2728LLDB_LOG(log, "{0}", m_max_hbp_supported);29return m_max_hbp_supported;30}3132uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,33size_t size) {34Log *log = GetLog(LLDBLog::Breakpoints);35LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);3637// Read hardware breakpoint and watchpoint information.38llvm::Error error = ReadHardwareDebugInfo();39if (error) {40LLDB_LOG_ERROR(41log, std::move(error),42"unable to set breakpoint: failed to read debug registers: {0}");43return LLDB_INVALID_INDEX32;44}4546uint32_t control_value = 0, bp_index = 0;4748if (!ValidateBreakpoint(size, addr))49return LLDB_INVALID_INDEX32;5051control_value = MakeBreakControlValue(size);5253// Iterate over stored breakpoints and find a free bp_index54bp_index = LLDB_INVALID_INDEX32;55for (uint32_t i = 0; i < m_max_hbp_supported; i++) {56if (!BreakpointIsEnabled(i))57bp_index = i; // Mark last free slot58else if (m_hbp_regs[i].address == addr)59return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.60}6162if (bp_index == LLDB_INVALID_INDEX32)63return LLDB_INVALID_INDEX32;6465// Update breakpoint in local cache66m_hbp_regs[bp_index].real_addr = addr;67m_hbp_regs[bp_index].address = addr;68m_hbp_regs[bp_index].control = control_value;6970// PTRACE call to set corresponding hardware breakpoint register.71error = WriteHardwareDebugRegs(eDREGTypeBREAK);7273if (error) {74m_hbp_regs[bp_index].address = 0;75m_hbp_regs[bp_index].control &= ~m_hw_dbg_enable_bit;7677LLDB_LOG_ERROR(78log, std::move(error),79"unable to set breakpoint: failed to write debug registers: {0}");80return LLDB_INVALID_INDEX32;81}8283return bp_index;84}8586bool NativeRegisterContextDBReg::ClearHardwareBreakpoint(uint32_t hw_idx) {87Log *log = GetLog(LLDBLog::Breakpoints);88LLDB_LOG(log, "hw_idx: {0}", hw_idx);8990// Read hardware breakpoint and watchpoint information.91llvm::Error error = ReadHardwareDebugInfo();92if (error) {93LLDB_LOG_ERROR(94log, std::move(error),95"unable to clear breakpoint: failed to read debug registers: {0}");96return false;97}9899if (hw_idx >= m_max_hbp_supported)100return false;101102// Create a backup we can revert to in case of failure.103lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;104uint32_t tempControl = m_hbp_regs[hw_idx].control;105106m_hbp_regs[hw_idx].control &= ~m_hw_dbg_enable_bit;107m_hbp_regs[hw_idx].address = 0;108109// PTRACE call to clear corresponding hardware breakpoint register.110error = WriteHardwareDebugRegs(eDREGTypeBREAK);111112if (error) {113m_hbp_regs[hw_idx].control = tempControl;114m_hbp_regs[hw_idx].address = tempAddr;115116LLDB_LOG_ERROR(117log, std::move(error),118"unable to clear breakpoint: failed to write debug registers: {0}");119return false;120}121122return true;123}124125Status126NativeRegisterContextDBReg::GetHardwareBreakHitIndex(uint32_t &bp_index,127lldb::addr_t trap_addr) {128Log *log = GetLog(LLDBLog::Breakpoints);129130LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);131132lldb::addr_t break_addr;133134for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {135break_addr = m_hbp_regs[bp_index].address;136137if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {138m_hbp_regs[bp_index].hit_addr = trap_addr;139return Status();140}141}142143bp_index = LLDB_INVALID_INDEX32;144return Status();145}146147Status NativeRegisterContextDBReg::ClearAllHardwareBreakpoints() {148Log *log = GetLog(LLDBLog::Breakpoints);149150LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);151152// Read hardware breakpoint and watchpoint information.153llvm::Error error = ReadHardwareDebugInfo();154if (error)155return Status::FromError(std::move(error));156157for (uint32_t i = 0; i < m_max_hbp_supported; i++) {158if (!BreakpointIsEnabled(i))159continue;160// Create a backup we can revert to in case of failure.161lldb::addr_t tempAddr = m_hbp_regs[i].address;162uint32_t tempControl = m_hbp_regs[i].control;163164// Clear watchpoints in local cache165m_hbp_regs[i].control &= ~m_hw_dbg_enable_bit;166m_hbp_regs[i].address = 0;167168// Ptrace call to update hardware debug registers169error = WriteHardwareDebugRegs(eDREGTypeBREAK);170171if (error) {172m_hbp_regs[i].control = tempControl;173m_hbp_regs[i].address = tempAddr;174175return Status::FromError(std::move(error));176}177}178179return Status();180}181182bool NativeRegisterContextDBReg::BreakpointIsEnabled(uint32_t bp_index) {183return ((m_hbp_regs[bp_index].control & m_hw_dbg_enable_bit) != 0);184}185186uint32_t NativeRegisterContextDBReg::NumSupportedHardwareWatchpoints() {187Log *log = GetLog(LLDBLog::Watchpoints);188llvm::Error error = ReadHardwareDebugInfo();189if (error) {190LLDB_LOG_ERROR(log, std::move(error),191"failed to read debug registers: {0}");192return 0;193}194195return m_max_hwp_supported;196}197198uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(199lldb::addr_t addr, size_t size, uint32_t watch_flags) {200Log *log = GetLog(LLDBLog::Watchpoints);201LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,202watch_flags);203204// Read hardware breakpoint and watchpoint information.205llvm::Error error = ReadHardwareDebugInfo();206if (error) {207LLDB_LOG_ERROR(208log, std::move(error),209"unable to set watchpoint: failed to read debug registers: {0}");210return LLDB_INVALID_INDEX32;211}212213uint32_t control_value = 0, wp_index = 0;214lldb::addr_t real_addr = addr;215WatchpointDetails details{size, addr};216217auto adjusted = AdjustWatchpoint(details);218if (adjusted == std::nullopt)219return LLDB_INVALID_INDEX32;220size = adjusted->size;221addr = adjusted->addr;222223// Check if we are setting watchpoint other than read/write/access Also224// update watchpoint flag to match AArch64/LoongArch write-read bit225// configuration.226switch (watch_flags) {227case lldb::eWatchpointKindWrite:228watch_flags = 2;229break;230case lldb::eWatchpointKindRead:231watch_flags = 1;232break;233case (lldb::eWatchpointKindRead | lldb::eWatchpointKindWrite):234break;235default:236return LLDB_INVALID_INDEX32;237}238239control_value = MakeWatchControlValue(size, watch_flags);240241// Iterate over stored watchpoints and find a free wp_index242wp_index = LLDB_INVALID_INDEX32;243for (uint32_t i = 0; i < m_max_hwp_supported; i++) {244if (!WatchpointIsEnabled(i))245wp_index = i; // Mark last free slot246else if (m_hwp_regs[i].address == addr) {247return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.248}249}250251if (wp_index == LLDB_INVALID_INDEX32)252return LLDB_INVALID_INDEX32;253254// Update watchpoint in local cache255m_hwp_regs[wp_index].real_addr = real_addr;256m_hwp_regs[wp_index].address = addr;257m_hwp_regs[wp_index].control = control_value;258259// PTRACE call to set corresponding watchpoint register.260error = WriteHardwareDebugRegs(eDREGTypeWATCH);261262if (error) {263m_hwp_regs[wp_index].address = 0;264m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;265266LLDB_LOG_ERROR(267log, std::move(error),268"unable to set watchpoint: failed to write debug registers: {0}");269return LLDB_INVALID_INDEX32;270}271272return wp_index;273}274275bool NativeRegisterContextDBReg::ClearHardwareWatchpoint(uint32_t wp_index) {276Log *log = GetLog(LLDBLog::Watchpoints);277LLDB_LOG(log, "wp_index: {0}", wp_index);278279// Read hardware breakpoint and watchpoint information.280llvm::Error error = ReadHardwareDebugInfo();281if (error) {282LLDB_LOG_ERROR(283log, std::move(error),284"unable to set watchpoint: failed to read debug registers: {0}");285return false;286}287288if (wp_index >= m_max_hwp_supported)289return false;290291// Create a backup we can revert to in case of failure.292lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;293uint32_t tempControl = m_hwp_regs[wp_index].control;294295// Update watchpoint in local cache296m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;297m_hwp_regs[wp_index].address = 0;298299// Ptrace call to update hardware debug registers300error = WriteHardwareDebugRegs(eDREGTypeWATCH);301302if (error) {303m_hwp_regs[wp_index].control = tempControl;304m_hwp_regs[wp_index].address = tempAddr;305306LLDB_LOG_ERROR(307log, std::move(error),308"unable to clear watchpoint: failed to read debug registers: {0}");309return false;310}311312return true;313}314315Status NativeRegisterContextDBReg::ClearAllHardwareWatchpoints() {316// Read hardware breakpoint and watchpoint information.317llvm::Error error = ReadHardwareDebugInfo();318if (error)319return Status::FromError(std::move(error));320321for (uint32_t i = 0; i < m_max_hwp_supported; i++) {322if (!WatchpointIsEnabled(i))323continue;324// Create a backup we can revert to in case of failure.325lldb::addr_t tempAddr = m_hwp_regs[i].address;326uint32_t tempControl = m_hwp_regs[i].control;327328// Clear watchpoints in local cache329m_hwp_regs[i].control = 0;330m_hwp_regs[i].address = 0;331332// Ptrace call to update hardware debug registers333error = WriteHardwareDebugRegs(eDREGTypeWATCH);334335if (error) {336m_hwp_regs[i].control = tempControl;337m_hwp_regs[i].address = tempAddr;338339return Status::FromError(std::move(error));340}341}342343return Status();344}345346Status347NativeRegisterContextDBReg::GetWatchpointHitIndex(uint32_t &wp_index,348lldb::addr_t trap_addr) {349Log *log = GetLog(LLDBLog::Watchpoints);350LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);351352// Read hardware breakpoint and watchpoint information.353llvm::Error error = ReadHardwareDebugInfo();354if (error)355return Status::FromError(std::move(error));356357// AArch64 need mask off ignored bits from watchpoint trap address.358trap_addr = FixWatchpointHitAddress(trap_addr);359360uint32_t watch_size;361lldb::addr_t watch_addr;362363for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {364watch_size = GetWatchpointSize(wp_index);365watch_addr = m_hwp_regs[wp_index].address;366367if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&368trap_addr < watch_addr + watch_size) {369m_hwp_regs[wp_index].hit_addr = trap_addr;370return Status();371}372}373374wp_index = LLDB_INVALID_INDEX32;375return Status();376}377378bool NativeRegisterContextDBReg::WatchpointIsEnabled(uint32_t wp_index) {379Log *log = GetLog(LLDBLog::Watchpoints);380LLDB_LOG(log, "wp_index: {0}", wp_index);381return ((m_hwp_regs[wp_index].control & m_hw_dbg_enable_bit) != 0);382}383384lldb::addr_t385NativeRegisterContextDBReg::GetWatchpointAddress(uint32_t wp_index) {386Log *log = GetLog(LLDBLog::Watchpoints);387LLDB_LOG(log, "wp_index: {0}", wp_index);388389if (wp_index >= m_max_hwp_supported)390return LLDB_INVALID_ADDRESS;391392if (WatchpointIsEnabled(wp_index))393return m_hwp_regs[wp_index].real_addr;394return LLDB_INVALID_ADDRESS;395}396397lldb::addr_t398NativeRegisterContextDBReg::GetWatchpointHitAddress(uint32_t wp_index) {399Log *log = GetLog(LLDBLog::Watchpoints);400LLDB_LOG(log, "wp_index: {0}", wp_index);401402if (wp_index >= m_max_hwp_supported)403return LLDB_INVALID_ADDRESS;404405if (WatchpointIsEnabled(wp_index))406return m_hwp_regs[wp_index].hit_addr;407return LLDB_INVALID_ADDRESS;408}409410411