| //===-- SBWatchpoint.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 "lldb/API/SBWatchpoint.h" | |
| #include "lldb/API/SBAddress.h" | |
| #include "lldb/API/SBDebugger.h" | |
| #include "lldb/API/SBDefines.h" | |
| #include "lldb/API/SBEvent.h" | |
| #include "lldb/API/SBStream.h" | |
| #include "lldb/Utility/Instrumentation.h" | |
| #include "lldb/Breakpoint/Watchpoint.h" | |
| #include "lldb/Breakpoint/WatchpointList.h" | |
| #include "lldb/Symbol/CompilerType.h" | |
| #include "lldb/Target/Process.h" | |
| #include "lldb/Target/Target.h" | |
| #include "lldb/Utility/Stream.h" | |
| #include "lldb/lldb-defines.h" | |
| #include "lldb/lldb-types.h" | |
| using namespace lldb; | |
| using namespace lldb_private; | |
| SBWatchpoint::SBWatchpoint() { LLDB_INSTRUMENT_VA(this); } | |
| SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp) | |
| : m_opaque_wp(wp_sp) { | |
| LLDB_INSTRUMENT_VA(this, wp_sp); | |
| } | |
| SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs) | |
| : m_opaque_wp(rhs.m_opaque_wp) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| } | |
| const SBWatchpoint &SBWatchpoint::operator=(const SBWatchpoint &rhs) { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| m_opaque_wp = rhs.m_opaque_wp; | |
| return *this; | |
| } | |
| SBWatchpoint::~SBWatchpoint() = default; | |
| watch_id_t SBWatchpoint::GetID() { | |
| LLDB_INSTRUMENT_VA(this); | |
| watch_id_t watch_id = LLDB_INVALID_WATCH_ID; | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) | |
| watch_id = watchpoint_sp->GetID(); | |
| return watch_id; | |
| } | |
| bool SBWatchpoint::IsValid() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| return this->operator bool(); | |
| } | |
| SBWatchpoint::operator bool() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| return bool(m_opaque_wp.lock()); | |
| } | |
| bool SBWatchpoint::operator==(const SBWatchpoint &rhs) const { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| return GetSP() == rhs.GetSP(); | |
| } | |
| bool SBWatchpoint::operator!=(const SBWatchpoint &rhs) const { | |
| LLDB_INSTRUMENT_VA(this, rhs); | |
| return !(*this == rhs); | |
| } | |
| SBError SBWatchpoint::GetError() { | |
| LLDB_INSTRUMENT_VA(this); | |
| SBError sb_error; | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| sb_error.SetError(watchpoint_sp->GetError().Clone()); | |
| } | |
| return sb_error; | |
| } | |
| int32_t SBWatchpoint::GetHardwareIndex() { | |
| LLDB_INSTRUMENT_VA(this); | |
| // For processes using gdb remote protocol, | |
| // we cannot determine the hardware breakpoint | |
| // index reliably; providing possibly correct | |
| // guesses is not useful to anyone. | |
| return -1; | |
| } | |
| addr_t SBWatchpoint::GetWatchAddress() { | |
| LLDB_INSTRUMENT_VA(this); | |
| addr_t ret_addr = LLDB_INVALID_ADDRESS; | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| ret_addr = watchpoint_sp->GetLoadAddress(); | |
| } | |
| return ret_addr; | |
| } | |
| size_t SBWatchpoint::GetWatchSize() { | |
| LLDB_INSTRUMENT_VA(this); | |
| size_t watch_size = 0; | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| watch_size = watchpoint_sp->GetByteSize(); | |
| } | |
| return watch_size; | |
| } | |
| void SBWatchpoint::SetEnabled(bool enabled) { | |
| LLDB_INSTRUMENT_VA(this, enabled); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| Target &target = watchpoint_sp->GetTarget(); | |
| TargetAPIMutex api_lock = target.GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| ProcessSP process_sp = target.GetProcessSP(); | |
| const bool notify = true; | |
| if (process_sp) { | |
| if (enabled) | |
| process_sp->EnableWatchpoint(watchpoint_sp, notify); | |
| else | |
| process_sp->DisableWatchpoint(watchpoint_sp, notify); | |
| } else { | |
| watchpoint_sp->SetEnabled(enabled, notify); | |
| } | |
| } | |
| } | |
| bool SBWatchpoint::IsEnabled() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| return watchpoint_sp->IsEnabled(); | |
| } else | |
| return false; | |
| } | |
| uint32_t SBWatchpoint::GetHitCount() { | |
| LLDB_INSTRUMENT_VA(this); | |
| uint32_t count = 0; | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| count = watchpoint_sp->GetHitCount(); | |
| } | |
| return count; | |
| } | |
| uint32_t SBWatchpoint::GetIgnoreCount() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| return watchpoint_sp->GetIgnoreCount(); | |
| } else | |
| return 0; | |
| } | |
| void SBWatchpoint::SetIgnoreCount(uint32_t n) { | |
| LLDB_INSTRUMENT_VA(this, n); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| watchpoint_sp->SetIgnoreCount(n); | |
| } | |
| } | |
| const char *SBWatchpoint::GetCondition() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (!watchpoint_sp) | |
| return nullptr; | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| return ConstString(watchpoint_sp->GetConditionText()).GetCString(); | |
| } | |
| void SBWatchpoint::SetCondition(const char *condition) { | |
| LLDB_INSTRUMENT_VA(this, condition); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| watchpoint_sp->SetCondition(condition); | |
| } | |
| } | |
| bool SBWatchpoint::GetDescription(SBStream &description, | |
| DescriptionLevel level) { | |
| LLDB_INSTRUMENT_VA(this, description, level); | |
| Stream &strm = description.ref(); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| watchpoint_sp->GetDescription(&strm, level); | |
| strm.EOL(); | |
| } else | |
| strm.PutCString("No value"); | |
| return true; | |
| } | |
| void SBWatchpoint::Clear() { | |
| LLDB_INSTRUMENT_VA(this); | |
| m_opaque_wp.reset(); | |
| } | |
| lldb::WatchpointSP SBWatchpoint::GetSP() const { | |
| LLDB_INSTRUMENT_VA(this); | |
| return m_opaque_wp.lock(); | |
| } | |
| void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) { | |
| LLDB_INSTRUMENT_VA(this, sp); | |
| m_opaque_wp = sp; | |
| } | |
| bool SBWatchpoint::EventIsWatchpointEvent(const lldb::SBEvent &event) { | |
| LLDB_INSTRUMENT_VA(event); | |
| return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event.get()) != | |
| nullptr; | |
| } | |
| WatchpointEventType | |
| SBWatchpoint::GetWatchpointEventTypeFromEvent(const SBEvent &event) { | |
| LLDB_INSTRUMENT_VA(event); | |
| if (event.IsValid()) | |
| return Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent( | |
| event.GetSP()); | |
| return eWatchpointEventTypeInvalidType; | |
| } | |
| SBWatchpoint SBWatchpoint::GetWatchpointFromEvent(const lldb::SBEvent &event) { | |
| LLDB_INSTRUMENT_VA(event); | |
| SBWatchpoint sb_watchpoint; | |
| if (event.IsValid()) | |
| sb_watchpoint = | |
| Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP()); | |
| return sb_watchpoint; | |
| } | |
| lldb::SBType SBWatchpoint::GetType() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| const CompilerType &type = watchpoint_sp->GetCompilerType(); | |
| return lldb::SBType(type); | |
| } | |
| return lldb::SBType(); | |
| } | |
| WatchpointValueKind SBWatchpoint::GetWatchValueKind() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| if (watchpoint_sp->IsWatchVariable()) | |
| return WatchpointValueKind::eWatchPointValueKindVariable; | |
| return WatchpointValueKind::eWatchPointValueKindExpression; | |
| } | |
| return WatchpointValueKind::eWatchPointValueKindInvalid; | |
| } | |
| const char *SBWatchpoint::GetWatchSpec() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (!watchpoint_sp) | |
| return nullptr; | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| // Store the result of `GetWatchSpec()` as a ConstString | |
| // so that the C string we return has a sufficiently long | |
| // lifetime. Note this a memory leak but should be fairly | |
| // low impact. | |
| return ConstString(watchpoint_sp->GetWatchSpec()).AsCString(nullptr); | |
| } | |
| bool SBWatchpoint::IsWatchingReads() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| return watchpoint_sp->WatchpointRead(); | |
| } | |
| return false; | |
| } | |
| bool SBWatchpoint::IsWatchingWrites() { | |
| LLDB_INSTRUMENT_VA(this); | |
| lldb::WatchpointSP watchpoint_sp(GetSP()); | |
| if (watchpoint_sp) { | |
| TargetAPIMutex api_lock = watchpoint_sp->GetTarget().GetAPIMutex(); | |
| std::lock_guard<TargetAPIMutex> guard(api_lock); | |
| return watchpoint_sp->WatchpointWrite() || | |
| watchpoint_sp->WatchpointModify(); | |
| } | |
| return false; | |
| } |