1//===-- SBWatchpoint.cpp --------------------------------------------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "lldb/API/SBWatchpoint.h" 10#include "lldb/API/SBAddress.h" 11#include "lldb/API/SBDebugger.h" 12#include "lldb/API/SBDefines.h" 13#include "lldb/API/SBEvent.h" 14#include "lldb/API/SBStream.h" 15#include "lldb/Utility/Instrumentation.h" 16 17#include "lldb/Breakpoint/Watchpoint.h" 18#include "lldb/Breakpoint/WatchpointList.h" 19#include "lldb/Symbol/CompilerType.h" 20#include "lldb/Target/Process.h" 21#include "lldb/Target/Target.h" 22#include "lldb/Utility/Stream.h" 23#include "lldb/lldb-defines.h" 24#include "lldb/lldb-types.h" 25 26using namespace lldb; 27using namespace lldb_private; 28 29SBWatchpoint::SBWatchpoint() { LLDB_INSTRUMENT_VA(this); } 30 31SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp) 32 : m_opaque_wp(wp_sp) { 33 LLDB_INSTRUMENT_VA(this, wp_sp); 34} 35 36SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs) 37 : m_opaque_wp(rhs.m_opaque_wp) { 38 LLDB_INSTRUMENT_VA(this, rhs); 39} 40 41const SBWatchpoint &SBWatchpoint::operator=(const SBWatchpoint &rhs) { 42 LLDB_INSTRUMENT_VA(this, rhs); 43 44 m_opaque_wp = rhs.m_opaque_wp; 45 return *this; 46} 47 48SBWatchpoint::~SBWatchpoint() = default; 49 50watch_id_t SBWatchpoint::GetID() { 51 LLDB_INSTRUMENT_VA(this); 52 53 watch_id_t watch_id = LLDB_INVALID_WATCH_ID; 54 lldb::WatchpointSP watchpoint_sp(GetSP()); 55 if (watchpoint_sp) 56 watch_id = watchpoint_sp->GetID(); 57 58 return watch_id; 59} 60 61bool SBWatchpoint::IsValid() const { 62 LLDB_INSTRUMENT_VA(this); 63 return this->operator bool(); 64} 65SBWatchpoint::operator bool() const { 66 LLDB_INSTRUMENT_VA(this); 67 68 return bool(m_opaque_wp.lock()); 69} 70 71bool SBWatchpoint::operator==(const SBWatchpoint &rhs) const { 72 LLDB_INSTRUMENT_VA(this, rhs); 73 74 return GetSP() == rhs.GetSP(); 75} 76 77bool SBWatchpoint::operator!=(const SBWatchpoint &rhs) const { 78 LLDB_INSTRUMENT_VA(this, rhs); 79 80 return !(*this == rhs); 81} 82 83SBError SBWatchpoint::GetError() { 84 LLDB_INSTRUMENT_VA(this); 85 86 SBError sb_error; 87 lldb::WatchpointSP watchpoint_sp(GetSP()); 88 if (watchpoint_sp) { 89 sb_error.SetError(watchpoint_sp->GetError()); 90 } 91 return sb_error; 92} 93 94int32_t SBWatchpoint::GetHardwareIndex() { 95 LLDB_INSTRUMENT_VA(this); 96 97 // For processes using gdb remote protocol, 98 // we cannot determine the hardware breakpoint 99 // index reliably; providing possibly correct 100 // guesses is not useful to anyone. 101 return -1; 102} 103 104addr_t SBWatchpoint::GetWatchAddress() { 105 LLDB_INSTRUMENT_VA(this); 106 107 addr_t ret_addr = LLDB_INVALID_ADDRESS; 108 109 lldb::WatchpointSP watchpoint_sp(GetSP()); 110 if (watchpoint_sp) { 111 std::lock_guard<std::recursive_mutex> guard( 112 watchpoint_sp->GetTarget().GetAPIMutex()); 113 ret_addr = watchpoint_sp->GetLoadAddress(); 114 } 115 116 return ret_addr; 117} 118 119size_t SBWatchpoint::GetWatchSize() { 120 LLDB_INSTRUMENT_VA(this); 121 122 size_t watch_size = 0; 123 124 lldb::WatchpointSP watchpoint_sp(GetSP()); 125 if (watchpoint_sp) { 126 std::lock_guard<std::recursive_mutex> guard( 127 watchpoint_sp->GetTarget().GetAPIMutex()); 128 watch_size = watchpoint_sp->GetByteSize(); 129 } 130 131 return watch_size; 132} 133 134void SBWatchpoint::SetEnabled(bool enabled) { 135 LLDB_INSTRUMENT_VA(this, enabled); 136 137 lldb::WatchpointSP watchpoint_sp(GetSP()); 138 if (watchpoint_sp) { 139 Target &target = watchpoint_sp->GetTarget(); 140 std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex()); 141 ProcessSP process_sp = target.GetProcessSP(); 142 const bool notify = true; 143 if (process_sp) { 144 if (enabled) 145 process_sp->EnableWatchpoint(watchpoint_sp, notify); 146 else 147 process_sp->DisableWatchpoint(watchpoint_sp, notify); 148 } else { 149 watchpoint_sp->SetEnabled(enabled, notify); 150 } 151 } 152} 153 154bool SBWatchpoint::IsEnabled() { 155 LLDB_INSTRUMENT_VA(this); 156 157 lldb::WatchpointSP watchpoint_sp(GetSP()); 158 if (watchpoint_sp) { 159 std::lock_guard<std::recursive_mutex> guard( 160 watchpoint_sp->GetTarget().GetAPIMutex()); 161 return watchpoint_sp->IsEnabled(); 162 } else 163 return false; 164} 165 166uint32_t SBWatchpoint::GetHitCount() { 167 LLDB_INSTRUMENT_VA(this); 168 169 uint32_t count = 0; 170 lldb::WatchpointSP watchpoint_sp(GetSP()); 171 if (watchpoint_sp) { 172 std::lock_guard<std::recursive_mutex> guard( 173 watchpoint_sp->GetTarget().GetAPIMutex()); 174 count = watchpoint_sp->GetHitCount(); 175 } 176 177 return count; 178} 179 180uint32_t SBWatchpoint::GetIgnoreCount() { 181 LLDB_INSTRUMENT_VA(this); 182 183 lldb::WatchpointSP watchpoint_sp(GetSP()); 184 if (watchpoint_sp) { 185 std::lock_guard<std::recursive_mutex> guard( 186 watchpoint_sp->GetTarget().GetAPIMutex()); 187 return watchpoint_sp->GetIgnoreCount(); 188 } else 189 return 0; 190} 191 192void SBWatchpoint::SetIgnoreCount(uint32_t n) { 193 LLDB_INSTRUMENT_VA(this, n); 194 195 lldb::WatchpointSP watchpoint_sp(GetSP()); 196 if (watchpoint_sp) { 197 std::lock_guard<std::recursive_mutex> guard( 198 watchpoint_sp->GetTarget().GetAPIMutex()); 199 watchpoint_sp->SetIgnoreCount(n); 200 } 201} 202 203const char *SBWatchpoint::GetCondition() { 204 LLDB_INSTRUMENT_VA(this); 205 206 lldb::WatchpointSP watchpoint_sp(GetSP()); 207 if (!watchpoint_sp) 208 return nullptr; 209 210 std::lock_guard<std::recursive_mutex> guard( 211 watchpoint_sp->GetTarget().GetAPIMutex()); 212 return ConstString(watchpoint_sp->GetConditionText()).GetCString(); 213} 214 215void SBWatchpoint::SetCondition(const char *condition) { 216 LLDB_INSTRUMENT_VA(this, condition); 217 218 lldb::WatchpointSP watchpoint_sp(GetSP()); 219 if (watchpoint_sp) { 220 std::lock_guard<std::recursive_mutex> guard( 221 watchpoint_sp->GetTarget().GetAPIMutex()); 222 watchpoint_sp->SetCondition(condition); 223 } 224} 225 226bool SBWatchpoint::GetDescription(SBStream &description, 227 DescriptionLevel level) { 228 LLDB_INSTRUMENT_VA(this, description, level); 229 230 Stream &strm = description.ref(); 231 232 lldb::WatchpointSP watchpoint_sp(GetSP()); 233 if (watchpoint_sp) { 234 std::lock_guard<std::recursive_mutex> guard( 235 watchpoint_sp->GetTarget().GetAPIMutex()); 236 watchpoint_sp->GetDescription(&strm, level); 237 strm.EOL(); 238 } else 239 strm.PutCString("No value"); 240 241 return true; 242} 243 244void SBWatchpoint::Clear() { 245 LLDB_INSTRUMENT_VA(this); 246 247 m_opaque_wp.reset(); 248} 249 250lldb::WatchpointSP SBWatchpoint::GetSP() const { 251 LLDB_INSTRUMENT_VA(this); 252 253 return m_opaque_wp.lock(); 254} 255 256void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) { 257 LLDB_INSTRUMENT_VA(this, sp); 258 259 m_opaque_wp = sp; 260} 261 262bool SBWatchpoint::EventIsWatchpointEvent(const lldb::SBEvent &event) { 263 LLDB_INSTRUMENT_VA(event); 264 265 return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event.get()) != 266 nullptr; 267} 268 269WatchpointEventType 270SBWatchpoint::GetWatchpointEventTypeFromEvent(const SBEvent &event) { 271 LLDB_INSTRUMENT_VA(event); 272 273 if (event.IsValid()) 274 return Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent( 275 event.GetSP()); 276 return eWatchpointEventTypeInvalidType; 277} 278 279SBWatchpoint SBWatchpoint::GetWatchpointFromEvent(const lldb::SBEvent &event) { 280 LLDB_INSTRUMENT_VA(event); 281 282 SBWatchpoint sb_watchpoint; 283 if (event.IsValid()) 284 sb_watchpoint = 285 Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP()); 286 return sb_watchpoint; 287} 288 289lldb::SBType SBWatchpoint::GetType() { 290 LLDB_INSTRUMENT_VA(this); 291 292 lldb::WatchpointSP watchpoint_sp(GetSP()); 293 if (watchpoint_sp) { 294 std::lock_guard<std::recursive_mutex> guard( 295 watchpoint_sp->GetTarget().GetAPIMutex()); 296 const CompilerType &type = watchpoint_sp->GetCompilerType(); 297 return lldb::SBType(type); 298 } 299 return lldb::SBType(); 300} 301 302WatchpointValueKind SBWatchpoint::GetWatchValueKind() { 303 LLDB_INSTRUMENT_VA(this); 304 305 lldb::WatchpointSP watchpoint_sp(GetSP()); 306 if (watchpoint_sp) { 307 std::lock_guard<std::recursive_mutex> guard( 308 watchpoint_sp->GetTarget().GetAPIMutex()); 309 if (watchpoint_sp->IsWatchVariable()) 310 return WatchpointValueKind::eWatchPointValueKindVariable; 311 return WatchpointValueKind::eWatchPointValueKindExpression; 312 } 313 return WatchpointValueKind::eWatchPointValueKindInvalid; 314} 315 316const char *SBWatchpoint::GetWatchSpec() { 317 LLDB_INSTRUMENT_VA(this); 318 319 lldb::WatchpointSP watchpoint_sp(GetSP()); 320 if (!watchpoint_sp) 321 return nullptr; 322 323 std::lock_guard<std::recursive_mutex> guard( 324 watchpoint_sp->GetTarget().GetAPIMutex()); 325 // Store the result of `GetWatchSpec()` as a ConstString 326 // so that the C string we return has a sufficiently long 327 // lifetime. Note this a memory leak but should be fairly 328 // low impact. 329 return ConstString(watchpoint_sp->GetWatchSpec()).AsCString(); 330} 331 332bool SBWatchpoint::IsWatchingReads() { 333 LLDB_INSTRUMENT_VA(this); 334 lldb::WatchpointSP watchpoint_sp(GetSP()); 335 if (watchpoint_sp) { 336 std::lock_guard<std::recursive_mutex> guard( 337 watchpoint_sp->GetTarget().GetAPIMutex()); 338 339 return watchpoint_sp->WatchpointRead(); 340 } 341 342 return false; 343} 344 345bool SBWatchpoint::IsWatchingWrites() { 346 LLDB_INSTRUMENT_VA(this); 347 lldb::WatchpointSP watchpoint_sp(GetSP()); 348 if (watchpoint_sp) { 349 std::lock_guard<std::recursive_mutex> guard( 350 watchpoint_sp->GetTarget().GetAPIMutex()); 351 352 return watchpoint_sp->WatchpointWrite() || 353 watchpoint_sp->WatchpointModify(); 354 } 355 356 return false; 357} 358